_
och %
är inte jokertecken i MySQL i allmänhet, och bör inte escapes i syfte att sätta dem i normala strängliteraler. mysql_real_escape_string
är korrekt och tillräcklig för detta ändamål. addcslashes
bör inte användas.
_
och %
är speciella enbart i sammanhanget LIKE
-motsvarande. När du vill förbereda strängar för bokstavlig användning i en LIKE
uttalande, så att 100%
matchar hundra procent och inte vilken sträng som helst som börjar med hundra, du har två nivåer av flykt att oroa dig för.
Den första är LIKE att fly. LIKE-hantering sker helt i SQL, och om du vill förvandla en bokstavlig sträng till ett bokstavlig LIKE-uttryck måste du utföra detta steg även om du använder parametriserade frågor !
I detta schema, _
och %
är speciella och måste undkomma. Escape-karaktären måste också escapes. Enligt ANSI SQL får andra tecken än dessa inte vara escaped:\'
skulle vara fel. (Även om MySQL vanligtvis låter dig komma undan med det.)
Efter att ha gjort detta fortsätter du till den andra nivån av flykt, vilket är vanlig gammal sträng bokstavlig flykt. Detta sker utanför SQL, skapar SQL, så måste göras efter LIKE escape-steget. För MySQL är detta mysql_real_escape_string
som förut; för andra databaser kommer det att finnas en annan funktion, du kan bara använda parametriserade frågor för att undvika att behöva göra det.
Problemet som leder till förvirring här är att i MySQL använder man ett omvänt snedstreck som ett escape-tecken för båda de kapslade escape-stegen! Så om du vill matcha en sträng mot ett bokstavligt procenttecken måste du dubbel-backslash-escape och säga LIKE 'something\\%'
. Eller, om det är i en PHP "
literal som också använder backslash escaping, "LIKE 'something\\\\%'"
. Argh!
Detta är felaktigt enligt ANSI SQL, som säger att:i strängliterala snedstreck betyder omvänt snedstreck och sättet att undkomma ett enstaka citattecken är ''
; i LIKE-uttryck finns det inget escape-tecken alls som standard.
Så om du vill LIKE-escape på ett portabelt sätt bör du åsidosätta standardbeteendet (fel) och ange ditt eget escape-tecken, med hjälp av LIKE ... ESCAPE ...
konstruera. För förnuftets skull väljer vi något annat än det jävla snedstrecket!
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 ...";
eller med parametrar (t.ex. i PDO):
$q= $db->prepare("... WHERE name LIKE ? ESCAPE '=' AND ...");
$q->bindValue(1, '%'.like($name, '=').'%', PDO::PARAM_STR);
(Om du vill ha mer portabilitetstid kan du också ha kul med att försöka ta hänsyn till MS SQL Server och Sybase, där [
tecknet är också, felaktigt, speciellt i en LIKE
uttalande och måste undkomma. argh.)