Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】JSON_INVALID_UTF8_SUBSTITUTE定数の使い方

JSON_INVALID_UTF8_SUBSTITUTE定数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

JSON_INVALID_UTF8_SUBSTITUTE定数は、PHPのJSON拡張機能で使用されるオプションの一つを表す定数です。この定数は、JSON形式のデータをエンコードまたはデコードする際に、入力データに含まれる無効なUTF-8バイトシーケンスを、安全な代替文字に置き換えるための振る舞いを指示します。

UTF-8は、様々な言語の文字をコンピュータで表現するための国際的な文字エンコーディング方式です。しかし、データが破損していたり、不正な処理を受けていたりすると、このUTF-8のルールに沿わない「無効なUTF-8バイトシーケンス」がデータ中に混入することがあります。

通常、json_encode()json_decode()といったJSON処理関数は、このような無効なUTF-8シーケンスを検出した場合、エラーとして処理を中断したり、nullを返したりすることがあります。これは、プログラムが予期せぬエラーで停止する原因となりえます。

JSON_INVALID_UTF8_SUBSTITUTE定数をオプションとして指定すると、JSON処理関数は無効なUTF-8シーケンスを見つけた際に、エラーで処理を中断する代わりに、それをUnicodeの「U+FFFD(�)」という代替文字に自動的に置き換えます。この動作により、一部のデータに問題があったとしても、JSONデータの変換処理全体を継続できるようになります。

特に、外部システムから取得した信頼性の低いデータや、文字エンコーディングが不完全なデータを取り扱う際に、この定数を使用することで予期せぬエラーを防ぎ、アプリケーションの堅牢性を高めることが可能です。無効な文字が含まれていても処理が停止することなく、安全にデータ変換を進めることができるため、安定したシステム開発に貢献します。

構文(syntax)

1<?php
2$data = ['key' => 'value'];
3$json = json_encode($data, JSON_INVALID_UTF8_SUBSTITUTE);
4?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

戻り値なし

戻り値はありません

サンプルコード

PHPでJSON無効UTF-8を置換デコードする

1<?php
2
3/**
4 * 無効なUTF-8バイトシーケンスを含むJSON文字列のデコードを試み、
5 * JSON_INVALID_UTF8_SUBSTITUTE フラグの効果を示します。
6 *
7 * このフラグは、json_decode が入力文字列内で無効なUTF-8シーケンスを検出した場合、
8 * それらを U+FFFD (REPLACEMENT CHARACTER) に置換し、デコード処理を継続させます。
9 * 通常、無効なUTF-8シーケンスがあると json_decode はエラーとなり null を返します。
10 */
11function demonstrateJsonInvalidUtf8Substitute(): void
12{
13    // 無効なUTF-8バイトシーケンスを含むJSON文字列をバイナリ形式で作成します。
14    // 例: {"message":"Hello \xc0 World"}
15    // ここで \xc0 は単独では無効なUTF-8バイトシーケンスです。
16    // PHPの文字列リテラルで直接不正なバイトを表現すると、PHP内部で処理される可能性があるため、
17    // `pack()` を使用してバイト列を明示的に作成します。
18    $invalidUtf8Json = pack('C*',
19        0x7b, 0x22, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x3a, 0x22,
20        0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, // "Hello "
21        0xc0, // 無効なUTF-8バイト
22        0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x22, 0x7d // " World"}
23    );
24
25    echo "--- JSON_INVALID_UTF8_SUBSTITUTE を使用しない場合 ---\n";
26
27    // フラグなしでデコードを試みる
28    $decodedWithoutSubstitute = json_decode($invalidUtf8Json);
29    $errorWithoutSubstitute = json_last_error();
30    $errorMessageWithoutSubstitute = json_last_error_msg();
31
32    if ($errorWithoutSubstitute !== JSON_ERROR_NONE) {
33        echo "デコードエラー ({$errorWithoutSubstitute}): {$errorMessageWithoutSubstitute}\n";
34        echo "デコード結果 (通常 null): ";
35        var_dump($decodedWithoutSubstitute);
36    } else {
37        echo "デコード成功:\n";
38        var_dump($decodedWithoutSubstitute);
39    }
40
41    echo "\n--- JSON_INVALID_UTF8_SUBSTITUTE を使用する場合 ---\n";
42
43    // JSON_INVALID_UTF8_SUBSTITUTE フラグを指定してデコードを試みる
44    // このフラグにより、無効なUTF-8シーケンスはU+FFFD (置換文字) に置き換えられます。
45    $decodedWithSubstitute = json_decode($invalidUtf8Json, false, 512, JSON_INVALID_UTF8_SUBSTITUTE);
46    $errorWithSubstitute = json_last_error();
47    $errorMessageWithSubstitute = json_last_error_msg();
48
49    if ($errorWithSubstitute !== JSON_ERROR_NONE) {
50        // このフラグを使っても、他のJSON構文エラーや非常に深刻なUTF-8エラーは発生する可能性があります。
51        echo "デコードエラー ({$errorWithSubstitute}): {$errorMessageWithSubstitute}\n";
52        echo "デコード結果: ";
53        var_dump($decodedWithSubstitute);
54    } else {
55        echo "デコード成功:\n";
56        var_dump($decodedWithSubstitute);
57        // デコードされた文字列の内容を確認
58        if (isset($decodedWithSubstitute->message)) {
59            echo "デコードされたメッセージ: \"" . $decodedWithSubstitute->message . "\"\n";
60            echo "(無効なUTF-8バイトは置換文字 '�' (U+FFFD) に置き換えられました)\n";
61        }
62    }
63
64    echo "\n--- 比較のために有効なUTF-8 JSON の例 ---\n";
65    $validUtf8Json = '{"message":"これは有効なUTF-8文字列です。😊"}';
66    $decodedValidData = json_decode($validUtf8Json);
67    echo "デコード成功:\n";
68    var_dump($decodedValidData);
69}
70
71// 関数を実行してデモンストレーションを開始
72demonstrateJsonInvalidUtf8Substitute();
73

