TLDR
// The key is the "charset=utf8" part.
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8';
$dbh = new PDO($dsn, 'user', 'pass');
Questa risposta ha l'accento sulla libreria PDO di PHP, perché è così onnipresente.
Un breve promemoria: mysql è un'architettura client-server. Questo è significativo perché non c'è solo il server mysql in cui si trova il vero database, ma c'è anche il driver client mysql separato, che è la cosa che parla al server mysql (sono entità separate). Si potrebbe quasi dire che il client mysql e pdo sono mescolati insieme.
Quando si utilizza set names utf8
, si invia una query sql standard a mysql.Mentre la query sql passa attraverso pdo, e quindi attraverso la libreria client mysql, e infine raggiunge il server mysql, SOLO il server mysql analizza e interpreta quella query sql. Questo è significativo perché il server mysql non invia alcun messaggio a pdo o al client mysql, facendogli sapere che il set di caratteri e la codifica sono cambiati, e quindi pdo è totalmente all'oscuro del fatto che sia successo.
È importante non eseguire questa operazione perché la libreria client non può gestire correttamente le stringhe se non è a conoscenza del set di caratteri corrente. Le operazioni più comuni funzioneranno correttamente senza che il client conosca il set di caratteri corretto, ma uno che non eseguirà l'escaping delle stringhe, come ad esempio PDO::quote. Potresti pensare che non ti devi preoccupare di tale escape manuale delle stringhe primitive perché usi istruzioni preparate, ma la verità è la stragrande maggioranza di pdo: gli utenti mysql utilizzano inconsapevolmente emulated prepared statements perché è stata l'impostazione predefinita per il driver pdo: mysql per un tempo molto lungo ora. Una dichiarazione preparata emulata non usa le istruzioni preparate in mysql native come fornite da mysql api; al contrario, php fa l'equivalente di chiamare PDO::quote()
su tutti i tuoi valori e str_replacinginging tutti i tuoi segnaposto con i valori quotati per te.
Poiché non è possibile scappare correttamente una stringa a meno che non si conosca il set di caratteri che si sta utilizzando, queste istruzioni preparate emulate sono vulnerabili all'iniezione di SQL se si è passati a determinati set di caratteri tramite nomi di set. Indipendentemente dalla possibilità di SQL injection, è comunque possibile interrompere le stringhe se si utilizza uno schema di escape destinato a un set di caratteri diverso.
Per il driver pdo mysql, è possibile specificare il set di caratteri quando ci si connette, tramite specifying it in the DSN. La libreria client e il server saranno entrambi a conoscenza del set di caratteri se lo fai.
// The key is the "charset=utf8" part.
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8';
$dbh = new PDO($dsn, 'user', 'pass');
Ma l'escape non corretto delle stringhe non è l'unico problema. Ad esempio, puoi anche avere problemi con l'uso di PDO::bindColumn perché i nomi delle colonne sono specificati come stringhe, e quindi di nuovo la codifica è importante. Un esempio potrebbe essere un nome di colonna denominato ütube
(annotare la umlaut) e passare da latin
a utf8
tramite nomi di set e quindi provare a $stmt->bindColumn('ütube', $var);
con ütube
come stringa codificata utf8 perché il file php è codificato in utf8. Non funzionerà, avresti bisogno di codificare la stringa come una variante latin1 ... e ora hai tutti i tipi di follia in corso.
quale tecnica hai finito per implementare? –