_
et %
ne sont pas des caractères génériques dans MySQL en général, et ne devraient pas être échappés dans le but de les mettre dans des littéraux de chaîne normaux. mysql_real_escape_string
est correct et suffisant à cet effet. addcslashes
ne doit pas être utilisé.
_
et %
sont spéciaux uniquement dans le contexte de LIKE
-matching. Lorsque vous souhaitez préparer des chaînes pour une utilisation littérale dans une instruction LIKE
, afin que 100%
corresponde à 100% et non à n'importe quelle chaîne commençant par une centaine, vous devez vous inquiéter de deux niveaux d'échappement.
Le premier est LIKE s'échappant. La gestion de LIKE s'effectue entièrement dans SQL, et si vous voulez transformer une chaîne littérale en une expression littérale LIKE, vous devez effectuer cette étape même si vous utilisez des requêtes paramétrées!
Dans ce schéma, _
et %
sont spéciaux et doivent être échappés. Le caractère d'échappement doit également être échappé. Selon ANSI SQL, les caractères autres que ceux ne doivent pas être être échappés: \'
aurait tort. (Bien que MySQL vous laisse généralement vous en sortir.)
Après avoir fait cela, vous passez au deuxième niveau d'échappement, qui est tout simplement l'échappement littéral. Cela se fait en dehors de SQL, en créant SQL, donc doit être fait après l'étape d'échappement LIKE. Pour MySQL, c'est mysql_real_escape_string
comme avant; pour d'autres bases de données il y aura une fonction différente, vous pouvez simplement utiliser des requêtes paramétrées pour éviter de devoir le faire.
Le problème qui conduit à la confusion ici est que MySQL utilise une barre oblique inverse comme un caractère d'échappement pour les deux étapes d'échappement imbriquées! Donc, si vous vouliez faire correspondre une chaîne avec un signe de pourcentage littéral, vous devriez double-backslash-escape et dire LIKE 'something\\%'
. Ou, si cela se trouve dans un littéral PHP "
qui utilise également une barre oblique inverse, "LIKE 'something\\\\%'"
. Argh!
Ceci est incorrect selon ANSI SQL, qui stipule que: dans les chaînes de texte, les barres obliques inverses signifient des antislashs littéraux et la manière d'échapper une seule citation est ''
; dans les expressions LIKE, il n'y a aucun caractère d'échappement par défaut. Par conséquent, si vous voulez ÉCHAPPER LIKE de manière portable, vous devez remplacer le comportement par défaut (incorrect) et spécifier votre propre caractère d'échappement, en utilisant la construction LIKE ... ESCAPE ...
. Pour la santé mentale, nous allons choisir quelque chose d'autre que le foutu backslash!
function like($s, $e) {
return str_replace(array($e, '_', '%'), array($e.$e, $e.'_', $e.'%'), $s);
}
$escapedname= mysql_real_escape_string(like($name, '='));
$query= "... WHERE name LIKE '%$escapedname%' ESCAPE '=' AND ...";
ou avec des paramètres (par exemple en AOP.):
$q= $db->prepare("... WHERE name LIKE ? ESCAPE '=' AND ...");
$q->bindValue(1, '%'.like($name, '=').'%', PDO::PARAM_STR);
(Si vous voulez la fête plus la portabilité, vous pouvez aussi vous amuser à essayer de rendre compte de MS SQL Server et Sybase, où le [
caractère est également, à tort, spécial dans une déclaration LIKE
et doit être échappé.)
Je voudrais encore +1 pour "la backslash damn!". – BoltClock
Merci, absorber cela maintenant ... cela m'aide vraiment à élargir mes connaissances de base. Bêtement, j'échappais à% et _ même si je n'utilise pas d'instruction LIKE et puisque je pense (veuillez confirmer) que% et _ ne sont que sauvages dans le contexte d'une instruction LIKE, je perds en fait mon temps. Mais alors cela me fait penser pourquoi voudriez-vous jamais échapper un% ou _ quand c'est dans le contexte d'une instruction LIKE. Sûrement la seule raison d'utiliser une déclaration LIKE est que vous pouvez utiliser ses caractères sauvages. (S'il vous plaît excusez mes connaissances limitées à ce sujet) – Columbo
Bien sûr, mais il est tout à fait naturel de vouloir pouvoir rechercher un caractère littéral '%' ou '_'. Si un utilisateur recherche '50%' dans la partie frontale, cela signifie probablement qu'il cherche une chaîne contenant '50%' et pas n'importe laquelle avec '50'. – bobince