MySQL autorise optionnellement le fait d'avoir plusieurs requêtes dans une seule chaîne de requête. L'envoi de requêtes multiples en une fois réduit les aller-retour client serveur mais nécessite une gestion spéciale.
Les requêtes multiples ou multi-requêtes doivent être exécutées avec la fonction mysqli_multi_query(). Les requêtes individuelles dans la chaîne de requête sont séparées par un point virgule. Ensuite, tous les jeux de résultats retournés par l'exécution des requêtes doivent être récupérés.
Le serveur MySQL autorise d'avoir des requêtes qui retournent des jeux de résultats ainsi que des requêtes qui ne retournent aucun jeu de résultats dans la même requête multiple.
Exemple #1 Requêtes multiples
<?php
$mysqli = new mysqli("example.com", "user", "password", "database");
if ($mysqli->connect_errno) {
echo "Echec lors de la connexion à MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}
if (!$mysqli->query("DROP TABLE IF EXISTS test") || !$mysqli->query("CREATE TABLE test(id INT)")) {
echo "Echec lors de la création de la table : (" . $mysqli->errno . ") " . $mysqli->error;
}
$sql = "SELECT COUNT(*) AS _num FROM test; ";
$sql.= "INSERT INTO test(id) VALUES (1); ";
$sql.= "SELECT COUNT(*) AS _num FROM test; ";
if (!$mysqli->multi_query($sql)) {
echo "Echec lors de l'exécution de la multi-requête : (" . $mysqli->errno . ") " . $mysqli->error;
}
do {
if ($res = $mysqli->store_result()) {
var_dump($res->fetch_all(MYSQLI_ASSOC));
$res->free();
}
} while ($mysqli->more_results() && $mysqli->next_result());
?>
L'exemple ci-dessus va afficher :
array(1) { [0]=> array(1) { ["_num"]=> string(1) "0" } } array(1) { [0]=> array(1) { ["_num"]=> string(1) "1" } }
D'un point de vue de la sécurité
Les fonctions mysqli_query() et mysqli_real_query() de l'API ne définissent pas de drapeau de connexion nécessaire pour l'activation des multi-requêtes sur le serveur. Un appel supplémentaire à l'API est utilisé pour les multi-requêtes pour réduire la probabilité d'injection SQL accidentelle. Un attaquant peut tenter d'ajouter des requêtes comme ; DROP DATABASE mysql ou ; SELECT SLEEP(999). Si l'attaquant arrive à ajouter ce genre de SQL dans la chaîne de requête mais que mysqli_multi_query n'est pas utilisé, le serveur n'excutera que la première requête, mais pas la seconde représentant la requête SQL malicieuse.
Exemple #2 Injection SQL
<?php
$mysqli = new mysqli("example.com", "user", "password", "database");
$res = $mysqli->query("SELECT 1; DROP TABLE mysql.user");
if (!$res) {
echo "Erreur lors de l'exécution de la requête : (" . $mysqli->errno . ") " . $mysqli->error;
}
?>
L'exemple ci-dessus va afficher :
Erreur lors de l'exécution de la requête : (1064) You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DROP TABLE mysql.user' at line 1
Prepared statements
L'utilisation des requêtes multiples avec des requêtes préparées n'est pas supportée.
Voir aussi