JSON_INVALID_UTF8_SUBSTITUTEは、PHP 8で導入された定数で、json_decode関数がJSON文字列を解析する際の挙動を制御するために使用されます。この定数自体に引数や戻り値は存在しません。

通常、json_decode関数は、入力されたJSON文字列内にPHPの標準的なUTF-8として認識できない不正なバイトシーケンス(無効なUTF-8データ)を検出すると、JSON_ERROR_UTF8というエラーを発生させ、デコード処理を中断してnullを返します。

しかし、json_decode関数のオプションとしてJSON_INVALID_UTF8_SUBSTITUTE定数を指定すると、この挙動が変更されます。具体的には、不正なUTF-8バイトシーケンスが検出されてもエラーで中断せず、それらのバイトをU+FFFD(REPLACEMENT CHARACTER、通常は「�」と表示される特殊な文字)に置き換えて、デコード処理を続行させます。

サンプルコードでは、pack関数を用いて意図的に無効なUTF-8バイトシーケンスを含むJSON文字列を作成し、この定数の効果を実演しています。定数を使用しない場合はデコードエラーとなりnullが返されますが、定数を指定してデコードすると、無効なバイトが置換文字に変換され、JSONデータとして適切にデコードが成功することを示しています。これにより、部分的に破損したUTF-8データを含むJSONでも、可能な限り情報を取得して処理を継続することが可能になります。

PHP 8で追加されたJSON_INVALID_UTF8_SUBSTITUTEは、json_decodeがJSON文字列内の不正なUTF-8バイトシーケンスを検出した際に、エラーで処理を中断せずにU+FFFD(置換文字 '�')へ自動変換してデコードを続行させるためのフラグです。このフラグを指定しない場合、不正なUTF-8シーケンスが含まれるとjson_decodeはエラーとなり、通常nullを返します。外部からの入力など、完全にUTF-8が保証できないJSONデータを処理する際に、デコード失敗を防ぎたい場合に便利です。ただし、不正な文字が置換されることで、データの内容が元の意図と異なる可能性があるため注意が必要です。デコード後には必ずjson_last_error()json_last_error_msg()を使って、エラーが発生していないか確認するようにしましょう。

PHPでJSON無効UTF-8置換する

