Pregunta

Aquí hay una instantánea de mi código:

$fetchPictures = $PDO->prepare("SELECT * 
    FROM pictures 
    WHERE album = :albumId 
    ORDER BY id ASC 
    LIMIT :skip, :max");

$fetchPictures->bindValue(':albumId', $_GET['albumid'], PDO::PARAM_INT);

if(isset($_GET['skip'])) {
    $fetchPictures->bindValue(':skip', trim($_GET['skip']), PDO::PARAM_INT);    
} else {
    $fetchPictures->bindValue(':skip', 0, PDO::PARAM_INT);  
}

$fetchPictures->bindValue(':max', $max, PDO::PARAM_INT);
$fetchPictures->execute() or die(print_r($fetchPictures->errorInfo()));
$pictures = $fetchPictures->fetchAll(PDO::FETCH_ASSOC);

yo obtengo

Tienes un error en tu sintaxis SQL;Verifique el manual que corresponde a su versión del servidor MySQL para que la sintaxis correcta use cerca de '' 15 ', 15' en la línea 1

Parece que PDO está agregando comillas simples a mis variables en la parte LIMIT del código SQL.Lo busqué y encontré este error que creo que está relacionado:http://bugs.php.net/bug.php?id=44639

¿Es eso lo que estoy mirando?¡Este error ha estado abierto desde abril de 2008!¿Qué se supone que debemos hacer mientras tanto?

Necesito crear algo de paginación y asegurarme de que los datos estén limpios y sean seguros para la inyección de SQL antes de enviar la declaración SQL.

¿Fue útil?

Solución

recuerdo haber tenido este problema antes. Convertir el valor a un número entero antes de pasarla a la función de vinculación. Creo que esto lo resuelve.

$fetchPictures->bindValue(':skip', (int) trim($_GET['skip']), PDO::PARAM_INT);

Otros consejos

La solución más simple sería conmutar el modo de emulación de . Puede hacerlo ya sea como una opción de conexión o simplemente añadiendo la siguiente línea

$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );

No sólo va a resolver su problema con el parámetro se unen, pero también le permiten enviar los valores de ejecutar (), lo que hará que su código muchshorter

$skip = $_GET['skip'] ?: 0;
$sql  = "SELECT * FROM pictures WHERE album = ? ORDER BY id LIMIT ?, ?";
$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
$stmt  = $PDO->prepare($sql);
$stmt->execute([$_GET['albumid'], $skip, $max]);
$pictures = $stmt->fetchAll(PDO::FETCH_ASSOC);

Mirando el informe de error, el siguiente podría funcionar:

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);

$fetchPictures->bindValue(':skip', (int)trim($_GET['skip']), PDO::PARAM_INT);  

Pero está seguro de que sus datos de entrada es correcta? Debido a que en el mensaje de error, parece que hay solamente un cita después del número (en contraposición a todo el número que se está entre comillas). Esto también podría ser un error con los datos entrantes. ¿Se puede hacer un print_r($_GET); para averiguar?

Esto es solo un resumen.
Hay cuatro opciones para parametrizar los valores LIMIT/OFFSET:

  1. Desactivar PDO::ATTR_EMULATE_PREPARES como se mencionó arriba.

    Lo que evita que los valores pasados ​​por ->execute([...]) para aparecer siempre como cadenas.

  2. Cambiar a manual ->bindValue(..., ..., PDO::PARAM_INT) población de parámetros.

    Lo cual, sin embargo, es menos conveniente que una ->lista de ejecución[].

  3. Simplemente haga una excepción aquí e interpola números enteros simples al preparar la consulta SQL.

     $limit = intval($limit);
     $s = $pdo->prepare("SELECT * FROM tbl LIMIT {$limit}");
    

    El casting es importante.Más comúnmente ves ->prepare(sprintf("SELECT ... LIMIT %d", $num)) utilizados para tales fines.

  4. Si no está utilizando MySQL, sino por ejemplo SQLite o Postgres;También puede convertir parámetros vinculados directamente en SQL.

     SELECT * FROM tbl LIMIT (1 * :limit)
    

    Nuevamente, MySQL/MariaDB no admite expresiones en la cláusula LIMIT.Aún no.

para LIMIT :init, :end

Es necesario para unir de ese modo. si tenía algo así como $req->execute(Array()); que no funcionará, ya que echará PDO::PARAM_STR a todos los VARs de la matriz y para la LIMIT es absolutamente necesario un entero. bindValue o BindParam como desee.

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);

Ya que nadie ha explicado por qué ocurre esto, estoy añadiendo una respuesta. La razón de que se está comportando de esta era es porque está utilizando trim(). Si nos fijamos en el manual de PHP para trim, se string el tipo de retorno. Luego se le tratando de pasar esto como PDO::PARAM_INT. Algunas maneras de evitar esto son:

  1. Uso filter_var($integer, FILTER_VALIDATE_NUMBER_INT) para asegurarse de que usted está pasando un entero.
  2. Como otros han dicho, utilizando intval()
  3. La colada con un (int)
  4. Comprobación de si es un número entero con is_int()

Hay muchas más formas, pero esto es básicamente la causa raíz.

bindValue desplazamiento y limitar el uso de PDO :: PARAM_INT y funcionará

// ANTES (error presente) $ Consulta = ".... LÍMITE: p1, 30;"; ... $ Stmt-> bindParam ( 'p1', $ limiteInferior);

// DESPUÉS (error corregido) $ Consulta = ".... LÍMITE: p1, 30;"; ... $ LimiteInferior = (int) $ limiteInferior; $ Stmt-> bindParam ( 'p1', $ limiteInferior, PDO :: PARAM_INT);

PDO::ATTR_EMULATE_PREPARES me dio la

  

controlador no es compatible con esta función: Este controlador no soporta   Error de configuración de atributos.

Mi solución fue establecer una variable $limit como una cadena, y luego combinarlo en la declaración preparar como en el siguiente ejemplo:

$limit = ' LIMIT ' . $from . ', ' . $max_results;
$stmt = $pdo->prepare( 'SELECT * FROM users WHERE company_id = :cid ORDER BY name ASC' . $limit . ';' );
try {
    $stmt->execute( array( ':cid' => $company_id ) );
    ...
}
catch ( Exception $e ) {
    ...
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top