【问题标题】:PHP, PDO, UTF8 and MySQL not playing ballPHP、PDO、UTF8 和 MySQL 不玩球
【发布时间】:2012-06-02 18:46:33
【问题描述】:

关于 UTF-8 字符,我真的很难通过 PDO 让 PHP 与 MySQL 一起玩。

我使用 php --version 得到以下信息:

PHP 5.3.6 (cli) (built: Apr 19 2011 13:21:12)
Copyright (c) 1997-2011 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2011 Zend Technologies

这是来自 mysql cli 的欢迎信息:

Server version: 5.1.57 Source distribution

我有这个作为我的数据库连接代码:

try {
    $dbh = new PDO('mysql:host='.$server.';dbname='.$database.';charset=UTF8', $user, $password, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"));
} catch (PDOException $e) {
    print "Error!: " . $e->getMessage() . "<br/>";
    die();
}

还有我要插入 MySQL 的 php 代码:

$dbh->query("SET NAMES 'UTF8'"); 
$values = array(':idCode' => $idCode, ':name' => $name, ':address' => $address, ':postcode' => $postcode, ':tel' => $tel, ':website' => $website, ':disabled' => $disabled, ':disabledWC' => $disabledWC, ':description' => $description, ':location' => $location, ':type' => $type, ':status' => $status, ':image1name' => $image1name, ':image2name' => $image2name, ':image3name' => $image3name, ':image4name' => $image4name, ':image5name' => $image5name);
$preparedStatement = $dbh->prepare('UPDATE venues SET name = :name, address = :address, postcode = :postcode, tel = :tel, website = :website, disabled = :disabled, disabledWC = :disabledWC, description = :description, location = :location, type = :type, status = :status, date_modified = NOW(), image1name = :image1name, image2name = :image2name, image3name = :image3name, image4name = :image4name, image5name = :image5name WHERE idCode = :idCode');
$preparedStatement->execute($values);

我遇到的问题是,即使我已经验证 $description 确实包含 UTF8 编码字节(使用 web2hex 和 web 上的 hex2UTF8 工具),数据也不会通过连接作为 UTF-8 提交我最终在数据库中使用“Générik”而不是“Générik”。

我尝试在执行之前调用“SET NAMES UTF8”,我已经输入:

[client]
default-character-set=utf8

[mysqld]
default-character-set=utf8

在我的 my.cnf 中,但似乎无法获得任何快乐。

关于如何让它发挥作用的任何提示或技巧?

我应该添加 - 如果我在命令行 MySQL 客户端中手动输入文本,它可以正常工作,该列设置为采用 UTF8 编码。

根据要求 - 创建表格脚本:

| venues | CREATE TABLE `venues` (
  `idCode` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(512) DEFAULT NULL,
  `address` varchar(1024) DEFAULT NULL,
  `postcode` varchar(32) DEFAULT NULL,
  `tel` varchar(32) DEFAULT NULL,
  `website` varchar(1024) DEFAULT NULL,
  `disabled` tinyint(4) DEFAULT NULL,
  `disabledWC` tinyint(4) DEFAULT NULL,
  `description` varchar(4096) CHARACTER SET utf8 DEFAULT NULL,
  `status` tinyint(4) DEFAULT NULL,
  `location` varchar(32) DEFAULT NULL,
  `type` varchar(32) DEFAULT NULL,
  `date_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `image1name` varchar(255) DEFAULT NULL,
  `image2name` varchar(255) DEFAULT NULL,
  `image3name` varchar(255) DEFAULT NULL,
  `image4name` varchar(255) DEFAULT NULL,
  `image5name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`idCode`)
) ENGINE=MyISAM AUTO_INCREMENT=129 DEFAULT CHARSET=latin1

以及 SELECT @@character_set_database 的结果:

SELECT @@character_set_database
    -> ;
+--------------------------+
| @@character_set_database |
+--------------------------+
| utf8                     |
+--------------------------+
1 row in set (0.00 sec)

以及dumpParams的结果:

