设置了我可以找到utf-8的charset的所有配置文件和运行时选项之后,用php创建的新mysqli连接仍然将其字符集设置为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%'
在调用show之前在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
客户端,连接和结果字符集只能$mysqli->set_charset('utf8')
在运行时更改为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使用了后备charset latin1.
我正在使用mysql 5.1在debian wheezy上运行php 5.3.
有什么建议吗?
更新了评论信息:
我忘了提到skip-character-set-client-handshake
指令以及为什么我不愿意使用它.
乍一看,我认为忽略握手可能会导致客户端在服务器会话utf8时会说latin1的情况.服务器如何将字符串从charset转换为不知道当前正在使用的字符集?character_set_client
character_set_server
如果我错了,请纠正我,PLZ. 我将在今天晚些时候试验这个设置,看看它是否有效.
更新了workaroud:
确保一切都在utf-8(或任何更好的字符集)下工作.然后添加skip-character-set-client-handshake
行my.cnf
.
到目前为止,这对我有用.我尝试了一些双倍宽度的utf-8字符.既insert
和select
成功,在浏览器中正确显示.
跳过握手意味着什么还不清楚.并且mysql服务器现在变得无法使用除utf-8之外的任何字符集,这使得这种解决方法非常不切实际,因为我无法将此设置应用于我的网站运行的所有服务器.
所以我不采用这种解决方法.进一步的意见和答案非常感谢.
你已经正确诊断的基本问题:虽然您可以更改客户端计算机的默认MySQL客户端字符集my.cnf
或者.my.cnf
,这些文件不使用PHP.
如果您考虑PHP的MySQLi/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并添加或覆盖你想要的任何方法(我已经完成了)这与简单的无ORM应用程序).
总是拥有某种数据库抽象层是一种很好的做法,即使它只是class MyDB extends mysqli {}
因为你将永远不必搜索/替换整个代码库来进行小的更改.
RE:您的解决方法,正如您解释的那样,无论客户端请求什么,这基本上都将您的整个数据库服务器硬编码为UTF-8.服务器只使用UTF-8而不是拥有多个数据库,每个数据库都有自己的字符集,如果客户端与另一个字符集连接,可能会静默地破坏数据.这是根本错误的,因为您已经有效地将应用程序配置(数据库字符集)的一个方面从app/client机器移动到它不真正属于的数据库服务器.
如果你考虑应用程序堆栈的层,
[server] <=> [network] <=> [client libmysql] <=> [PHP binary] <=> [app]
然后你会明白,像这样的特定于应用程序的配置的"正确"位置是在应用程序本身,而不是堆栈中的其他位置.你可以不喜欢有在PHP中指定数据库的字符集,但如果你仔细想想,这真的属于它的地方,因为它也是在那里你指定要连接到数据库本身 - 这是一个连接参数,不是服务器配置问题.在其他任何地方对字符集进行硬编码会使您的应用程序无法移植.