json_encodeが空の文字列を返す理由


107

3つのネストされた配列を持つ単純なphp構造があります。

私は特定のオブジェクトを使用せず、2つのループがネストされた配列を自分で構築しています。

これは、Jsonに変換する配列のvar_dumpのサンプルです。

array (size=2)
  'tram B' => 
    array (size=2)
      0 => 
        array (size=3)
          'name' => string 'Ile Verte' (length=9)
          'distance' => int 298
          'stationID' => int 762
      1 => 
        array (size=3)
          'name' => string 'La Tronche Hôpital' (length=18)
          'distance' => int 425
          'stationID' => int 771
  16 => 
    array (size=4)
      0 => 
        array (size=3)
          'name' => string 'Bastille' (length=8)
          'distance' => int 531
          'stationID' => int 397
      1 => 
        array (size=3)
          'name' => string 'Xavier Jouvin' (length=13)
          'distance' => int 589
          'stationID' => int 438

別のスクリプトでは、私は同様の構造を持ち、json_encodeうまく機能します。なぜjson_encodeここで動かないのか分かりません。

編集:エンコーディングに問題があるようです。ときにmb_detect_encoding返すASCII、json_encode動作しますが、それはUTF8を返すとき、それはもう動作しません。

Edit2:をjson_last_error()返します。JSON_ERROR_UTF8これは、不正なUTF-8文字がエンコードされている可能性があることを意味します。


PHPのマニュアルにはThis function only works with UTF-8 encoded data.、エンコードに関する問題はないはずです。
MahanGM 2013年

13
文字列を渡す前utf8_encode()に、name配列フィールドで使用してみてくださいjson_encode()
MahanGM 2013年

どうも !私は自分の問題を解決するこの解決策にたどり着きました。
Matthieu Riegler 2013年

ええ、答えを見ました。幸運を。
MahanGM 2013年

3
JSON_PARTIAL_OUTPUT_ON_ERRORオプションを使用して問題を確認します(たとえば、UTF8のフィールドはnullになります)。
Peter Krauss、2016年

回答:


255

さて、2時間掘り進んだ後(編集を参照)

私は以下を見つけました:

  • 私の場合、それはエンコーディングの問題です
  • mb_detect_encoding おそらく不完全な応答を返します。一部の文字列はおそらくUTF-8ではありませんでした
  • utf8_encode()これらの文字列で使用すると問題が解決しましたが、以下の注意を参照

以下は、配列に含まれるすべての文字列を強制的にUTF-8に変換できる再帰関数です。

function utf8ize($d) {
    if (is_array($d)) {
        foreach ($d as $k => $v) {
            $d[$k] = utf8ize($v);
        }
    } else if (is_string ($d)) {
        return utf8_encode($d);
    }
    return $d;
}

次のように使用します。

echo json_encode(utf8ize($data));

注:utf8_encode()は、ドキュメントに従ってISO-8859-1文字列をUTF-8にエンコードします。そのため、入力エンコーディングが不明な場合は、コメントや他のソリューションで指摘されているように、iconv()またはmb_convert_encoding()がより良いオプションになる場合があります。


