update funcion example entre diferencia php mysql sql pdo bindvalue

funcion - php bindparam pdo



¿Cómo aplicar el método bindValue en la cláusula LIMIT? (9)

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

Usted tiene un error en su sintaxis SQL; revise el manual que corresponde a su versión del servidor MySQL para la sintaxis correcta para usar 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é Encontré este error que creo que está relacionado: http://bugs.php.net/bug.php?id=44639

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

Necesito construir una cierta paginación, y necesito asegurarme de que los datos estén limpios, sql injection-safe, antes de enviar la declaración sql.


// ANTES (Error presente) $ query = ".... LIMIT: p1, 30;"; ... $ stmt-> bindParam ('': p1'', $ limiteInferior);

// DESPUÉS (Error corregido) $ query = ".... LIMIT: p1, 30;"; ... $ limiteInferior = (int) $ limiteInferior; $ stmt-> bindParam ('': p1'', $ limiteInferior, PDO :: PARAM_INT);


Como nadie ha explicado por qué sucede esto, estoy agregando una respuesta. La razón por la que se está comportando así es porque está usando trim() . Si mira el manual de PHP para trim , el tipo de retorno es string . Usted está tratando de pasar esto como PDO::PARAM_INT . Algunas formas de evitar esto son:

  1. Use filter_var($integer, FILTER_VALIDATE_NUMBER_INT) para asegurarse de que está pasando un número entero.
  2. Como otros dijeron, usando intval()
  3. Casting con (int)
  4. Comprobando si es un número entero con is_int()

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


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

  1. Desactive PDO::ATTR_EMULATE_PREPARES como se menciona share .

    Lo que impide que los valores pasados ​​por ->execute([...]) siempre aparezcan como cadenas.

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

    Sin embargo, es menos conveniente que una -> ejecutar lista [].

  3. Simplemente haga una excepción aquí e interpola 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 se ve ->prepare(sprintf("SELECT ... LIMIT %d", $num)) utilizado para tales fines.

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

    SELECT * FROM tbl LIMIT (1 * :limit)

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


Hice lo siguiente en el mío, donde $ info es mi matriz que contiene mis parámetros vinculados:

preg_match( ''/LIMIT :(?P<limit>[0-9a-zA-Z]*)/'', $sql, $matches ); if (count($matches)) { //print_r($matches); $sql = str_replace( $matches[0], ''LIMIT '' . intval( $info['':'' . $matches[''limit'']] ), $sql ); } // LIMIT #, :limit# preg_match( ''/LIMIT (?P<limit1>[0-9]*),/s?:(?P<limit2>[0-9a-zA-Z]*)/'', $sql, $matches ); if (count($matches)) { //print_r($matches); $sql = str_replace( $matches[0], ''LIMIT '' . $matches[''limit1''] . '','' . intval( $info['':'' . $matches[''limit2'']] ), $sql ); }

Esto se basa en parte en el código de Sebas.


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

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

No solo resolverá su problema con bind param, sino que también le permitirá enviar valores en execute (), lo que hará que su código se dispare dramáticamente.

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


Mirando el informe de error, lo 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ás seguro de que tus datos entrantes son correctos? Porque en el mensaje de error, parece haber una sola cotización después del número (a diferencia del número entero entre comillas). Esto también podría ser un error con sus datos entrantes. Puedes hacer un print_r($_GET); ¿descubrir?


Recuerdo haber tenido este problema antes. Emite el valor a un entero antes de pasarlo a la función de vinculación. Creo que esto lo soluciona

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


bindValue offset y limit usando PDO :: PARAM_INT y funcionará


para LIMIT :init, :end

Debes unirte de esa manera. si tiene algo como $req->execute(Array()); no funcionará, ya que arrojará PDO::PARAM_STR a todos los vars en la matriz y para el LIMIT necesitarás absolutamente un Entero. bindValue o BindParam como quieras.

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