SQL: [410] UPDATE venues SET name = :name, address = :address, postcode = :postcode, tel = :tel, website = :website, disabled = :disabled, disabledWC = :disabledWC, description = :description, location = :location, type = :type, status = :status, date_modified = NOW(), image1name = :image1name, image2name = :image2name, image3name = :image3name, image4name = :image4name, image5name = :image5name WHERE idCode = :idCode
Params:  17
Key: Name: [7] :idCode
paramno=-1
name=[7] ":idCode"
is_param=1
param_type=2
Key: Name: [5] :name
paramno=-1
name=[5] ":name"
is_param=1
param_type=2
Key: Name: [8] :address
paramno=-1
name=[8] ":address"
is_param=1
param_type=2
Key: Name: [9] :postcode
paramno=-1
name=[9] ":postcode"
is_param=1
param_type=2
Key: Name: [4] :tel
paramno=-1
name=[4] ":tel"
is_param=1
param_type=2
Key: Name: [8] :website
paramno=-1
name=[8] ":website"
is_param=1
param_type=2
Key: Name: [9] :disabled
paramno=-1
name=[9] ":disabled"
is_param=1
param_type=2
Key: Name: [11] :disabledWC
paramno=-1
name=[11] ":disabledWC"
is_param=1
param_type=2
Key: Name: [12] :description
paramno=-1
name=[12] ":description"
is_param=1
param_type=2
Key: Name: [9] :location
paramno=-1
name=[9] ":location"
is_param=1
param_type=2
Key: Name: [5] :type
paramno=-1
name=[5] ":type"
is_param=1
param_type=2
Key: Name: [7] :status
paramno=-1
name=[7] ":status"
is_param=1
param_type=2
Key: Name: [11] :image1name
paramno=-1
name=[11] ":image1name"
is_param=1
param_type=2
Key: Name: [11] :image2name
paramno=-1
name=[11] ":image2name"
is_param=1
param_type=2
Key: Name: [11] :image3name
paramno=-1
name=[11] ":image3name"
is_param=1
param_type=2
Key: Name: [11] :image4name
paramno=-1
name=[11] ":image4name"
is_param=1
param_type=2
Key: Name: [11] :image5name
paramno=-1
name=[11] ":image5name"
is_param=1
param_type=2

$description 的记录的十六进制字节(和预期的字符串值):

 Desctription: 526f756e64696e67206f6666205361747572646179206e6967687420696e20756e666f726765747461626c65207374796c652c204672656e636820636f6d70616e792047c3a96ec3a972696b20566170657572206272696e67207468656972206e65772073686f772057617465726c69747a20746f207468652048617420466169722e204174204b696e672047656f726765205620506c6179696e67204669656c64732c2042617220456e642e: Rounding off Saturday night in unforgettable style, French company Générik Vapeur bring their new show Waterlitz to the Hat Fair. At King George V Playing Fields, Bar End.

