Clause limit et PDO

Eléphant du PHP | 171 Messages

20 juin 2011, 22:23

Salut à tous,

Je viens aujourd'hui vous poser une question par rapport à la clause LIMIT en PDO.
En programmant, j'avais vu qu'on ne pouvait pas utiliser LIMIT ? ou LIMIT :index dans une requête comme par exemple :
$array['pagebillet'] = 1;
$db->prepare('SELECT lien_billet WHERE later_billet = 0 '.$requestBit.' GROUP BY id_billet ORDER BY date_billet DESC LIMIT :pagebillet,10');
$db->execute($array);
Avec ce code, on a pas de résultat. Si on remplace par :pagebillet par ?, on a une erreur. Bon quand j'avais rencontré ça après une recherche ou deux, j'ai vu qu'on pouvait pas et qu'il fallait utilisé bindValue.
Donc j'ai fait avec, puis j'avais pas envie d'aller chercher le pourquoi du comment à ce moment là. Mais aujourd'hui j'ai besoin de restructurer mon code, je construit ma requête au fur et a mesure, et je met mes valeurs dans un tableau puis j'utilise execute(myarray); et je suis donc revenu sur la question. Et aujourd'hui j'aimerais bien savoir, si il y en a quelques un de vous qui savent pourquoi on est obligé de bindé notre valeur pour la clause LIMIT et seulement avec elle. (enfin jusqu’à maintenant j'ai rencontré des problèmes qu'avec LIMIT par rapport à ça ^^).

Donc voilà, je peux passer ce problème en gardant mon bindValue, mais c'est juste pour comprendre pourquoi ? :)

Merci d'avance.
Le bon jugement s'apprend par l'expérience qui s'acquiert en partie par le mauvais jugement.

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

20 juin 2011, 22:39

salut,

je ne sais pas pourquoi exactement, par contre j'ai un argument en faveur du bindvalue.
lorsque tu passe un chiffre (entier ou pas, mais dans ton cas un entier) celui ci va être "échappé" et des ' vont être ajoutée, malheureusement un entier n'a pas de ' autour (quand mysql l'accepte c'est parce qu'il est sympa :) ). Par contre un bindvalue et l'indication du type (int) ne te pose aucun soucis.

au pire utilise un foreach pour parcourir ton tableau et placer les bindvalue "en auto" ;) (bon faut gérer le type mais tu peux le rajouter dans le tableau :) ).

@+
Il en faut peu pour être heureux ......

Eléphant du PHP | 171 Messages

20 juin 2011, 23:01

Ouais mais execute() aussi l'échappe je crois bien.
Après bonne lecture sur :
http://julp.developpez.com/php/pdo/?pag ... ion#L6.2.3
ainsi que le paragraphe :
http://julp.developpez.com/php/pdo/?pag ... ter#L3.2.2

J'ai compris pourquoi. En résumé : c'est que execute() va traiter toutes les valeurs comme des chaînes par rapport à SQL. Par exemple pour une valeur comme 666, celle ci deviendra '666'.
La clause LIMIT n'acceptant que des entiers à ses bornes, cela va générer une erreur.

Ça confirme donc ce que tu disais moogli.

Je suis donc en train de me faire une petite fonction bindValueArray, pour bindé tout mon tableau automatiquement avec le type. Ça peut toujours être pratique (dans mon cas par exemple ^^).

Edit: voilà j'ai fait la petite fonction pour bindée les tableaux à la volée voir ici : vos-contributions/bindvalue-sur-tableau-t259264.html
Modifié en dernier par Skw33d le 21 juin 2011, 12:06, modifié 3 fois.
Le bon jugement s'apprend par l'expérience qui s'acquiert en partie par le mauvais jugement.

devlop78
Invité n'ayant pas de compte PHPfrance

21 juin 2011, 01:41

Je voudrais bien savoir ce qu'il se passe lorsque l'on ne respecte pas le typage avec bindValue (que je préfère à bindParam). Je ferai le test, mais si quelqu'un sait ^^

=> Si on lui donne une chiffre en tant que chaine de caractère mais qu'on le déclare comme chiffre
=> Si on lui donne des lettres en tant que chaine de caractère mais qu'on le déclare comme chiffre

J'espère juste qu'une exception sera émise ... à priori pas d'injection SQL possible (??? aucun échappement mais juste typage) ...

Eléphant du PHP | 209 Messages

21 juin 2011, 05:31

