Spiegazione del funzionamento di Wordpress con il set di caratteri e la collazione MySQL a basso livello
Come suggerisce il titolo della domanda, sto cercando di capire come Wordpress funziona con i set di caratteri MySQL e le opzioni di collazione. Come mostrerò di seguito, alcune cose non hanno molto senso per me...
Ho installato Wordpress seguendo le istruzioni nella loro pagina di installazione:
https://codex.wordpress.org/Installing_WordPress
Come parte delle istruzioni, ho seguito il loro consiglio per la creazione manuale del database MySQL dalla riga di comando, specificatamente i comandi:
mysql> CREATE DATABASE databasename;
Query OK, 1 row affected (0.00 sec)
mysql> GRANT ALL PRIVILEGES ON databasename.* TO "wordpressusername"@"hostname"
-> IDENTIFIED BY "password";
Query OK, 0 rows affected (0.00 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)
mysql> EXIT
Inoltre, come indicato, ho modificato il file "wp-config.php" per utilizzare il set di caratteri UTF-8:
define( 'DB_CHARSET', 'utf8' );
...e ho lasciato vuota l'impostazione della collazione:
define( 'DB_COLLATE', '' );
Ed è qui che inizia il divertimento...
Se inserisco un carattere che non fa parte di UTF-8 di MySQL, ma fa parte di UTF-8 MB4, come , in un post, viene visualizzato correttamente nella pagina renderizzata. Mi sarei aspettato che questo non accadesse, dato che non ho impostato il set di caratteri su UTF-8 MB4, ma sul più ristretto UTF-8 (come definito da MySQL ovviamente, non come generalmente inteso).
Se investigo la questione in MySQL dalla riga di comando, diventa ancora più strano. Se eseguo
show variables like 'char%';
, ottengo questa risposta:+--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | latin1 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+
Mi sarei aspettato che il set di caratteri del database fosse UTF-8, non latin1.
Se eseguo il comando
show variables like 'collation%';
, l'output è:+----------------------+-------------------+ | Variable_name | Value | +----------------------+-------------------+ | collation_connection | utf8_general_ci | | collation_database | latin1_swedish_ci | | collation_server | latin1_swedish_ci | +----------------------+-------------------+
Questo è ancora più strano, per ovvie ragioni (non mi sarei aspettato la collazione predefinita latin1_swedish_ci in un database UTF-8).
- Infine, se eseguo
show full columns from mywpdatabase.wp_posts;
, le righe di output, dove il valore non è NULL, mostrano che la collazione è:
| post_content_filtered | longtext | utf8mb4_unicode_ci |
La mia domanda è quindi - come si può spiegare tutto questo? Perché la mia installazione di Wordpress visualizza correttamente i caratteri UTF-8 MB4, quando il database è definito come UTF-8 nella configurazione? E perché il database viene mostrato in MySQL come latin1, con collazione svedese, invece che UTF-8? E come mai, nonostante tutto questo, i singoli campi nella tabella sono utf8mb4_unicode_ci? Una spiegazione a basso livello del modo in cui Wordpress lavora con MySQL sarebbe molto utile. Grazie!
Ci sono due definizioni nel file wp-config.php di un sito WordPress:
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');
Ci sono diverse cose che vengono spesso fraintese. I nomi delle costanti in queste definizioni potrebbero far pensare che siano relative al database stesso. Non è così. Sono relative alle tabelle all'interno del database.
La creazione del database è totalmente indipendente dalla creazione delle tabelle. WordPress non crea un database e non si preoccupa del set di caratteri predefinito e della collazione del database, purché possa connettersi al database.
Il valore 'utf8' nella prima definizione indica il set di caratteri meno restrittivo della famiglia 'utf8', che può essere 'utf8' o 'utf8mb4'.
Se lasci le definizioni sopra invariate, prima di tentare di installare il tuo sito, è come dire a WordPress di fare le sue scelte riguardo al set di caratteri e alla collazione delle tabelle del database, che sono supportati da MySQL (a seconda della versione di MySQL) e sono i meno limitanti.
Ecco le cose che WordPress analizza per determinare le sue scelte durante l'installazione:
- Versione di MySQL
- Collazione del database (in wp-config.php)
In base alla versione di MySQL, WordPress decide quale gruppo della famiglia utf8 utilizzare. Ce ne sono due, distinti dai loro nomi: utf8 e utf8mb4. I set di caratteri del gruppo utf8 consentono di memorizzare caratteri con una lunghezza massima di 3 byte. I set di caratteri del gruppo utf8mb4 consentono di memorizzare caratteri con una lunghezza massima di 4 byte.
Ora, WordPress controlla il valore della definizione DB_COLLATE. Se è vuoto, utilizzerà la collazione meno limitante della famiglia utf8 scelta, altrimenti utilizzerà il valore specificato.
Esempi
define('DB_CHARSET', 'utf8'); define('DB_COLLATE', '');
Se MySQL non supporta utf8mb4 (versioni più vecchie) allora il set di caratteri delle tabelle sarà utf8 e la collazione sarà utf8_general_ci. Altrimenti, possiamo aspettarci utf8mb4 e utf8mb4_unicode_520_ci, o utf8mb4_unicode_ci (a seconda della versione di MySQL), rispettivamente.
define('DB_CHARSET', 'utf8'); define('DB_COLLATE', 'utf8_polish_ci');
Versione più vecchia di MySQL - utf8 e utf8_polish_ci. Versione più recente di MySQL - utf8mb4 e utf8mb4_polish_ci (il suffisso _polish_ci viene rispettato)
define('DB_CHARSET', 'cp1250'); define('DB_COLLATE', 'cp1250_polish_ci');
Qualsiasi versione di MySQL - cp1250 e cp1250_polish_ci.
define('DB_CHARSET', 'cp1250'); define('DB_COLLATE', 'utf8_general_ci');
Qualsiasi versione di MySQL - errore (mancata corrispondenza tra set di caratteri e collazione)
Riepilogo
Nella maggior parte dei casi, lasciare invariati i valori delle definizioni spiegate sopra è una buona scelta. Ma, se vuoi che la collazione delle tabelle corrisponda alla lingua del tuo sito, puoi modificare il valore della definizione DB_COLLATE in modo appropriato (ad esempio - utf8mb4_polish_ci).
Nota: questo spiega perché il carattere è stato memorizzato e recuperato correttamente. Semplicemente, il set di caratteri delle tue tabelle apparteneva al gruppo utf8mb4, non a utf8.

Grazie per aver spiegato come WordPress imposta la collation, ma non hai affrontato gli altri punti. Perché, se è definito il set di caratteri UTF-8, MySQL mostra il database come latin1? E perché mostra la collation del database come svedese? Inoltre, sembra che tu stia confondendo il set di caratteri con la collation. La collation definisce solo le regole di ordinamento e confronto, non il set di caratteri. Quindi, indipendentemente dalla collation utilizzata, se UTF-8 è il set di caratteri, i caratteri al di fuori di esso (come definito nel senso più ristretto di MySQL) non dovrebbero essere visualizzati.

Aggiornerò la mia risposta per spiegare più chiaramente il processo.

Grazie per l'aggiornamento! Ho accettato la tua risposta, ora è tutto chiaro. Il problema è con MySQL e la mia mancanza di competenza in esso - non sapevo che le tabelle possono utilizzare un set di caratteri più ampio rispetto al database stesso. Questa nuova informazione mi ha tranquillizzato. Non ho bisogno di cambiare il set di caratteri predefinito in MySQL, WordPress se ne occupa a livello di tabella.
