2010-09-10 4 views
35

Sur un serveur plus ancien j'utilise que je ne peux pas utiliser les instructions préparées sur J'essaye actuellement d'échapper complètement l'entrée d'utilisateur avant de l'envoyer à MySQL. Pour cela, j'utilise la fonction PHP mysql_real_escape_string.Echapper à des caractères génériques MySQL

Puisque cette fonction n'échappe pas aux caractères génériques MySQL% et _ j'utilise addcslashes pour les échapper également.

Quand j'envoie quelque chose comme:

test_test " ' 

à la base de données, puis relis la base de données montre:

test\_test " ' 

En regardant cela, je ne comprends pas pourquoi le _ a une précédente backslash mais le "et" ne le font pas Puisqu'ils sont tous échappés avec \ sûrement _ 'et "devraient tous sembler identiques, tous ont le caractère d'échappement visible ou tous ne l'ont pas visible.

sont les échappements \ s automatiquement criblés pour

Quelqu'un peut-il expliquer cela?

Répondre

79

_ 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é.)

+4

Je voudrais encore +1 pour "la backslash damn!". – BoltClock

+0

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

+2

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

Questions connexes