Referencia: preguntas frecuentes sobre la DOP

Resuelto Your Common Sense asked hace 54 años • 0 respuestas

¿Qué es esto?

Esta es una lista de preguntas frecuentes sobre objetos de datos PHP.

¿Por qué es esto?

Como PDO tiene algunas características desconocidas para un usuario habitual de PHP, las preguntas sobre declaraciones preparadas y el manejo de errores en PDO son bastante frecuentes. Entonces, este es solo un lugar donde se pueden encontrar todos ellos.

¿Qué debo hacer aquí?

Si su pregunta ha sido votada de cerca con esta lista, busque su pregunta a continuación y aplique la corrección a su código. También es una buena idea echar un vistazo breve a otras preguntas para prepararse para otros errores comunes.

La lista

  • La consulta de PDO falla pero no veo ningún error. ¿Cómo recibir un mensaje de error de PDO?
  • ¿Cómo puedo utilizar declaraciones preparadas con el operador LIKE?
  • ¿Cómo puedo crear una declaración preparada para el operador IN ()?
  • ¿Puedo utilizar una declaración preparada por PDO para vincular un identificador (una tabla o nombre de campo) o una palabra clave de sintaxis?
  • La declaración preparada por PDO provoca un error en la declaración LIMIT

Ver también

  • Referencia: ¿Qué significa este símbolo en PHP?
  • Referencia: ¿Qué significa este error en PHP?
  • Referencia: ¿Qué es el alcance de la variable, a qué variables se puede acceder desde dónde y qué son los errores de “variable no definida”?
Your Common Sense avatar Jan 01 '70 08:01 Your Common Sense
Aceptado

La consulta de PDO falla pero no veo ningún error. ¿Cómo recibir un mensaje de error de PDO?

Para poder ver los errores de la base de datos, hay que configurar PDO errmode en excepciones. Las excepciones son mejores que los errores normales en muchos sentidos: siempre contienen un seguimiento de la pila, se pueden detectar usando try..catch o manejar mediante un controlador de errores dedicado. E incluso si no se controlan, actúan como errores regulares de PHP que brindan toda la información importante, siguiendo la configuración de informes de errores de todo el sitio.

Tenga en cuenta que configurar este modo como una opción de conexión permitirá que PDO también genere excepciones en errores de conexión, lo cual es muy importante.
Entonces, aquí hay un ejemplo para crear una conexión PDO de la manera correcta:

$dsn = "mysql:host=$host;dbname=$db;charset=utf8";
$opt = array(
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    // other options 
);
$pdo = new PDO($dsn, $user, $pass, $opt);

Al conectarse de esta manera, siempre será notificado de todos los errores de la base de datos que ocurran durante la ejecución de la consulta. Tenga en cuenta que debe poder ver los errores de PHP en general. En un sitio en vivo, debe echar un vistazo a los registros de errores, por lo que la configuración debe ser

error_reporting(E_ALL);
ini_set('display_errors',0);
ini_set('log_errors',1);

mientras que en un servidor de desarrollo local está bien cometer errores en la pantalla:

error_reporting(E_ALL);
ini_set('display_errors',1);

y, por supuesto, nunca debería utilizar el operador de supresión de errores ( @) delante de sus declaraciones PDO.

Además, debido a muchos malos ejemplos que le indican que debe envolver cada declaración PDO en try..catchun bloque, debo hacer una nota clara:

NO utilice el operador try..catch solo para repetir un mensaje de error. La excepción no detectada ya es excelente para este propósito, ya que actuará de la misma manera que otros errores de PHP; por lo tanto, puede definir el comportamiento usando la configuración de todo el sitio; por lo tanto, recibirá su mensaje de error sin este código inútil. Si bien el mensaje de error repetido incondicionalmente puede revelar información confidencial a un atacante potencial, aún confunde a un visitante honesto.

  • Más adelante se podría agregar un controlador de excepciones personalizado , pero no es necesario. Especialmente para los nuevos usuarios, se recomienda utilizar excepciones no controladas, ya que son extremadamente informativas, útiles y seguras.
  • Úselo try..catchsolo si va a manejar el error en sí mismo, por ejemplo, para revertir una transacción.
 avatar Apr 13 '2013 17:04

La declaración preparada por PDO provoca un error en la cláusula LIMIT

Por motivos de compatibilidad, PDO simplemente emulará declaraciones preparadas sustituyendo marcadores de posición con datos reales, en lugar de enviarlos al servidor por separado, a menos que se indique lo contrario. Y con el enlace "perezoso" (usando una matriz en ejecutar()), PDO tratará cada parámetro como una cadena. Como resultado, la LIMIT ?,?consulta preparada presenta LIMIT '10', '10'una sintaxis no válida que provoca que la consulta falle.

Este problema se puede resolver ya sea

  • desactivando el modo de emulación (ya que MySQL puede ordenar todos los marcadores de posición correctamente):

    $conn->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
    
  • vinculando y estableciendo el tipo adecuado (PDO::PARAM_INT) explícitamente:

    $stm = $pdo->prepare('SELECT * FROM table LIMIT ?, ?');
    $stm->bindValue(1, $limit_from,PDO::PARAM_INT);
    $stm->bindValue(2, $per_page,PDO::PARAM_INT);
    $stm->execute();
    $data = $stm->fetchAll();
    
Your Common Sense avatar Apr 13 '2013 18:04 Your Common Sense

¿Cómo puedo utilizar declaraciones preparadas con el operador LIKE?

La declaración preparada sólo puede representar datos completos literales . No es parte de un literal, ni una expresión compleja, ni un identificador. Pero solo cadena o número . Entonces, un error muy común es una consulta como esta:

$sql = "SELECT * FROM t WHERE column LIKE '%?%'";

Si reflexiona un poco sobre esta consulta, comprenderá que al estar entre comillas simples, un signo de interrogación se convierte en un signo de interrogación literal, sin ningún significado especial para las declaraciones preparadas.

Por lo tanto, hay que enviar una cadena literal completa utilizando una declaración preparada. Hay 2 formas posibles:

  • Prepare primero la expresión COMPLETA:

    $name = "%$name%";
    $stm  = $pdo->prepare("SELECT * FROM table WHERE name LIKE ?");
    $stm->execute(array($name));
    $data = $stm->fetchAll();
    
  • o usar una concatenación dentro de la consulta

    $sql = "SELECT * FROM t WHERE column LIKE concat('%',?,'%')";
    

aunque este último parece demasiado inflado.

 avatar Apr 13 '2013 17:04