web-dev-qa-db-ja.com

UTF-8文字エンコーディングの戦いjson_encode()

クエスト

アクセント付き文字を含む行をフェッチしようとしています。列(NAME)のエンコーディングは_latin1_swedish_ci_です。

コード

次のクエリは、phpMyAdminを使用して_Abord â Plouffe_を返します。

_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 )と呼ばれます):

_  while( $row = mysql_fetch_assoc( $result ) ) {
    foreach( $row as $value ) {
      echo $value . " ";
      $value = utf8_encode( $value );
      echo $value . " ";
    }

    $r[] = $row;
  }
_

表示される値:_5482 5482 Abord â Plouffe Abord â Plouffe_

次に、配列は_json_encode_を使用してエンコードされます。

_$rows = db_fetch_all( $result );
echo json_encode( $rows );
_

問題

Webブラウザーは次の値を受け取ります。

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

の代わりに:

_{"ID":"5482","NAME":"Abord â Plouffe"}
_

(またはエンコードされた同等のもの。)

質問

ドキュメントには、json_encode()がUTF-8で機能することが記載されています。 LATIN1からUTF-8にエンコードされている値を確認できます。ただし、json_encode()の呼び出し後、値はnullになります。

json_encode()でUTF-8値を適切にエンコードするにはどうすればよいですか?

可能な解決策の1つは Zend Framework を使用することですが、回避できればいいのではないでしょうか。

30
Dave Jarvis
// 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);
38
Kemo
foreach( $row as $value ) {
  $value = utf8_encode( $value );

エンコードされた値を実際に$row配列に書き戻すのではなく、ローカル変数$valueを変更するだけです。変数を変更したときに書き戻したい場合は、参照として扱う必要があります。

foreach( $row as &$value ) {

個人的には、可能な限り参照を避けようとしますが、この場合は、代わりにKemoが投稿したarray_mapを使用します。

または、アプリをUTF-8に移行するための最初のステップとして、mysql_set_charsetをUTF-8に変換して、実際のテーブル照合に関係なく、UTF-8で戻り値を取得します。

11
bobince

私の解決策は、SELECTの前にこの行mysql_query('SET CHARACTER SET utf8');を挿入することです。この方法は良いです。

5
jailsonjan

それをクエリに置くのではなく、次のように置くべきです:

mysql_set_charset('utf8');

mysql connectステートメントの後。

4
Robert Imhoff

接続:mysql_set_charset('utf8', $link);

例:

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

それが多少役立つことを願っています。

1
alditis

結果をiconv_r($row,"LATIN1","UTF-8//TRANSLIT");する前にjson_encode()(以下の関数)を試してください。

テーブルエンコーディングと結果セットエンコーディングとしてUTF-8を使用していますが、フォームを介してUTF-8以外の文字を送信することもでき、すべての入力ソースを追跡するのが面倒なので、json_encode()より安全にするため。特に、英国の人々がとても気に入っているように見える度合記号と「スマートクオート」を含むNULL文字列を私はそれに持っていました。

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);
         }
      }
   }
}
0
Wil