lorsque tu passe un chiffre (entier ou pas, mais dans ton cas un entier) celui ci va être "échappé" et des ' vont être ajoutée, malheureusement un entier n'a pas de ' autour (quand mysql l'accepte c'est parce qu'il est sympa :) ).
J'ai remarqué que d'une part cela ne posait strictement aucun problème sur les valeurs des colonnes, j'ai même benchmarké tous ca et d'après mes test rapides, ca n'a pas l'air d'avoir d'impact sur les performances. Ca fonctionne (au moins) avec PostgreSQL, MySQL, SQLite. Je pense que ca fonctionne avec toutes les bases de données, et lors d'une phase prématuré d'analyse de la requête, les chaines sont converti dans leur type de base (donc en int).

Je ne me sert donc plus que de ca (envoyer toutes les données sous la forme de chaine de charactère), je n'ai donc plus à me préoccupé des injections SQL (ex: http://source.zenprog.com/zencancan/lib ... .class.php).

Par contre, cela ne fonctionne pas sur les limit (et le offset aussi) et je n'ai jamais trouvé de solution bien élégante pour cela ...
--
Eric

devlop78
Invité n'ayant pas de compte PHPfrance

21 juin 2011, 14:26

Bah écoute j'utilise peu les procédures stockées, mais tout n'est pas données. Ce que je veux dire c'est que les valeurs de LIMIT ne sont peut-être pas des données mais bien de la structure nécessaire à la compilation. D'ailleurs, ça a été aussi un des freins pour l'utilisation de procédures stockées sur une des méthodes d'un de mes projets, c'est que j'avais des ORDER ASC/DESC et que je ne pense pas que ça entre dans les données de la procédure.

Désolé si je m'exprime mal mais je viens de me lever ...

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

22 juin 2011, 21:44

lorsque tu passe un chiffre (entier ou pas, mais dans ton cas un entier) celui ci va être "échappé" et des ' vont être ajoutée, malheureusement un entier n'a pas de ' autour (quand mysql l'accepte c'est parce qu'il est sympa :) ).
J'ai remarqué que d'une part cela ne posait strictement aucun problème sur les valeurs des colonnes, j'ai même benchmarké tous ca et d'après mes test rapides, ca n'a pas l'air d'avoir d'impact sur les performances. Ca fonctionne (au moins) avec PostgreSQL, MySQL, SQLite. Je pense que ca fonctionne avec toutes les bases de données, et lors d'une phase prématuré d'analyse de la requête, les chaines sont converti dans leur type de base (donc en int).

Je ne me sert donc plus que de ca (envoyer toutes les données sous la forme de chaine de charactère), je n'ai donc plus à me préoccupé des injections SQL (ex: http://source.zenprog.com/zencancan/lib ... .class.php).

Par contre, cela ne fonctionne pas sur les limit (et le offset aussi) et je n'ai jamais trouvé de solution bien élégante pour cela ...
je répondrais simplement : ce n'est pas parce que c'est possible qu'il faut le faire.
Par exemple en ce moment avec php true == 1 ou false == 0 et ce n'est pas le cas dans d'autre language, rien ne dit que ce sera toujours le cas pour les sgbd et cela évite le cas dont découle ce sujet : dès que l'on n'est plus dans le cas de base ....

@+
Il en faut peu pour être heureux ......

devlop78
Invité n'ayant pas de compte PHPfrance

23 juin 2011, 00:36

Oui, en fait j'ai compris un truc en listant un tuto sur C hier, c'était à propos de sprintf (en C). J'ai compris que le type qu'on indique dans le sprintf n'est pas le type qu'on lui donne mais ce qu'il doit afficher. Ainsi, %d sur un caractère affichera son ASCII, sur un pointeur son numéro, etc. C'est une sorte de transtypage.

Dans ce cas, si c'est la même chose avec les préparées, cela n'aurait effectivement pas de sens de lui dire quel type on lui donne, mais en quel type on veut que ça arrive. Ca reste très flou quand même et le mot "type" n'est pas forcément approprié, car là en C, le type n'a rien à voir avec ceux que PHP ou des langages haut niveau, mais est lié à l'allocation de mémoire.

Bref au delà de "utiliser pour que ça marche partout", je dirais surtout "utiliser en connaissance". Et là moi j'utilise des fois un simple if(!$truc), des fois un if($truc==false) des fois un if($truc===false), ça dépend de la situation, et je le fais en connaissance de cause.

Au final, j'utilise mal le truc, mais ça marche, mais je n'en suis pas satisfait, car je ne le comprends pas.