W3docs

real_escape_string

Découvrez la fonction mysqli_real_escape_string() en PHP pour échapper les caractères spéciaux dans les requêtes SQL et prévenir les injections SQL.

La fonction mysqli_real_escape_string() échappe les caractères spéciaux d'une chaîne afin qu'elle puisse être placée en toute sécurité dans une requête SQL. Cette page explique ce que fait la fonction, sa syntaxe et sa valeur de retour, le problème de jeu de caractères qui peut la faire échouer, la fonction dépréciée mysql_real_escape_string() qu'elle a remplacée, et pourquoi les instructions préparées sont aujourd'hui le meilleur choix.

Ce que fait mysqli_real_escape_string()

Lorsque vous construisez une requête SQL en concaténant directement l'entrée utilisateur dans la chaîne de requête, une valeur comme O'Reilly termine la chaîne entre guillemets prématurément et le reste est interprété comme du SQL. Un attaquant peut exploiter cela pour lire, modifier ou supprimer des données — c'est une attaque par injection SQL.

mysqli_real_escape_string() empêche cela en ajoutant des barres obliques inverses avant les caractères ayant une signification spéciale dans un littéral de chaîne MySQL : le guillemet simple ', le guillemet double ", la barre oblique inverse \, l'octet NUL, le saut de ligne \n, le retour chariot \r et Ctrl+Z. Après l'échappement, la valeur peut être intégrée en toute sécurité entre guillemets dans une requête.

Elle est dite « real » car elle consulte le jeu de caractères de la connexion, ce qui lui permet d'échapper correctement même les encodages multi-octets — ce que l'ancienne fonction addslashes() ne peut pas faire.

Syntaxe

mysqli_real_escape_string(mysqli $connection, string $string): string
ParamètreDescription
$connectionUn lien retourné par mysqli_connect(). La fonction en a besoin pour connaître le jeu de caractères de la connexion.
$stringLa chaîne à échapper.

Elle retourne la chaîne échappée. Notez qu'elle n'ajoute pas les guillemets environnants — vous devez toujours écrire '$escaped' vous-même dans la requête.

En style orienté objet, appelez-la comme une méthode : $mysqli->real_escape_string($string).

Comment l'utiliser

<?php
$con = mysqli_connect('localhost', 'username', 'password', 'database');

if (!$con) {
    exit('Could not connect: ' . mysqli_error($con));
}

// Set charset to prevent multi-byte character vulnerabilities
mysqli_set_charset($con, 'utf8mb4');

$name = "John O'Reilly";
$name = mysqli_real_escape_string($con, $name);

$sql = "INSERT INTO customers (name) VALUES ('$name')";

if (!mysqli_query($con, $sql)) {
    exit('Error: ' . mysqli_error($con));
}

echo '1 record added';

mysqli_close($con);
?>

Ici, nous nous connectons avec mysqli_connect(), définissons $name avec un guillemet simple et l'échappons. La valeur échappée John O\'Reilly s'intègre en toute sécurité dans le paramètre fictif '$name', de sorte que l'instruction INSERT s'exécute sans erreur de syntaxe et sans ouvrir une faille d'injection. Consultez Insérer des données dans MySQL pour le flux de travail complet d'insertion.

Définir le jeu de caractères en premier

mysqli_real_escape_string() n'échappe correctement que si la connexion connaît son jeu de caractères. Appelez toujours mysqli_set_charset() immédiatement après la connexion :

mysqli_set_charset($con, 'utf8mb4');

Omettre cette étape avec certains encodages (notamment GBK) laisse ouverte une vulnérabilité d'injection multi-octets où la barre oblique inverse d'échappement est « absorbée » par une séquence multi-octets. Définir le jeu de caractères sur la connexion — et pas seulement dans la requête — ferme cette faille.

Ce qu'elle ne protège pas

L'échappement rend une valeur sûre à l'intérieur d'un littéral de chaîne entre guillemets. Elle ne rend pas les valeurs sûres dans les contextes où les guillemets ne peuvent pas être utilisés — noms de tables et de colonnes, nombres pour LIMIT, ou mots-clés. N'échappez jamais un identifiant pour l'insérer dans une requête ; validez-le plutôt par rapport à une liste d'autorisation.

// WRONG — escaping does nothing useful for an identifier
$column = mysqli_real_escape_string($con, $_GET['sort']);
$sql = "SELECT * FROM users ORDER BY $column"; // still injectable

// RIGHT — allow-list
$allowed = ['name', 'email', 'created_at'];
$column  = in_array($_GET['sort'], $allowed, true) ? $_GET['sort'] : 'name';

mysql_real_escape_string() vs mysqli_real_escape_string()

L'ancienne fonction mysql_real_escape_string() (sans i) appartenait à l'extension originale mysql_*, qui a été supprimée dans PHP 7. Utilisez la version mysqli_* — ou PDO — sur tout PHP moderne. Si vous l'appelez sans connexion active, elle ouvre silencieusement une connexion par défaut et émet un avertissement, ce qui est une autre raison de son abandon.

Privilégier les instructions préparées

L'échappement fonctionne, mais il repose sur le fait de ne jamais oublier une seule valeur. Les instructions préparées sont plus sûres car le modèle de requête et les données voyagent séparément, de sorte que l'entrée utilisateur ne peut jamais modifier la structure de la requête :

<?php
$con = mysqli_connect('localhost', 'username', 'password', 'database');
mysqli_set_charset($con, 'utf8mb4');

$stmt = mysqli_prepare($con, 'INSERT INTO customers (name) VALUES (?)');
mysqli_stmt_bind_param($stmt, 's', $name);

$name = "John O'Reilly"; // no manual escaping needed
mysqli_stmt_execute($stmt);

echo '1 record added';
mysqli_close($con);
?>

Utilisez mysqli_real_escape_string() lorsque vous devez vraiment construire du SQL dynamique manuellement ; recourez à mysqli_prepare() dans tous les autres cas. Pour une vue d'ensemble de l'extension, consultez PHP MySQLi.

Conclusion

mysqli_real_escape_string() échappe les caractères spéciaux qui autrement briseraient — ou seraient exploités dans — un littéral de chaîne SQL. Définissez d'abord le jeu de caractères de la connexion, gardez à l'esprit qu'elle ne protège pas les identifiants, et privilégiez les instructions préparées chaque fois que possible.

Pratique

Pratique
Que fait la fonction PHP mysql_real_escape_string ?
Que fait la fonction PHP mysql_real_escape_string ?
Was this page helpful?