Question

Voici un aperçu de mon code:

$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);

Je reçois

  

Vous avez une erreur dans votre syntaxe SQL;   vérifier le manuel qui correspond à   votre version du serveur MySQL pour la   bonne syntaxe à utiliser près de « » 15' , 15' à   ligne 1

Il semble que PDO ajoute des guillemets simples à mes variables dans la partie limite du code SQL. Je l'ai cherché, j'ai trouvé ce bug que je pense est lié: http://bugs.php.net/bug.php?id=44639

Est-ce que je regarde? Ce bogue a été ouvert depuis Avril 2008! Que sommes-nous censés faire en attendant?

Je dois construire une mise en page, et devez vous assurer que les données sont propres, l'injection de sécurité sql, avant d'envoyer l'instruction SQL.

Était-ce utile?

La solution

Je me souviens d'avoir ce problème avant. Monter la valeur à un nombre entier avant de le transmettre à la fonction de liaison. Je pense que cela résout.

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

Autres conseils

La solution la plus simple serait de changer le mode d'émulation de . Vous pouvez le faire soit comme une option de connexion ou simplement en ajoutant la ligne suivante

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

Il ne sera pas seulement de résoudre votre problème avec le paramètre de liaison, mais aussi vous laisser d'envoyer des valeurs dans l'exécution (), qui fera votre code 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);

En regardant le rapport de bogue, ce qui suit pourrait fonctionner:

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

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

mais êtes-vous sûr que vos données d'entrée est correcte? Parce que dans le message d'erreur, il semble y avoir que un citation après le numéro (par opposition au nombre entier étant entre guillemets). Cela pourrait aussi être une erreur avec vos données entrantes. Pouvez-vous faire un print_r($_GET); pour savoir?

comme résumé.
Il y a quatre options pour paramétrer les valeurs limites / OFFSET:

  1. Disable PDO::ATTR_EMULATE_PREPARES comme mentionné ci-dessus .

    Ce qui empêche les valeurs transmises par ->execute([...]) pour montrer toujours sous forme de chaînes.

  2. Passez à la population des paramètres manuel ->bindValue(..., ..., PDO::PARAM_INT).

    Ce qui est cependant moins pratique qu'un -> exécuter la liste []

  3. .
  4. Il suffit de faire une exception ici et juste interpoler entiers simples lors de la préparation de la requête SQL.

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

    Le casting est important. Plus souvent que vous voyez ->prepare(sprintf("SELECT ... LIMIT %d", $num)) utilisé à de telles fins.

  5. Si vous ne l'utilisez MySQL, mais par exemple SQLite, ou Postgres; vous pouvez également jeter directement dans les paramètres liés SQL.

     SELECT * FROM tbl LIMIT (1 * :limit)
    

    Encore une fois, MySQL / MariaDB ne prennent pas en charge les expressions dans la clause LIMIT. Pas encore.

pour LIMIT :init, :end

Vous devez lier cette façon. si vous aviez quelque chose comme $req->execute(Array()); il ne fonctionnera pas comme il jettera PDO::PARAM_STR à tous vars dans le tableau et le LIMIT vous devez absolument un entier. bindValue ou BindParam que vous voulez.

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

Comme personne n'a expliqué pourquoi cela se produit, j'ajoute une réponse. La raison pour laquelle il se comporte c'était parce que vous utilisez trim(). Si vous regardez le manuel PHP pour trim, le type de retour est string. Vous êtes alors essayez de passer cela comme PDO::PARAM_INT. Quelques façons de contourner ce sont:

  1. Utilisez filter_var($integer, FILTER_VALIDATE_NUMBER_INT) pour vous assurer que vous passez un entier.
  2. Comme d'autres ont dit, en utilisant intval()
  3. Castings avec (int)
  4. Vérification si elle est un nombre entier avec is_int()

Il y a beaucoup d'autres façons, mais cela est essentiellement la cause racine.

bindValue décalage et limite en utilisant PDO :: PARAM_INT et il fonctionnera

// AVANT (erreur actuelle) $ query = ".... LIMIT: p1, 30;"; ... $ Stmt-> bindParam ( ': p1', limiteInferior $);

// APRES (correction d'erreur) $ query = ".... LIMIT: p1, 30;"; ... $ LimiteInferior = (int) limiteInferior $; $ Stmt-> bindParam ( ': p1', limiteInferior $, PDO :: PARAM_INT);

PDO::ATTR_EMULATE_PREPARES m'a donné le

  

Le pilote ne prend pas en charge cette fonction: Ce pilote ne prend pas en charge   l'erreur de réglage des attributs.

Ma solution a été de définir une variable de $limit comme une chaîne, puis le combiner dans la déclaration préparer comme dans l'exemple suivant:

$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 ) {
    ...
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top