一种永久的mysqli->set_charset()方式?

2022-08-31 00:59:36

在将我可以找到的字符集的所有配置文件和运行时选项设置为utf-8之后,使用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}).");

我想知道是否有永久的方法可以做到这一点?

这篇文章中也遇到了类似的问题。


在调用之前,mysql 服务器上的“”查询显示:
(此部分在以前的版本中是模棱两可的)show variables like 'character_set%'$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无关。

无论我做什么,返回值始终是 latin1,直到被调用。$mysqli->character_set_name()$mysqli->set_charset('utf8')

我想“latin1”是一个mysql的东西,因为我不记得在我的系统上默认为“latin1”的任何其他东西。

^更新:根据mysql手册9.1.49.1.55.1.3,应由客户端提供。我猜php在连接时不提供它,mysql使用回退字符集latin1character_set_client

我正在运行php 5.3在debian wheezy与mysql 5.1。

任何建议?


使用评论中的信息进行更新:

我忘了提到指令以及为什么我不愿意使用它。skip-character-set-client-handshake

乍一看,我认为忽略握手可能会导致客户端谈论latin1而服务器谈论utf8的情况。服务器如何将字符串从字符集转换为不知道当前正在使用的字符集?character_set_clientcharacter_set_server

如果我错了,请纠正我。我将在今天晚些时候尝试此设置,看看它是否有效。

使用工作指南更新:

确保一切在utf-8(或任何首选字符集)下工作。然后将该行添加到 。skip-character-set-client-handshakemy.cnf

到目前为止,这对我有用。我尝试了一些双倍宽度的utf-8字符。两者都成功并在浏览器中正确显示。insertselect

跳过握手意味着什么仍然不清楚。并且mysql服务器现在无法使用除utf-8以外的任何字符集,whick使此解决方法非常不切实际,因为我根本无法将此设置应用于运行我网站的所有服务器。

所以我不采用这种解决方法。非常感谢进一步的评论和答案。


答案 1

您已经正确诊断了基本问题:虽然您可以在客户端计算机或中更改默认的MySQL客户端字符集,但PHP不会使用这些文件。my.cnf.my.cnf

如果你考虑PHP的MySQLi/MySQL扩展是如何工作的,这将是有道理的 —— 它们与客户端程序无关,也不会抓取你的文件系统来查找配置文件,因为它们直接使用。mysqllibmysql

要更改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

根据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文档中找不到引用。如果我找到它,我会让你知道。

希望有所帮助。

问候

更新

顺便说一句,@Unisland我发现这个线程 http://www.webmasterworld.com/php/3553642.htm 讨论了类似的问题

尝试

所以你可以尝试添加一个:
[mysqld]
init-connect='SET NAMES utf8'

[客户端]
默认字符集 = utf8

[mysqld]
字符集服务器=utf8
默认字符集=utf8
默认排序规则=utf8_unicode_ci
字符集客户端 = utf8

将其设置为所有连接的默认值,或者在发送其他查询之前,在特定脚本连接到数据库后从这些查询开始:设置 NAMES utf8;SET CHARACTER_SET utf8;


推荐