PDO et syntaxe

Eléphant du PHP | 216 Messages

04 mars 2015, 18:03

Bonjour,
pouvez-vous me dire si cette syntaxe est correcte ?

Code : Tout sélectionner

$sqla = $db->prepare("SELECT cont_".$lang." FROM flatforswap_continent ORDER BY cont_".$lang." ASC"); $sqla->execute(array());
Merci d'avance pour votre aide.

Mammouth du PHP | 2278 Messages

04 mars 2015, 18:57

$sqla = $db->prepare("SELECT cont_".$lang." FROM flatforswap_continent ORDER BY cont_".$lang." ASC");
serait plus simple ainsi:
$cont_lang = "cont"_".$lang;
//on peut vérifier la variable et on s'épargne des concaténations dans la requête
$sqla = $db->prepare("SELECT $cont_lang FROM flatforswap_continent ORDER BY $cont_lang ASC"); /
Vanitas vanitatum et omnia vanitas
Mes derniers livres :
Sauvez les Mots chez BoD,
Tous les chemins mènent à ROM chez BoD

ViPHP
AB
ViPHP | 5818 Messages

04 mars 2015, 20:20

Si tu ne lie (bind) aucune variable alors pas la peine de faire une requête préparée...

Tu as intérêt de vérifier la valeur de $lang avant de l'employer dans ta requête sinon tu auras une erreur.

Eléphant du PHP | 216 Messages

05 mars 2015, 15:40

Bonjour,

mais alors à quoi sert le

Code : Tout sélectionner

$sqla->execute(array());
?

Dans la requête suivante, par exemple, j'utilise le ->execute(array())

Code : Tout sélectionner

$sql = $db->prepare("select * from fcadsd_adh where mail=? and mdp=? and valide !=?"); $sql->execute(array($mail, $mdp, '0'));

Mammouth du PHP | 688 Messages

05 mars 2015, 15:43

le execute sert à exécuter ta requête, étape indispensable.
selon que tu as des paramètres à lier, tu passes un tableau avec du contenu, un tableau vide, ou rien.

ViPHP
xTG
ViPHP | 7331 Messages

05 mars 2015, 16:05

Non... Si tu ne passes rien tu ne fais pas de requête préparée du tout.
Sinon c'est comme utiliser une pelleteuse 40t pour retourner ton parterre de fleur de 2m², cela ne sert à rien... :P

Voici quelques exemples d'utilisation (et encore qui pourraient se discuter).
Requête préparée car utilisée plusieurs fois :
foreach($liste as $champs3)
{
   $sql = $db->prepare("SELECT champs1, champs2 FROM maTable WHERE champs3 = ? AND date > NOW()");
   $sql->execute(array($champs3));
   // traitement ....
}
Un cas de requête unique qui ne requiert donc pas de requête préparée :
$sql = $db->query("SELECT champs1, champs2 FROM maTable WHERE champs3 = " . $db->quote($champs3));
La fonction quote est là pour protéger la requête contre les injections.
Note : dans le cas d'une requête préparée c'est directement géré par la fonction execute.

ViPHP
AB
ViPHP | 5818 Messages

05 mars 2015, 16:18

Normalement on utilise une requête préparée pour lier des variables dans une requête.
Donc on fait un prepare(), on bind les variables individuellement et on utilise execute() sans paramètre,
ou,
on fait un prepare() et on bind les variables globalement en passant un tableau comme paramètre dans le execute($array).

Quand il n'y a pas de variable à lier dans la requête, l'étape du prepare() n'est pas justifiée.
Dans ce cas on utilise juste query() pour les sélections et exec() pour les autres (update, insert, delete)

ViPHP
AB
ViPHP | 5818 Messages

05 mars 2015, 16:45

J'avais pas vu le message d'xTG...

Voici donc quelques explications concernant nos "différentes versions" :

Il faut savoir qu'à l'origine les requêtes préparées sont prévues pour accélérer le processus d'exécution des requêtes multiples, typiquement dans une boucle.

Ensuite il s'avère que les requêtes préparées sont plus sécurisées contre les infections sql car la préparation de la requête fait une abstraction (bind) entre le symbol et la variable et donc la variable ne fait pas partie directement de la chaine de la requête. Comme le coût de la préparation n'est pas très élevé en terme de performance on conseille donc d'utiliser les requêtes préparées pratiquement à chaque fois que l'on traite des variables utilisateurs.
Ensuite pour pas se prendre le choux, on peut aller jusqu'à dire à chaque fois que l'on traite une variable.