1<?php
2
3/**
4 * JSON_INVALID_UTF8_SUBSTITUTE オプションの動作を示すサンプル関数。
5 *
6 * この関数は、無効なUTF-8シーケンスを含む文字列がjson_encode()によって
7 * どのように処理されるかを示します。JSON_INVALID_UTF8_SUBSTITUTE オプションを
8 * 使用することで、無効なUTF-8シーケンスがエラーを発生させることなく
9 * U+FFFD (REPLACEMENT CHARACTER, '�') に置換され、処理が続行されます。
10 */
11function demonstrateJsonInvalidUtf8Substitute(): void
12{
13    // PHPで無効なUTF-8シーケンスを含む文字列を定義します。
14    // 例: バイトシーケンス 0xC3 0x28 は有効なUTF-8ではありません。
15    // (UTF-8のルールでは、0xC3の後に続くバイトは0x80から0xBFの範囲でなければなりません)
16    $invalidUtf8String = "Hello\xC3\x28World!";
17
18    echo "--- 1. JSON_INVALID_UTF8_SUBSTITUTE オプションなしの場合 ---" . PHP_EOL;
19    // オプションなしで json_encode() を実行します。
20    // デフォルトでは、無効なUTF-8シーケンスが見つかるとエラーとなり、falseを返します。
21    $encodedWithoutOption = json_encode($invalidUtf8String);
22
23    if (json_last_error() !== JSON_ERROR_NONE) {
24        echo "エラー発生: " . json_last_error_msg() . PHP_EOL;
25        echo "json_encode() の戻り値: " . var_export($encodedWithoutOption, true) . PHP_EOL;
26    } else {
27        echo "成功 (この文字列では通常エラーになりますが、環境によっては異なる場合もあります): " . $encodedWithoutOption . PHP_EOL;
28    }
29    echo PHP_EOL;
30
31    echo "--- 2. JSON_INVALID_UTF8_SUBSTITUTE オプションを使用した場合 ---" . PHP_EOL;
32    // JSON_INVALID_UTF8_SUBSTITUTE オプションを指定して json_encode() を実行します。
33    // このオプションは、無効なUTF-8シーケンスをU+FFFD (REPLACEMENT CHARACTER, '�') に置換します。
34    $encodedWithOption = json_encode($invalidUtf8String, JSON_INVALID_UTF8_SUBSTITUTE);
35
36    if (json_last_error() !== JSON_ERROR_NONE) {
37        echo "エラー発生: " . json_last_error_msg() . PHP_EOL;
38        echo "json_encode() の戻り値: " . var_export($encodedWithOption, true) . PHP_EOL;
39    } else {
40        echo "成功: " . $encodedWithOption . PHP_EOL;
41        echo "  - 無効な文字が '�' (U+FFFD REPLACEMENT CHARACTER) に置換されました。" . PHP_EOL;
42    }
43    echo PHP_EOL;
44}
45
46// 関数を実行し、JSON_INVALID_UTF8_SUBSTITUTE オプションの動作を確認します。
47demonstrateJsonInvalidUtf8Substitute();

PHP 8におけるJSON_INVALID_UTF8_SUBSTITUTEは、JSON拡張機能で利用される定数の一つです。この定数自体は引数や戻り値を持ちませんが、json_encode()関数などのオプションとして使用することで、関数の挙動を制御します。

具体的には、json_encode()関数がPHPのデータをJSON形式の文字列に変換する際、入力された文字列内に無効なUTF-8シーケンス(文字コードの誤り)が含まれていた場合の処理方法を定義します。通常、json_encode()は無効なUTF-8シーケンスを検出するとエラーを発生させ、結果としてfalseを返したり、正しくJSONを生成できなかったりします。

しかし、json_encode()の第二引数にJSON_INVALID_UTF8_SUBSTITUTEオプションを指定すると、無効なUTF-8シーケンスが見つかってもエラーで処理を中断する代わりに、その部分をU+FFFD (REPLACEMENT CHARACTER) という「�」のような代替文字に自動的に置き換えて、処理を続行します。これにより、データに多少の文字コードの問題があっても、完全に変換を失敗させることなくJSON文字列を生成できるようになります。

サンプルコードでは、まず無効なUTF-8シーケンスを含む文字列を準備し、このオプションなしでjson_encode()を実行した場合にエラーが発生することを示しています。次に、JSON_INVALID_UTF8_SUBSTITUTEオプションを指定して実行すると、エラーにならずに不正な部分が「�」に置き換わったJSON文字列が正常に生成される様子が確認できます。この定数は、文字コードの問題に柔軟に対応し、より堅牢なデータ処理を実現するために役立ちます。

このオプションは、JSON変換の際に不正なUTF-8文字が検出された場合の挙動を制御します。通常、json_encode()は無効なUTF-8シーケンスを含む文字列を変換しようとするとエラーとなり、処理が失敗します。JSON_INVALID_UTF8_SUBSTITUTEを指定すると、エラーで処理を中断せず、無効なUTF-8文字を「�」(U+FFFD)に自動置換してJSON変換を続行します。これによりエラーは回避されますが、データが変更されるため、元の情報が失われる可能性があります。データの正確性が求められる場面では、まず入力データの文字エンコーディングが正しいUTF-8であるかを確認し、修正することが重要です。このオプションは一時的な回避策として利用し、根本的な原因究明と対応を心がけてください。

関連コンテンツ

関連IT用語

関連プログラミング言語