web-dev-qa-db-ja.com

PHP json_decodeのJSON_ERROR_UTF8エラーを解決するにはどうすればよいですか?

私はこのコードを試しています

$json = file_get_contents("http://www.google.com/alerts/preview?q=test&t=7&f=1&l=0&e");
print_r(json_decode(utf8_encode($json), true));

        //////////////

// Define the errors.
$constants = get_defined_constants(true);
$json_errors = array();
foreach ($constants["json"] as $name => $value) {
    if (!strncmp($name, "JSON_ERROR_", 11)) {
        $json_errors[$value] = $name;
    }
}

// Show the errors for different depths.
foreach (range(4, 3, -1) as $depth) {
    var_dump(json_decode($json, true, $depth));
    echo 'Last error: ', $json_errors[json_last_error()], PHP_EOL, PHP_EOL;
}

Html_entities_decode、utf8_encode、decode、hexコードのデコードなど、多くの機能を試しましたが、常にエラー「JSON_ERROR_UTF8」が発生します。

これをどのように解決できますか?

47
James Harzs

良い機能があります 配列をサニタイズします。

次のようなjson_encodeラッパーを使用することをお勧めします。

function safe_json_encode($value, $options = 0, $depth = 512, $utfErrorFlag = false) {
    $encoded = json_encode($value, $options, $depth);
    switch (json_last_error()) {
        case JSON_ERROR_NONE:
            return $encoded;
        case JSON_ERROR_DEPTH:
            return 'Maximum stack depth exceeded'; // or trigger_error() or throw new Exception()
        case JSON_ERROR_STATE_MISMATCH:
            return 'Underflow or the modes mismatch'; // or trigger_error() or throw new Exception()
        case JSON_ERROR_CTRL_CHAR:
            return 'Unexpected control character found';
        case JSON_ERROR_SYNTAX:
            return 'Syntax error, malformed JSON'; // or trigger_error() or throw new Exception()
        case JSON_ERROR_UTF8:
            $clean = utf8ize($value);
            if ($utfErrorFlag) {
                return 'UTF8 encoding error'; // or trigger_error() or throw new Exception()
            }
            return safe_json_encode($clean, $options, $depth, true);
        default:
            return 'Unknown error'; // or trigger_error() or throw new Exception()

    }
}

function utf8ize($mixed) {
    if (is_array($mixed)) {
        foreach ($mixed as $key => $value) {
            $mixed[$key] = utf8ize($value);
        }
    } else if (is_string ($mixed)) {
        return utf8_encode($mixed);
    }
    return $mixed;
}

私のアプリケーションでは、utf8_encode()はiconv()よりもうまく動作します

72
Konstantin

簡単なコード行が必要です。

$input = iconv('UTF-8', 'UTF-8//IGNORE', utf8_encode($input));
$json = json_decode($input);

クレジット:Sang Le、私のチームメイトがこのコードをくれました。うん!

54
Andy Truong

入力が有効であることを保証できない限り、iconv関数はほとんど役に立ちません。代わりにmb_convert_encodingを使用してください。

mb_convert_encoding($value, "UTF-8", "auto");

「auto」よりも明示的になり、予想される入力エンコーディングのコンマ区切りリストを指定することもできます。

最も重要なのは、無効な文字が処理され、文字列全体が破棄されることはありません(iconvとは異なります)。

11
Rich Remer

PHPでのJSONのデコードJSONのデコードは、エンコードと同じくらい簡単です。 PHPは、すべてを処理する便利なjson_decode関数を提供します。有効なJSON文字列をメソッドに渡すだけで、stdClass型のオブジェクトを取得できます。以下に簡単な例を示します。

<?php
$string = '{"foo": "bar", "cool": "attr"}';
$result = json_decode($string);

// Result: object(stdClass)#1 (2) { ["foo"]=> string(3) "bar" ["cool"]=> string(4) "attr" }
var_dump($result);

// Prints "bar"
echo $result->foo;

// Prints "attr"
echo $result->cool;
?>

代わりに連想配列を取得する場合は、2番目のパラメーターをtrueに設定します。

<?php
$string = '{"foo": "bar", "cool": "attr"}';
$result = json_decode($string, true);

// Result: array(2) { ["foo"]=> string(3) "bar" ["cool"]=> string(4) "attr" }
var_dump($result);

// Prints "bar"
echo $result['foo'];

// Prints "attr"
echo $result['cool'];
?>

非常に大きなネストされたJSONドキュメントが必要な場合は、再帰の深さを特定のレベルに制限できます。ドキュメントが指定された深さよりも深い場合、関数はnullを返し、解析を停止します。

<?php
$string = '{"foo": {"bar": {"cool": "value"}}}';
$result = json_decode($string, true, 2);

// Result: null
var_dump($result);
?>

最後の引数はjson_encodeと同じように機能しますが、現在サポートされているビットマスクは1つだけです(これにより、bigintsを文字列に変換でき、PHP 5.4以上)からのみ使用できます)。これまでは有効なJSON文字列を使用していました(ヌル深度エラーは別として)。次のパートでは、エラーの処理方法を示します。

エラー処理とテストJSON値を解析できなかった場合、または指定された(またはデフォルトの)深さよりも深いネストレベルが見つかった場合、NULLが返されますjson_decodeから。これは、json_encode/json_deocdeによって直接例外が発生しないことを意味します。

では、どのようにしてエラーの原因を特定できますか?ここでjson_last_error関数が役立ちます。 json_last_errorは、次の定数(ここから取得)のいずれかである整数エラーコードを返します。

JSON_ERROR_NONE:エラーは発生していません。 JSON_ERROR_DEPTH:最大スタック深度を超えました。 JSON_ERROR_STATE_MISMATCH:無効または不正なJSON。 JSON_ERROR_CTRL_CHAR:制御文字エラー。おそらく正しくエンコードされていません。 JSON_ERROR_SYNTAX:構文エラー。 JSON_ERROR_UTF8:誤ってエンコードされた可能性のある不正なUTF-8文字(PHP 5.3.3)以降。これらの情報が手元にある場合、エラー時に記述的な例外を発生させる簡単な解析ヘルパーメソッドを記述できます。見つかった。

<?php
class JsonHandler {

    protected static $_messages = array(
        JSON_ERROR_NONE => 'No error has occurred',
        JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded',
        JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
        JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
        JSON_ERROR_SYNTAX => 'Syntax error',
        JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
    );

    public static function encode($value, $options = 0) {
        $result = json_encode($value, $options);

        if($result)  {
            return $result;
        }

        throw new RuntimeException(static::$_messages[json_last_error()]);
    }

    public static function decode($json, $assoc = false) {
        $result = json_decode($json, $assoc);

        if($result) {
            return $result;
        }

        throw new RuntimeException(static::$_messages[json_last_error()]);
    }

}
?>

例外処理に関する最後の投稿の例外テスト機能を使用して、例外が正しく機能するかどうかをテストできます。

// Returns "Correctly thrown"
assertException("Syntax error", function() {
    $string = '{"foo": {"bar": {"cool": NONUMBER}}}';
    $result = JsonHandler::decode($string);
});

PHP 5.3.3であるため、文字列に無効なUTF-8文字が見つかった場合、JSON_ERROR_UTF8エラーが返されます。これは、UTF-8と異なる文字セットが入力文字列が制御下にない場合、utf8_encode関数を使用してutf8に変換できます。

<?php echo utf8_encode(json_encode($payload)); ?>

過去にこれを使用して、UTF-8を使用しないレガシーMSSQLデータベースからロードされたデータを変換しました。

ソース

0
Muhammad Tahir