关于php:UTF-8字符编码与jason_encode()

UTF-8 character encoding battles json_encode()

本问题已经有最佳答案,请猛点这里访问。

探索

我在找有重音字符的行。列(NAME的编码是latin1_swedish_ci的编码。

代码

下面的查询使用phpmyadmin返回Abord a Plouffe

1
2
3
SELECT C.NAME FROM CITY C
WHERE C.REGION_ID=10 AND C.NAME_LOWERCASE LIKE '%abor%'
ORDER BY C.NAME LIMIT 30

下面显示期望值(函数称为db_fetch_all( $result )

1
2
3
4
5
6
7
8
9
  while( $row = mysql_fetch_assoc( $result ) ) {
    foreach( $row as $value ) {
      echo $value ."";
      $value = utf8_encode( $value );
      echo $value ."";
    }

    $r[] = $row;
  }

显示值:5482 5482 Abord a Plouffe Abord ?¢ Plouffe

然后使用json_encode对数组进行编码:

1
2
$rows = db_fetch_all( $result );
echo json_encode( $rows );

问题

Web浏览器接收以下值:

1
{"ID":"5482","NAME":null}

而不是:

1
{"ID":"5482","NAME":"Abord a Plouffe"}

(或编码的等价物。)

问题

文件指出,json_encode()在utf-8上工作。我可以看到从Latin1到UTF-8的编码值。但是,在调用json_encode()之后,该值变为null

如何使json_encode()正确编码utf-8值?

一种可能的解决方案是使用Zend框架,但是如果可以避免的话,我宁愿不使用它。


1
2
3
4
5
6
7
8
9
10
// Create an empty array for the encoded resultset
$rows = array();

// Loop over the db resultset and put encoded values into $rows
while($row = mysql_fetch_assoc($result)) {
  $rows[] = array_map('utf8_encode', $row);
}

// Output $rows
echo json_encode($rows);

1
2
foreach( $row as $value ) {
  $value = utf8_encode( $value );

实际上,您并没有将编码后的值写回其中的$row数组中,而是只更改了局部变量$value。如果要在更改变量时写回,则需要将其视为引用:

1
foreach( $row as &$value ) {

就我个人而言,我会尽量避免引用,在这种情况下,使用Kemo发布的array_map

或者mysql_set_charset到utf-8,以获取utf-8格式的返回值,而不管实际的表排序是什么,这是将应用程序迁移到utf-8的第一步。


我的解决方案是在SELECT之前插入这行mysql_query('SET CHARACTER SET utf8');。这个方法很好。


似乎人们不应该把它放在查询中,而是应该放在:

在mysql connect语句之后。


在你的连接中:mysql_set_charset('utf8', $link);

例子:

1
2
3
4
5
<?php
$link = mysql_connect('localhost', 'your_user', 'your_password');
mysql_set_charset('utf8', $link);
$db_selected = mysql_select_db('your_db', $link);
...

希望能有所帮助。


在你得到你的结果之前,试一下iconv_r($row,"LATIN1","UTF-8//TRANSLIT");(下面的函数)。

我有utf-8作为表编码和结果集编码,但有时人们仍然设法通过表单提交非utf-8字符,跟踪每个输入源很麻烦,所以我也包装了json_encode(),以使其更安全。尤其是,我身上有一个空字符串,包含学位符号和"聪明的引号",英国人似乎很喜欢。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function safe_json_encode($mixed,$missing="TRANSLIT"){
   $out=json_encode($mixed);
   if ($err=  json_last_error()){
      iconv_r("UTF-8","UTF-8//$missing",$mixed);
      $out=json_encode($mixed);
   }
   return $out;
}
function iconv_r($charset_i, $charset_o, &$mixed) {
   if (is_string($mixed)) {
      $mixed = iconv($charset_i, $charset_o, $mixed);
   } else {
      if (is_object($mixed)){
         $mixed = (array) $mixed;
      }
      if (is_array($mixed)){
         foreach ($mixed as $key => &$value) {
            iconv_r($charset_i, $charset_o, $value);
         }
      }
   }
}