【问题讨论】:

  • 你有没有试过在执行$preparedStatement-&gt;debugDumpParams()之前执行它?它给了什么?
  • $preparedStatement->debugDumpParams() 产生:Params: 0
  • 在调用$preparedStatement-&gt;debugDumpParams()之前将参数“绑定”到PDO语句,如$preparedStatement-&gt;bindParam(':description', $description', PDO::PARAM_STR);等。然后给我们输出。
  • 数据究竟来自哪里?
  • 数据来自 HTML 表单上的文本区域,通过 $_REQUEST['description'] (但我已经检查了 $description 的内容包含 UTF8,所以我认为它不可能源头有问题)

标签: php mysql utf-8 pdo


【解决方案1】:
  try {
      $dbh = new PDO(
          'mysql:host='.$server.';dbname='.$database, 
          $user, 
          $password,
          array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'")
      );
      $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  } catch (PDOException $e) {
      print "Error!: " . $e->getMessage() . "<br/>";
      die();
  }

在将数据放入数据库之前不要对数据进行编码,只发送纯原始 utf-8 数据。应该够了。

问候。

【讨论】:

  • 没有骰子。我没有对数据进行任何编码 - 只是从 $_REQUEST 对象中获取(检查它已经按照记录字节的描述进行了 UTF8 编码)并提交给 MySQL。 :(
  • 天才,您的表是 latin1 并且您以 UTF-8 格式向它们写入数据?它应该如何工作?将集合名称更改为 latin1,您的站点也应位于 iso-1 或将 db 更改为 utf-8
  • 首先——那种语气是完全不合适的。其次,仅仅因为某些东西对你来说很明显,并不意味着对其他人来说很明显,这就是为什么这个网站存在的原因。根据您的评论,我假设您说在不同的列中不可能有不同的字符编码?不是明显的或确实必要的限制。
  • dev.mysql.com/doc/refman/5.0/en/charset-column.html 请阅读并指出“如果在没有 COLLATE 的情况下指定了 CHARACTER SET X,则使用字符集 X 及其默认排序规则。”问候。
  • 所以你的意思是——我的数据库没有问题?我在该列上有一个默认的 UTF8 字符集 - 所以它会使用默认的 UTF8 排序规则。更重要的是,我现在尝试更改整个表格的默认字符集,但它仍然不起作用。
【解决方案2】:

对于单词Générik,您的“记录的十六进制字节”是0x47c3a96ec3a972696b。这确实是 UTF-8 编码的。您尝试验证存储数据的客户端几乎可以肯定在获取表格内容之前设置了错误的字符集。

【讨论】:

  • 不 - 我正在检查 MySQL 命令行客户端。如果我使用该客户端设置值,然后再次选择,一切都很好。更何况如果我使用客户端设置值,然后查看我的Web界面,也可以,但是使用PHP设置值,两者都会产生损坏的文本。
  • @MattFellows:对不起,我以为你的意思是那些记录的十六进制字节是存储在表中的......你得到什么 SELECT HEX(description) FROM venues WHERE ... ?
  • 嗯 - 我收回 - 需要更多调查。 HEX(介绍)产量:526F756E64696E67206F6666205361747572646179206E6967687420696E20756E666F726765747461626C65207374796C652C204672656E636820636F6D70616E792047C3A96EC3A972696B20566170657572206272696E67207468656972206E65772073686F772057617465726C69747A20746F207468652048617420466169722E204174204B696E672047656F726765205620506C6179696E67204669656C64732C2042617220456E642E看起来正确编码给我。我将比较每种输入法的 HEX 值 - 一个小时内的第一道光线...谢谢。
  • @MattFellows:正如我所说,您的mysql 客户端几乎可以肯定设置了不正确的连接字符集(因此 it 存储的数据编码不正确,但在检索时使用相同的字符集——例如使用相同的客户端——错误被撤消并且未被注意到)。
  • 谢谢。问题实际上在于我使用 PuTTY 将值输入 MySQL 命令行客户端。我基本上被骗了关于什么是有效的 utf8。切换到我的 Mac 终端,问题更容易解决。因此,虽然从技术上讲,你没有给我答案,但你肯定让我找到了正确的答案。
【解决方案3】:

我遇到了同样的问题,我在this post 的帮助下解决了这个问题。我将完全有效的变音符号输入 DB,但它正在存储垃圾。

我基本上只是在我的连接/初始化密码之后添加了这个:array(PDO::MYSQL_ATTR_INIT_COMMAND =&gt; "SET NAMES 'utf8'"),因此:

$this->db = new PDO($this->dsn, $this->username, $this->password, 
                    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));

【讨论】:

  • 这个答案与特别的问题无关,而且总体上是错误的。字符集必须在 DSN 中设置
  • 你到底在说什么?有用!想查看 (github.com/MAGSHARE/BMLT-Root-Server/blob/master/main_server/…) 代码吗?我会接受“离题”,但我真的很想知道为什么它“一般”是错误的。我会很感激,因为我不喜欢写错误的代码,而且我想正确地做,这正是我来这里的原因。
  • 嗯...刚刚检查过了。 php.net/manual/en/ref.pdo-mysql.connection.php(看第三条评论)。 stackoverflow.com/users/285587/your-common-sense 回来了。这没有帮助。
  • 哦,是的。感谢您删除 Terry Pratchett 参考资料。看,让我们好一点,在这里。我们都是经验丰富的极客,可以提供很多东西,我完全没有兴趣与你竞争。您是拥有 37K 的大人物先生,而我是拥有区区 145 的 Johnny-Come-Lately。我想做的就是成为这个奇妙资源的体面公民,并回馈社会。我的回答完全正确。我的代码用于安装回 5.1,而我发布的代码正是 php.net 所说的。你的“常识”破解不好。这不再是 UseNet。好吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-05
  • 2014-08-11
  • 2015-09-01
  • 2015-09-02
  • 1970-01-01
  • 1970-01-01
  • 2012-07-09
相关资源
最近更新 更多