Mais si j'ai bien compris vous voulez utiliser des requêtes préparées systématiquement même sans variables. Là vous poussez le bouchon un peu loin. Et puis vous passez à côté des fonctionnalités pratiques des fonctions exec et query que ne possède pas execute.

Eléphant du PHP | 216 Messages

05 mars 2015, 16:50

OK.

j'ai effectivement été attaqué par injection mysql. certaines de mes tables ont complètement été vidées.
J'ai donc décidé de mettre à jour mon site en intégrant du PDO.
Si j'ai bien compris, et en tenant compte de vos remarques, voici ce que donne mon code :

Code : Tout sélectionner

$sqla = $db->query("SELECT cont_".$lang." FROM flatforswap_continent ORDER BY cont_".$lang." ASC"); while($dataa = $sqla->fetch()) { if ($continent == $dataa['cont_'.$lang.'']) { echo '<option value="'.$dataa['cont_'.$lang.''].'" selected="selected">'.$dataa['cont_'.$lang.''].'</option>'; } if ($continent != $dataa['cont_'.$lang.'']) { echo '<option value="'.$dataa['cont_'.$lang.''].'">'.$dataa['cont_'.$lang.''].'</option>'; } }
etc-ce que ça vous semble correct ?

ViPHP
xTG
ViPHP | 7331 Messages

05 mars 2015, 16:53

Tu t'exposes toujours aux injections.
Regardes mon exemple utilisant query ET SURTOUT l'utilisation de quote. ;)

Eléphant du PHP | 216 Messages

05 mars 2015, 17:13

es-tu sûr que je m'expose aux injections...

Je ne vois pas comment une injection peut rentrer dans ce code...

ViPHP
AB
ViPHP | 5818 Messages

05 mars 2015, 17:19

Effectivement c'est typiquement le cas où les requêtes préparées ne servent à rien car les marqueurs ne peuvent se lier qu'aux valeurs des champs et non pas au nom des champs. Ainsi tu faisais une requête préparée qui n'était pas sécurisée. Avec query ou exec il faut utiliser quote pour protéger la chaine de la requête.

Cela dit normalement tu dois bien avoir un tableau de traduction des langues. Et dans le cas il te suffit de faire

Code : Tout sélectionner

if(in_array($lang, $tab_lang)) {//requête}
Pour dire qu'à chaque fois que cela est possible, requête préparée ou pas, on vérifie toujours si la variable fournie fait partie des variables attendues avant de faire une requête.

Eléphant du PHP | 216 Messages

05 mars 2015, 17:48

Au fait la variables $lang est définiie en amont de mon code (elle est donc forcément vérifiée puisque c'est moi qui l'impose)

Code : Tout sélectionner

$domaines_config = array( 'www.example.com' => 'en', 'www.example.fr' => 'fr', 'www.example.es' => 'es' ); // $domaine = ''; $lang = ''; // On vérifie que le domaine if ( isset($domaines_config[$_SERVER['HTTP_HOST']] ) ) { $lang = $domaines_config[$_SERVER['HTTP_HOST']] ; } else { echo 'Domaine non reconnu'; exit(); // throw new Exception("Domaine non reconnu:".$_SERVER['HTTP_HOST']); }

ViPHP
AB
ViPHP | 5818 Messages

05 mars 2015, 18:08

Oui donc tu ne risque pas d'injection.
Enfin bon cela ne te dispense pas de faire la requête correctement avec la protection quote sur $lang, comme ça tu sauras le faire (c'est assez souvent qu'on ne peut pas contrôler la variable avant).

ViPHP
AB
ViPHP | 5818 Messages

05 mars 2015, 18:20

Je me répond à moi-même :

Cela dit quand on modifie le nom d'un champ avec une variable, il est normalement "toujours" possible de contrôler si le nom du champ est correct avant de faire la requête. Et si par ailleurs on utilise les requêtes préparées dès qu'il s'agit de lier des valeurs aux variables (excepté les noms des champs), cela explique pourquoi je n'utilise quasiment jamais la fonction quote().