постоянный способ сделать mysqli-> set_charset ()? - PullRequest
15 голосов
/ 30 апреля 2011

после установки всех конфигурационных файлов и опций времени выполнения для набора символов, которые я могу найти в utf-8, для новых соединений mysqli, установленных с помощью php, по-прежнему установлено значение charset, равное latin1, что фактически означает, что мне нужно каждый раз вызывать $mysqli->set_charset('utf8') подключения.

$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);  
if ($mysqli->connect_error)  
  err_handle("mysql connect error({$mysqli->connect_errno}).");  
if (!$mysqli->set_charset("utf8"))  
  err_handle("db error({$mysqli->errno}).");

Интересно, есть ли постоянный способ сделать это?

похожая проблема возникла в этом посте .


запрос "show variables like 'character_set%'" на сервере MySQL перед вызовом $mysqli->set_charset('utf8') показывает:
(эта часть была неоднозначной в предыдущих оборотах)

character_set_client    latin1  
character_set_connection    latin1  
character_set_database  utf8  
character_set_filesystem    binary  
character_set_results   latin1  
character_set_server    utf8  
character_set_system    utf8  

клиент, кодировка соединения и результатов могут быть изменены только на utf8 с $mysqli->set_charset('utf8') во время выполнения. после этого он показывает:

character_set_client    utf8  
character_set_connection    utf8  
character_set_database  utf8  
character_set_filesystem    binary  
character_set_results   utf8  
character_set_server    utf8  
character_set_system    utf8  

у меня есть

default_charset = "utf-8"

установлено в php.ini и

[client]  
default-character-set=utf8  
...  
[mysqld]  
## This option is deprecated in favor of --character-set-server.
#default-character-set=utf8  

установлено в my.cnf.

кодировка по умолчанию для моих таблиц также utf8.

похоже, что параметры "[client]" влияют только на инструмент cmd "mysql" и не имеют ничего общего с php.

Возвращаемое значение $mysqli->character_set_name() всегда latin1 , независимо от того, что я делаю, до тех пор, пока не будет вызван $mysqli->set_charset('utf8').

Полагаю, что "latin1" - вещь, связанная с mysql, так как я не могу вспомнить ничего, что по умолчанию равно "latin1" в моей системе.

^ обновление: в соответствии с руководством mysql 9.1.4 , 9.1.5 и 5.1.3 , character_set_client следует быть предоставленным клиентом. Я полагаю, php не предоставляет его при подключении, и MySQL использует запасной набор символов latin1 .

Я использую php 5.3 на Debian Wheezy с MySQL 5.1.

есть предложения?


дополнено информацией из комментариев:

я забыл упомянуть директиву skip-character-set-client-handshake и почему я не хотел ее использовать.

с первого взгляда я подумал, что игнорирование рукопожатия может привести к ситуации, когда клиент говорит latin1 , в то время как сервер говорит utf8 . как сервер преобразует строку из кодировки character_set_client в character_set_server, не зная, какая кодировка используется в данный момент?

поправьте меня, если я не прав, плз. Я поэкспериментирую с этим параметром позже сегодня, чтобы проверить, работает ли он.

Обновлено с workaroud :

убедитесь, что все работает под utf-8 (или любой другой предпочтительной кодировкой). затем добавьте строку skip-character-set-client-handshake к my.cnf.

это работает для меня до сих пор. я экспериментировал с некоторыми символами utf-8 двойной ширины. insert и select успешно выполнены и правильно отображаются в браузере.

что означает пропуск рукопожатия, до сих пор неясно. и сервер MySQL теперь не может использовать любую кодировку, кроме utf-8, что делает этот обход весьма непрактичным, поскольку я просто не могу применить этот параметр ко всем серверам, на которых работает мой веб-сайт.

так что я не принимаю этот обходной путь. дальнейшие комментарии и ответы приветствуются.

Ответы [ 3 ]

18 голосов
/ 07 июня 2011

Вы правильно диагностировали основную проблему: хотя вы можете изменить кодировку клиента MySQL по умолчанию в my.cnf или .my.cnf клиентского компьютера, эти файлы не используются PHP.

Если вы думаете окак работают расширения MySQLi / MySQL в PHP, это будет иметь смысл - они не имеют ничего общего с клиентской программой mysql и не собираются сканировать вашу файловую систему на наличие конфигурационных файлов, поскольку они используют libmysql напрямую.

Чтобы изменить действующую кодировку libmysql по умолчанию, вам просто нужно пересобрать libmysql.Возможно, это не тот ответ, который вам нравится (поскольку вы используете предварительно скомпилированные двоичные файлы MySQL), но это фактический ответ.Значения по умолчанию устанавливаются во время компиляции, а затем могут быть переопределены во время выполнения.

Если вы не хотите этого делать, и вызов set_charset () вас раздражает, я предлагаю просто расширить класс MySQLi ииспользуйте этот класс вместо mysqli.то есть:

class MyDB extends mysqli {
  // (You could set defaults for the params here if you want
  //  i.e. $host = 'myserver', $dbname = 'myappsdb' etc.)
  public function __construct($host = NULL, $username = NULL, $dbname = NULL, $port = NULL, $socket = NULL) {
    parent::__construct($host, $username, $dbname, $port, $socket);
    $this->set_charset("utf8");
  } 
} 

Как правило, в приложении у вас все равно будет какой-то уровень абстракции базы данных, поэтому вы можете либо использовать этот слой, используя MyDB вместо mysqli, либо этот слой будет MyDB и добавьте или переопределите любые методы, которые вы хотите (я сделал это с простыми приложениями без ORM).

Хорошей практикой является всегда иметь какой-то слой абстракции базы данных, даже если он запускаетсякак просто class MyDB extends mysqli {}, потому что тогда вам никогда не придется искать / заменять всю кодовую базу, чтобы вносить небольшие изменения.

RE: ваш обходной путь, как вы объясняете, по сути, жестко кодирует весь ваш сервер базы данных в UTF-8независимо от того, что клиенты запрашивают.Вместо нескольких баз данных, каждая из которых имеет свою собственную кодировку, сервер работает только с UTF-8 и может молча манипулировать данными, если клиенты соединяются с другой кодировкой.Это в корне неверно, потому что вы фактически переместили один аспект конфигурации вашего приложения (кодировка базы данных) с компьютера приложения / клиента на сервер базы данных, где он на самом деле не принадлежит.

Если вы думаете о приложениислои стека,

[server] <=> [network] <=> [client libmysql] <=> [PHP binary] <=> [app]

, тогда вы поймете, что «правильное» место для конкретной конфигурации приложения, как это, находится в самом приложении, а не где-либо еще в стеке.Возможно, вам не понравится указывать кодировку вашей базы данных в PHP, но если вы подумаете об этом, это действительно то, к чему она относится, потому что именно там вы указываете саму базу данных, к которой хотите подключиться - это параметр соединения,не проблема конфигурации сервера.Жесткое кодирование кодировки в любом другом месте делает ваше приложение непереносимым.

2 голосов
/ 30 апреля 2011

согласно следующим постам из MySQL

http://dev.mysql.com/doc/refman/5.0/en/charset-connection.html http://dev.mysql.com/doc/refman/5.0/en/charset-applications.html

Ваши настройки не совсем верны, т.е.

использовать

 [mysqld]
 character-set-server=utf8
 collation-server=utf8_general_ci

вместо

 [mysqld]
 default-character-set=utf8

для клиента, которого я только нашел

 [mysql]
 default-character-set=utf8

не

 [client]
 default-character-set=utf8

попробуйте дать мне обратную связь.

Я помню, что однажды я читал о настройке var, чтобы отключить возможность для клиента изменить настройку персонажа. Но я не могу найти ссылку в документации MySQL сейчас. Если я найду его, я дам вам знать.

Надеюсь, это поможет.

Привет

UPDATE

@ Unisland Кстати, я нашел эту тему http://www.webmasterworld.com/php/3553642.htm, где обсуждается похожая проблема

Попробуйте либо

Так что вы можете попробовать добавить:
[ТуздЫ]
init-connect = 'SET NAMES utf8'

или

[клиент]
набор символов по умолчанию = utf8

[туздЫ] * * тысяча пятьдесят-одна символьный набор-сервер = utf8
по умолчанию символов-комплект = utf8
по умолчанию-сверка = utf8_unicode_ci
набор символов-клиент = utf8

, чтобы установить это значение по умолчанию для всех соединений или начать с этих запросов после того, как ваш конкретный скрипт подключится к базе данных перед отправкой других запросов: SET NAMES utf8; SET CHARACTER_SET utf8;

0 голосов
/ 15 июня 2019

Я знаю, что это очень старая тема, но я только что столкнулся с этой проблемой на своем ноутбуке Fedora 30 KDE после установки MariaDB (и потратил более часа на поиск ответа). На моем сервере Ubuntu 18.04 все работает без изменения каких-либо конфигурационных файлов, но на моем ноутбуке с Fedora 30 KDE мне пришлось:

$ sudo vi /etc/my.cnf.d/client.cnf

, а затем добавили default-character-set в раздел [client-mariadb]:

[client-mariadb]
default-character-set = utf8mb4

Мне пришлось сделать то же самое для конфигурации сервера:

$ sudo vi /etc/my.cnf.d/mariadb-server.cnf

, а затем добавил следующее в раздел [mysqld]:

[mysqld]
character-set-server  = utf8mb4
collation-server      = utf8mb4_general_ci

Тогда просто перезапустите MariaDB:

$ sudo systemctl restart mariadb.service

После этого нет необходимости явно устанавливать набор символов в скриптах PHP.

...