par
naholyr » 26 juin 2007, 15:50
Le plus simple c'est de se créer des "placeholders", typiquement c'est fait avec des points d'interrogations:
$requete = construitRequete('SELECT * FROM maTable WHERE champ = ?', $maVariable);
On n'a pas besoin de s'occuper au moment de la construction de la requête de l'utilisation de mysql_real_escape_string(), etc... C'est typiquement le genre de chose qu'on retrouve dans des couches d'abstraction de bases de données, car les fonctions d'échappements dépendant de la base de données, elles doivent être abstraites également
Pour se faire un constructeur de requêtes maison, c'est assez simple avec sprintf et %s (l'utilisation du point d'interogation pose quelques soucis qu'on aura ici la flemme de résoudre, avec sprintf c'est facile et on a l'habitude, pour afficher un '%' il faut mettre '%%', classique) :
function construitRequete($requete) {
$args = func_get_args();
array_shift($args);
foreach ($args as &$arg) {
switch (gettype($arg)) {
case 'string':
$arg = '"' . mysql_real_escape_string($arg) . '"';
break;
case 'bool':
case 'boolean':
$arg = $arg ? 1 : 0;
break;
case 'array':
foreach ($arg as &$element) {
$element = construitRequete('%s', $element);
}
$arg = implode(',',$arg);
break;
}
}
array_unshift($args, $requete);
return call_user_func_array('sprintf', $args);
}
C'est un bon exercice de faire ça une fois dans sa vie, ne serait-ce que pour l'apprivoisement de call_user_func_array(), func_get_args() et autres fonctions qu'on utilise rarement.
Résultat :
$nom = 'Toto"; # DELETE FROM maTable'; // Tentative de hack
$id = 3; // un entier
$classes = array('6eA','6eB','6eC'); // un tableau
echo construitRequete('SELECT * FROM elves WHERE id=%s OR nom=%s OR classe IN (%s)', $id, $nom, $classes);
donne
Code : Tout sélectionner
SELECT * FROM elves WHERE id=3 OR nom="Toto\"; # DELETE FROM maTable" OR classe IN ("6eA","6eB","6eC")
Et ça devient tout de suite beaucoup plus simple de construire des requêtes sécurisées, sans avoir bourrer son code d'appels à mysql_real_escape_string()
Moralité :
Utilisez une couche d'abstration d'accès à la base de données, vous aurez forcément un support des "placeholders". Et si ce n'est pas le cas n'hésitez pas à construire le votre.
Le plus simple c'est de se créer des "placeholders", typiquement c'est fait avec des points d'interrogations:[php]$requete = construitRequete('SELECT * FROM maTable WHERE champ = ?', $maVariable);[/php]
On n'a pas besoin de s'occuper au moment de la construction de la requête de l'utilisation de mysql_real_escape_string(), etc... C'est typiquement le genre de chose qu'on retrouve dans des couches d'abstraction de bases de données, car les fonctions d'échappements dépendant de la base de données, elles doivent être abstraites également :)
Pour se faire un constructeur de requêtes maison, c'est assez simple avec sprintf et %s (l'utilisation du point d'interogation pose quelques soucis qu'on aura ici la flemme de résoudre, avec sprintf c'est facile et on a l'habitude, pour afficher un '%' il faut mettre '%%', classique) :[php]function construitRequete($requete) {
$args = func_get_args();
array_shift($args);
foreach ($args as &$arg) {
switch (gettype($arg)) {
case 'string':
$arg = '"' . mysql_real_escape_string($arg) . '"';
break;
case 'bool':
case 'boolean':
$arg = $arg ? 1 : 0;
break;
case 'array':
foreach ($arg as &$element) {
$element = construitRequete('%s', $element);
}
$arg = implode(',',$arg);
break;
}
}
array_unshift($args, $requete);
return call_user_func_array('sprintf', $args);
}[/php]C'est un bon exercice de faire ça une fois dans sa vie, ne serait-ce que pour l'apprivoisement de call_user_func_array(), func_get_args() et autres fonctions qu'on utilise rarement.
Résultat :[php]$nom = 'Toto"; # DELETE FROM maTable'; // Tentative de hack
$id = 3; // un entier
$classes = array('6eA','6eB','6eC'); // un tableau
echo construitRequete('SELECT * FROM elves WHERE id=%s OR nom=%s OR classe IN (%s)', $id, $nom, $classes);[/php]donne[code]SELECT * FROM elves WHERE id=3 OR nom="Toto\"; # DELETE FROM maTable" OR classe IN ("6eA","6eB","6eC")[/code]
Et ça devient tout de suite beaucoup plus simple de construire des requêtes sécurisées, sans avoir bourrer son code d'appels à mysql_real_escape_string() ;)
Moralité : [b]Utilisez une couche d'abstration d'accès à la base de données, vous aurez forcément un support des "placeholders"[/b]. Et si ce n'est pas le cas n'hésitez pas à construire le votre.