Come nota, prima di dire qualcosa su questo problema: per favore considera di passare a MySQLi o PDO con query parametrizzate. Non solo sono un ordine o grandezza più sicuri, ma sono più facili da utilizzare e pienamente supportati. Le vecchie funzioni mysql_
sono ora considerate al termine del ciclo di vita e saranno presto deprecate. (mi dispiace, ho perso il i
dal tuo post originale ... maledette chiamate procedurali!)
MySQL opera su stringhe. Le stringhe sono due cose: una sequenza di byte e una sequenza di caratteri. Il modo in cui queste due sequenze si mappano è chiamato set di caratteri, che è specificato da una codifica.
Ad esempio, ASCII mappa lettere, numeri, simboli e caratteri di controllo sui valori di byte da 0 a 127. ASCII estesi quindi aggiunge più caratteri per i valori da 128 a 255. Altre codifiche, come la famiglia UTF (es. UTF- 8) utilizzare byte singoli o multipli per codificare caratteri diversi. Ad esempio, i caratteri UTF-16 possono essere codificati come uno o due codepoint di 2 byte (vale a dire ogni carattere è codificato come 2 o 4 byte).
La parte interessante si verifica quando si assume un set di caratteri o una codifica, ma i dati sottostanti vengono effettivamente codificati in modo diverso. Ad esempio, il carattere CJK est-asiatico per "acqua" è 水, che è definito in UTF-16 come U + 6C34. Questo codifica per 34 6C
in UTF-16LE. Ora, se accidentalmente supponiamo che i dati che ci sono stati consegnati siano ASCII, dovremmo decodificare questo come "4l" piuttosto che il carattere Unicode corretto.
Ora, cosa succede se l'applicazione front-end (in questo caso PHP) è stata configurata per utilizzare l'ASCII esteso, ma le regole di confronto del database sono state impostate su UTF-8 (ad es. utf8_general_ci) e il computer dell'utente è stato configurato per utilizzare il Windows CP1251 Codepage in cirillico? In un mondo ideale, ogni sistema riconoscerebbe i requisiti dell'applicazione di destinazione e convertirà in modo appropriato. Sfortunatamente questo non è un mondo ideale. I byte sottostanti che rappresentano i caratteri cirillici verrebbero probabilmente trasformati in caratteri ASCII sulla loro strada nella webapp di PHP. Quindi, qualsiasi carattere elevato (128-255) potrebbe re-mappare a sequenze di byte diverse quando i caratteri ASCII vengono convertiti in UTF-8, o potrebbe addirittura formare caratteri completamente nuovi se accidentalmente tradotti in codice in codepoint UTF-8. In alcuni casi, esistono regole speciali che causano determinati codepoint sequenziali (ad esempio segni diacritici) per essere combinati in caratteri speciali.
In breve: la codifica dei caratteri è voodoo . Questo è un territorio serio "qui sia i draghi". Se riesci a ottenere una risposta sensata da chiunque abbia scritto una vera libreria di stringhe prima (di solito scarabocchiano "cthulhu ebcdic fhtagn" sul tuo viso con un pennarello magico e se ne allontani misteriosamente) allora loro probabilmente ti dirò alcune cose veramente disgustose sull'abominio che è il nostro linguaggio umano.
Perché questo è importante per cose come mysql_escape_string
? Bene, diciamo che la tua app PHP è in modalità UTF-8, ma il tuo server MySQL è in esecuzione in modalità ASCII. Il tuo utente digita un carattere ∻ ( U + 223B ) e la tua funzione di fuga dice "Spara bene, mi sta bene, ho solo cura di citazioni e cose ". Il tuo server MySQL quindi guarda quei byte sottostanti ... oh, risulta che 22 3B
è una codifica di ";
in ASCII. Ops!
Questo peggiora quando ti ricordi di quelli che combinano trucchi. Puoi fare cose come applicare un segno diacritico a un pezzo di punteggiatura, o dare uno schiaffo alla punteggiatura nel mezzo di un testo arabo, e potrebbe essere combinato in un carattere "combinato" con un codepoint completamente diverso quando viene ricodificato . Questo è importante quando utilizzi diversi moderni formati di codifica come UTF-8 e UTF-16 insieme.
La funzione mysql_real_escape_string
tenta di salvarci da questo inferno controllando correttamente la stringa una volta che è stata ricodificata nella codifica selezionata del server MySQL di destinazione. Ha bisogno di un riferimento alla connessione per recuperare questi metadati dal server.
La cosa più misericordiosa del mondo, penso, è l'incapacità della mente umana di comprendere le codifiche dei caratteri. Viviamo in una placida isola dell'ignoranza in mezzo a mari neri di codice, e non intendevamo viaggiare lontano. Le lingue, ognuna tesa nella sua stessa direzione, ci hanno finora danneggiato poco; ma un giorno il mettere insieme i piani Unicode dissociati aprirà così terrificanti eccentricità del linguaggio, e della nostra terrificante posizione in esso, che dovremo o separarci dalla rivelazione o fuggire dalla luce nella pace e nella sicurezza di EBCDIC.