Подтвердить что ты не робот

Постоянный способ выполнения mysqli-> set_charset()?

после установки всех конфигурационных файлов и параметров времени выполнения для кодировки, которую я могу найти для utf-8, новые соединения mysqli, выполненные с php, все еще имеют набор символов для 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}).");

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

Аналогичная проблема возникла в этом сообщении.


a "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.

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

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

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

^ update: согласно руководству 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. как сервер преобразует строку из charset character_set_client в character_set_server, не зная, что используемая в данный момент кодировка?

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

Обновлено с помощью workaroud:

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

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

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

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

4b9b3361

Ответ 1

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

Если вы думаете о том, как работают PHP MySQL/MySQL, это будет иметь смысл - они не имеют ничего общего с клиентской программой 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 и добавлять или переопределять любые методы, которые вы хотите (I это было сделано с помощью простых приложений без ORM).

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

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

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

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

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

Ответ 2

в соответствии со следующими сообщениями из 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

ваши настройки не совсем правы. i.e.

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

 [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, чтобы отключить возможность для клиента для изменения настройки символа. Но я не могу найти ref в документации mysql. Если я найду это, я дам вам знать.

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

Привет

UPDATE

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

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

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

или

[клиент]
default-character-set = utf8

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

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

Ответ 3

Я знаю, что это очень старая тема, но я только что столкнулся с этой проблемой на своем ноутбуке 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.