Por favor, explique como o Wordpress funciona com o conjunto de caracteres MySQL e agrupamento em um nível baixo

10

Como o título da pergunta sugere, estou procurando entender como o Wordpress funciona com conjuntos de caracteres e opções de agrupamento do MySQL. Como mostrarei abaixo, as coisas não fazem muito sentido para mim ...

Instalei o Wordpress seguindo as instruções na página de instalação:

https://codex.wordpress.org/Installing_WordPress

Como parte das instruções, segui os conselhos deles para a criação manual do banco de dados MySQL na linha de comando, a saber, os comandos:

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

Além disso, conforme as instruções, editei o arquivo "wp-config.php" para usar o conjunto de caracteres UTF-8:

define( 'DB_CHARSET', 'utf8' );

... e deixou a configuração de agrupamento em branco:

define( 'DB_COLLATE', '' );

Aqui é onde a diversão começa ...

  1. Se eu inserir um caractere que não faz parte do MySQL UTF-8, mas faz parte do UTF-8 MB4, como 𝌆, em uma postagem, ele será exibido corretamente na página renderizada. Eu esperava que isso não acontecesse, pois não defini o conjunto de caracteres para UTF-8 MB4, mas o UTF-8 mais restrito (conforme definido pelo MySQL, é claro, não como geralmente entendido).

  2. Se eu investigar o problema no MySQL na linha de comando, ele ficará mais estranho. Se eu executar show variables like 'char%';, recebo esta resposta:

    +--------------------------+----------------------------+
    | 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/ |
    +--------------------------+----------------------------+

Eu esperava que o conjunto de caracteres do banco de dados fosse UTF-8, não latin1.

  1. Se eu executar o comando show variables like 'collation%';, a saída é:

    +----------------------+-------------------+
    | Variable_name        | Value             |
    +----------------------+-------------------+
    | collation_connection | utf8_general_ci   |
    | collation_database   | latin1_swedish_ci |
    | collation_server     | latin1_swedish_ci |
    +----------------------+-------------------+

Isso é ainda mais estranho, por razões óbvias (não seria esperado o agrupamento latin1_swedish_ci padrão em um banco de dados UTF-8).

  1. Finalmente, se eu executar show full columns from mywpdatabase.wp_posts;, as linhas de saída, onde o valor não é NULL, mostram o agrupamento como:

| post_content_filtered | longtext | utf8mb4_unicode_ci |

Minha pergunta então - como isso pode ser explicado? Por que minha instalação do Wordpress renderiza corretamente caracteres UTF-8 MB4, quando o banco de dados é definido como UTF-8 na configuração? E por que o banco de dados é exibido no MySQL como latin1, agrupamento sueco, em vez de UTF-8? E como, apesar de tudo isso, os campos individuais da tabela são utf8mb4_unicode_ci? Uma explicação de baixo nível sobre como o Wordpress trabalha com o MySQL seria muito útil. Obrigado!

X-Mann
fonte

Respostas:

11

Existem duas definições no site wp-config.php do WordPress:

define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');

Existem várias coisas que são mais comumente incompreendidas. Os nomes de constantes nessas definições podem sugerir que eles estão relacionados ao próprio banco de dados. Eles não são. Eles estão relacionados às tabelas no banco de dados.

A criação do banco de dados é totalmente independente da criação da tabela. O WordPress não cria um banco de dados e não se importa com o conjunto de caracteres padrão e o agrupamento, desde que possa se conectar ao banco de dados.

O valor 'utf8' na primeira definição significa o conjunto de caracteres menos restrito da família 'utf8', que é 'utf8' ou 'utf8mb4'.

Se você deixar as definições acima inalteradas, antes de tentar instalar seu site, é como dizer ao WordPress para fazer suas próprias escolhas, em relação ao conjunto de caracteres e agrupamento de tabelas do banco de dados, que são suportados pelo MySQL (dependendo da versão do MySQL) e são menos limitantes.

A seguir, o que o WordPress analisa para determinar suas opções durante a instalação:

  • Versão do MySQL
  • agrupamento do banco de dados (em wp-config.php)

Baseado na versão do MySQL, o WordPress decide qual grupo de famílias utf8 usar. Existem dois, diferenciados por seus nomes: utf8 e utf8mb4 . Os conjuntos de caracteres do grupo utf8 permitem o armazenamento de no máximo 3 bytes de caracteres. Os conjuntos de caracteres do grupo utf8mb4 permitem o armazenamento de caracteres máximos de 4 bytes.

Agora, o WordPress verifica o valor de DB_COLLATE define. Se vazio, ele usará o agrupamento menos limitativo da família utf8 escolhida ; caso contrário, usará o valor especificado.

Exemplos

define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');

Se o MySQL não suportar utf8mb4 (versões mais antigas), o conjunto de caracteres das tabelas será utf8 e o agrupamento será utf8_general_ci . Caso contrário, podemos esperar utf8mb4 e utf8mb4_unicode_520_ci ou utf8mb4_unicode_ci (dependente da versão do MySQL), respectivamente.

define('DB_CHARSET', 'utf8');
define('DB_COLLATE', 'utf8_polish_ci');

Versão mais antiga do MySQL - utf8 e utf8_polish_ci . Versão mais recente do MySQL - utf8mb4 e utf8mb4_polish_ci (o sufixo _polish_ci é respeitado)

define('DB_CHARSET', 'cp1250');
define('DB_COLLATE', 'cp1250_polish_ci');

Qualquer versão do MySQL - cp1250 e cp1250_polish_ci .

define('DB_CHARSET', 'cp1250');
define('DB_COLLATE', 'utf8_general_ci');

Qualquer versão do MySQL - erro (incompatibilidade de conjunto de caracteres e agrupamento)

Sumário

Na maioria dos casos, deixar valores de define, explicados acima, inalterados, é uma boa opção. Mas, se você deseja que o agrupamento de tabelas corresponda ao idioma do seu site, é possível modificar o valor de DB_COLLATE definido adequadamente (por exemplo - utf8mb4_polish_ci ).

Nota: isso explica por que o caractere 𝌆 foi armazenado e recuperado corretamente. Simplesmente, seu conjunto de caracteres de tabelas pertencia ao grupo utf8mb4 , não ao utf8 .

Frank P. Walentynowicz
fonte
11
Obrigado por explicar como o Wordpress define a intercalação, mas você não abordou o restante dos pontos. Por que, se o conjunto de caracteres UTF-8 está definido, o MySQL mostra o banco de dados como latin1? E por que está mostrando o agrupamento de banco de dados como sueco? Além disso, você parece confundir conjunto de caracteres e agrupamento. O agrupamento define apenas a ordem, as regras de comparação e não o conjunto de caracteres. Portanto, independentemente do agrupamento usado, se UTF-8 for o conjunto de caracteres, caracteres fora dele (conforme definido no sentido mais restrito do MySQL) não serão renderizados.
X-Mann
Vou atualizar minha resposta, para explicar mais claramente o processo.
Frank P. Walentynowicz
11
Obrigado pela atualização! Eu aceitei sua resposta, está tudo claro agora. O problema está no MySQL e na minha falta de conhecimento - eu não sabia que as tabelas podem usar um conjunto de caracteres mais amplo que o próprio banco de dados. Esta nova informação deixou minha mente à vontade. Não preciso alterar o conjunto de caracteres padrão no MySQL, o Wordpress cuida dele no nível da tabela.
X-Mann
Você é bem vindo. Estou feliz que ajudou.
Frank P. Walentynowicz