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:
- Use
filter_var($integer, FILTER_VALIDATE_NUMBER_INT)
para asegurarse de que está pasando un número entero. - Como otros dijeron, usando
intval()
- Casting con
(int)
- 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:
Desactive
PDO::ATTR_EMULATE_PREPARES
como se menciona share .Lo que impide que los valores pasados por
->execute([...])
siempre aparezcan como cadenas.Cambiar a manual
->bindValue(..., ..., PDO::PARAM_INT)
población de parámetros.Sin embargo, es menos conveniente que una -> ejecutar lista [].
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.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);