4
解決策をありがとう...ただし、1つの注意事項:をに変更} else {} else if (is_string ($d)) {ます。それ以外の場合は、すべてを文字列に変更します(たとえば、INTになりますSTRING)。
Paul Peelen、2014年

3
あなたは私の命を救った。この機能が見つかるまで全てを終わらせようとしていた!! ありがとうございました。
silversunhunter

2
WTF!ソリューションを共有していただきありがとうございます。これを理解するには多くの掘り下げが必要だったと思います。それを実行して共有してくれたことに感謝します。
クリス

1
3日間のデバッグの後、今すぐあなたにキスをすることができました。
AJB 2016

2
データベースから読み取る場合は、$ conn-> set_charset( "utf8");を使用します。
Andrew Briggs

36

Matthieu Rieglerは本当に良い解決策を提示しましたが、オブジェクトを処理するために少し修正する必要もありました:

function utf8ize($d) {
    if (is_array($d)) 
        foreach ($d as $k => $v) 
            $d[$k] = utf8ize($v);

     else if(is_object($d))
        foreach ($d as $k => $v) 
            $d->$k = utf8ize($v);

     else 
        return utf8_encode($d);

    return $d;
}

もう1つの注意:json_last_error()は、json_encode()/ json_encode()関数のデバッグに役立つ場合があります。


elseif代わりにすべきではないelse ifですか?(つまり、空白なし)。
Uwe Keim 2016年

2
PHPのドキュメントによると、@ UweKeimは「elseifとelse ifは中かっこを使用した場合にのみまったく同じと見なされる」ということです。つまり、コロン表記を使用しない限り、それらは同等です。例if(): elseif:
Adam Bubela

1
よくやった。PHPはゴミであり、あなたが好きな人はゴミを捨てないでください。
ロニーベスト

あなたは挿入する必要がありelse if(is_int($d)||is_bool($d)) return $d;:ための、最後の、他の前に{"success":true, "message":"Ⲃⲟⲟ𝓵ⲉⲁⲛ ⲁⲛⲇ Ⲓⲛϯⲉ𝓰ⲉꞅ𝛓"}
デイヴィッドRefoua

ちょうど@ paul-peelenが@ matthieu-rieglerにすすめるように:最後のelseelse if(is_string ($d)); それ以外の場合は、すべてを文字列に変更します(たとえば、INTになりますSTRING)。
Bruno Serrano 2017

30

私にとって、この問題の答えcharset=utf8は私のPDO接続での設定でした。

$dbo = new PDO('mysql:host=localhost;dbname=yourdb;charset=utf8', $username, $password);

2
またはmysqli関数で:mysqli_set_charset($ connection、 "utf8");
user18099 2017年

これが私の解決策のヒントでした。msqli接続の少し異なる原因。$mysqli->set_charset("utf8");データベースの処理を行った後に呼び出すだけです。
MaggusK 2018年

utf8mb4最近のMySQLバージョンで使用してください。utf8廃止されました。
ダーマン

10

Adam Bubelaも私の問題を解決してくれた本当に良い解決策を提示してくれました、そしてここに簡略化された関数があります:

function utf8ize($d)
{ 
    if (is_array($d) || is_object($d))
        foreach ($d as &$v) $v = utf8ize($v);
    else
        return utf8_encode($d);

    return $d;
}

1
キーが保存されるので、これが好きです。
dev0

7

PHP 5.6でもまったく同じ問題があります。私はWindows 7でOpen Server + Nginx を使用しています。すべての文字セットはUTF-8に設定されています。理論的には、公式ドキュメントによると、フラグ

JSON_UNESCAPED_UNICODE

これを解決する必要があります。残念ながら、これは私のケースではありません。何故かはわからない。上記のすべてのスニペットは私の問題を解決しないので、私は自分の実装を見つけました。私はそれが誰かを助けることができると信じています。少なくとも、ロシアの手紙はテストに合格しています。

function utf8ize($d) {
    if (is_array($d) || is_object($d)) {
        foreach ($d as &$v) $v = utf8ize($v);
    } else {
        $enc   = mb_detect_encoding($d);

        $value = iconv($enc, 'UTF-8', $d);
        return $value;
    }

    return $d;
}

4

この受け入れられた答えは機能します。しかし、MySQLからデータを取得している場合(私がそうであったように)より簡単な方法があります。

データベースを開いたら、クエリを実行する前に、mysqliを使用して次のように文字セットを設定できます。

/* change character set to utf8 | Procedural*/
if (!mysqli_set_charset($link, "utf8")) {
    printf("Error loading character set utf8: %s\n", mysqli_error($link));
    exit();
}

または

/* change character set to utf8 | Object Oriented*/
if (!$mysqli->set_charset("utf8")) {
        printf("Error loading character set utf8: %s\n", $mysqli->error);
        exit();
 }

リンク:http : //php.net/manual/en/mysqli.set-charset.php


4

古いバージョンのPHP(5.2)を実行しているサーバーでこの問題に遭遇しました。私はJSON_FORCE_OBJECTフラグを使用していましたが、どうやらこれは5.3までサポートされていません

そのフラグを使用している場合は、バージョンを確認してください。

回避策は、エンコードする前にオブジェクトにキャストするだけのようです:

json_encode((object)$myvar);

3

の返品mb_detect_encodingが正しくない可能性があります:

$data = iconv('UTF-8', 'ISO-8859-1', 'La Tronche Hôpital');
var_dump(
    mb_detect_encoding($data),
    mb_detect_encoding($data, array('ISO-8859-1', 'UTF-8'))
);

デフォルトの検出順序に応じて、上記は異なる結果を返す可能性があるため、エンコーディングは誤ってUTF-8として報告されます。(これはより大きな例です。)

データがUTF-8としてエンコードされていない可能性が高いため、json_encodeが返されfalseます。JSONエンコードの前に、文字列をUTF-8に変換することを確認する必要があります。

$fromEncoding = 'ISO-8859-1'; // This depends on the data

array_walk_recursive($array, function (&$value, $key, $fromEncoding) {
    if (is_string($value)) {
        $value = iconv($fromEncoding, 'UTF-8', $value);
    }
}, $fromEncoding);

3

ob_get_clean()からデータを取得していて、同じ問題がありましたが、上記の解決策ではうまくいきません。私の場合、解決策はこれでした、おそらくそれは誰かを助けるでしょう。

$var = mb_convert_encoding($var, 'UTF-8');

2

これらの文字列でutf8_encode()を使用すると、問題が解決しました。


1

Adam Bubelaの答えを改善しました。ブロックが{と}で閉じられていないときは、私はそれを嫌います。それはよりきれいで、あなたはバグを導入しないか、多分それは私が過去にPerlを使用したことです:)

<?php

class App_Updater_String_Util {    
    /**
     * Usage: App_Updater_String_Util::utf8_encode( $data );
     *
     * @param mixed $d
     * @return mixed
     * @see http://stackoverflow.com/questions/19361282/why-would-json-encode-returns-an-empty-string
     */
    public static function utf8_encode($d) {
        if (is_array($d)) {
            foreach ($d as $k => $v) {
                $d[$k] = self::utf8_encode($v);
            }
        } elseif (is_object($d)) {
            foreach ($d as $k => $v) {
                $d->$k = self::utf8_encode($v);
            }
        } elseif (is_scalar($d)) {
            $d = utf8_encode($d);
        }

        return $d;
    }
}

?>

0

このデータをデータベースから取得する場合は、データベースmysqli_set_charset($connection, "utf8");からパラメータを取得するときに接続で使用 します


0

この問題は時々発生します-ヘッダーのアクセス制御を通過していません。

私の場合、json_encodeの前にエコーが追加された場合。結果が表示されていなかった場合は、空白のページが表示されていました。

追加した

header('Access-Control-Allow-Origin: *'); 

そして私の問題は解決しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.