【PHP8.x】unserialize関数の使い方

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

作成日: 更新日:

基本的な使い方

unserialize関数は、シリアライズされた文字列をPHPの値に戻す関数です。シリアライズとは、変数やオブジェクトを文字列形式に変換する処理であり、unserialize関数はその逆の操作を行います。この関数を用いることで、ファイルやデータベースに保存されたシリアライズされたデータを、元のPHPの変数やオブジェクトとして復元することができます。

unserialize関数は、シリアライズされた文字列を引数として受け取り、復元された値を返します。復元された値は、元の変数の型(文字列、整数、配列、オブジェクトなど)を保持しています。もしシリアライズされた文字列が不正な形式であった場合、unserialize関数はfalseを返します。また、オブジェクトのunserialize中にクラスが定義されていない場合、__PHP_Incomplete_Classオブジェクトが生成されます。

unserialize関数を使用する際には、セキュリティ上の注意が必要です。特に、信頼できないソースからのシリアライズされたデータをunserializeすると、意図しないコードが実行される可能性があります。これは、オブジェクトのunserialize時にマジックメソッド(__wakeup()など)が自動的に実行されるためです。したがって、unserializeするデータは信頼できるソースからのものに限るか、unserializeの前に厳密な検証を行うことが推奨されます。PHP 7.0以降では、unserialize()の第2引数にオプションとして許可するクラスの配列を渡すことで、特定のクラスのみunserializeを許可する機能が追加されました。この機能を利用することで、セキュリティリスクを軽減することができます。

構文(syntax)

1unserialize(string $data, array $options = []): mixed

引数(parameters)

string $data, array $options = []

  • string $data: シリアライズされたデータ文字列
  • array $options = []: デシリアライズの挙動を制御するオプションの配列

戻り値(return)

mixed

unserialize関数は、PHPのシリアライズ(serialize)関数によって生成された文字列を、元のPHPの値(文字列、数値、配列、オブジェクトなど)に復元して返します。復元に失敗した場合はFALSEを返します。

サンプルコード

PHP unserialize エラーハンドリングと復元

1<?php
2
3/**
4 * unserialize 関数を使用してデータを復元し、エラーハンドリングをデモンストレーションします。
5 *
6 * PHP 8 環境では、不正なシリアライズデータが入力された場合、unserialize は false を返し、
7 * E_NOTICE (または E_WARNING) が発生することがあります。
8 * したがって、関数の戻り値を適切にチェックし、エラー発生時に対処することが重要です。
9 *
10 * @param string $serializedData unserializeする文字列
11 * @return mixed unserializeされたデータ、またはエラーを通知する文字列
12 */
13function safeUnserialize(string $serializedData): mixed
14{
15    // @演算子を使用して、unserializeが発行する可能性のあるE_NOTICEやE_WARNINGを抑制します。
16    // その後、戻り値のfalseをチェックしてエラーを判定します。
17    $unserializedResult = @unserialize($serializedData);
18
19    // unserialize が false を返した場合にエラーと判定します。
20    // ただし、boolean型の false をシリアライズした 'b:0;' は正常な値なので、この場合はエラーとみなしません。
21    if ($unserializedResult === false && $serializedData !== 'b:0;') {
22        // エラー発生時の処理 (例: ログへの記録、ユーザーへの通知)
23        error_log("Unserialize error: Malformed or invalid data encountered. Input: " . substr($serializedData, 0, 100) . "...");
24        return "エラー: データの復元に失敗しました。不正なシリアライズデータが入力された可能性があります。";
25    }
26
27    return $unserializedResult;
28}
29
30// --- サンプルコードの実行 ---
31
32// 1. 正常なデータの例
33$validArray = ['id' => 1, 'name' => 'Alice', 'roles' => ['admin', 'user']];
34$serializedValidData = serialize($validArray);
35echo "--- 正常なデータの復元 ---\n";
36echo "シリアライズされたデータ: " . $serializedValidData . "\n";
37$restoredValidData = safeUnserialize($serializedValidData);
38if (is_string($restoredValidData)) {
39    echo $restoredValidData . "\n"; // エラーメッセージの場合
40} else {
41    echo "復元されたデータ: ";
42    print_r($restoredValidData);
43}
44echo "\n";
45
46// 2. 不正な形式のデータの例 (途中で途切れた文字列)
47$malformedString = 'a:2:{s:4:"name";s:5:"Alice";s:3:"age";i:30'; // 不完全なシリアライズデータ
48echo "--- 不正なデータの復元 (途中で途切れた文字列) ---\n";
49echo "シリアライズされたデータ: " . $malformedString . "\n";
50$restoredMalformedData = safeUnserialize($malformedString);
51if (is_string($restoredMalformedData)) {
52    echo $restoredMalformedData . "\n"; // エラーメッセージが返される
53} else {
54    echo "復元されたデータ: ";
55    print_r($restoredMalformedData);
56}
57echo "\n";
58
59// 3. 無効なクラスを参照するデータの例 (定義されていないクラス)
60// PHPは、不明なクラスを参照するシリアライズデータをunserializeしようとすると、
61// `__PHP_Incomplete_Class`オブジェクトを返すか、falseを返すことがあります。
62// この例ではfalseを返すケースを想定。
63$undefinedClassData = 'O:15:"UndefinedMyClass":2:{s:3:"foo";s:3:"bar";s:3:"baz";s:6:"quxphp";}';
64echo "--- 無効なクラスを参照するデータの復元 ---\n";
65echo "シリアライズされたデータ: " . $undefinedClassData . "\n";
66$restoredUndefinedClassData = safeUnserialize($undefinedClassData);
67if (is_string($restoredUndefinedClassData)) {
68    echo $restoredUndefinedClassData . "\n"; // エラーメッセージが返される
69} else {
70    echo "復元されたデータ: ";
71    print_r($restoredUndefinedClassData);
72}
73echo "\n";
74
75// 4. boolean `false` の正常なシリアライズデータ
76$serializedBooleanFalse = serialize(false); // これは 'b:0;' となる
77echo "--- 論理値 false の復元 ---\n";
78echo "シリアライズされたデータ: " . $serializedBooleanFalse . "\n";
79$restoredBooleanFalse = safeUnserialize($serializedBooleanFalse);
80if (is_string($restoredBooleanFalse)) {
81    echo $restoredBooleanFalse . "\n"; // エラーメッセージの場合
82} else {
83    echo "復元されたデータ (型を維持): ";
84    var_dump($restoredBooleanFalse); // false (boolean) が正常に復元される
85}
86echo "\n";
87
88?>

PHPのunserialize関数は、serialize関数によって文字列形式に変換(シリアライズ)されたデータを、元のPHPの値(配列、オブジェクト、数値など)に復元するために利用されます。引数$dataにはシリアライズされた文字列を指定し、戻り値として元のデータ型で復元された値が返されます。

PHP 8では、入力されたシリアライズデータが不正な形式であった場合、unserialize関数はfalseを返し、同時にE_NOTICEなどの警告を発することがあります。そのため、この関数の利用時には戻り値を適切にチェックし、エラー発生時に対処することが極めて重要です。

提供されたサンプルコードのsafeUnserialize関数は、このエラーハンドリングの例を示しています。この関数では、unserializeが発行する可能性のある警告を@演算子で抑制しつつ、戻り値がfalseである場合にエラーと判断しています。ただし、PHPで論理値のfalseをシリアライズすると'b:0;'という文字列になるため、この特定のケースは正常なデータとして扱い、それ以外のfalseが返された場合を不正なデータによるエラーと識別しています。これにより、途中で途切れた文字列や、定義されていないクラスを参照するデータのような不正な入力を安全に検出し、復元失敗のメッセージを返すことができる堅牢な処理が実現されています。

unserialize関数は、文字列を元のPHPデータ型に戻す役割がありますが、入力されるシリアライズデータが不正な場合、falseを返し、同時にE_NOTICEE_WARNINGといった警告が発生する可能性があります。サンプルコードでは、この警告を@演算子で一時的に抑制していますが、抑制しただけではエラー処理は完了しません。そのため、unserializeの戻り値がfalseかどうかを必ず確認し、エラーが発生した際の適切な処理を実装することが非常に重要です。ただし、シリアライズされた論理値のfalse ('b:0;') もfalseとして復元されるため、これをエラーと誤認しないよう、サンプルコードのように特別な条件で区別する必要があります。また、unserializeは悪意のあるデータによりセキュリティ上の脆弱性を引き起こす可能性があるため、信頼できない外部からのデータには決して使用しないでください。

unserializeのPHP_INT_MAX超過時の型変換

1<?php
2
3/**
4 * unserialize() function demonstration.
5 *
6 * This function illustrates how `unserialize` handles a numeric value
7 * that exceeds the maximum integer limit (PHP_INT_MAX) for the system.
8 * Instead of a classical integer overflow (where the value wraps around),
9 * PHP converts such a value to a floating-point number. This demonstrates
10 * a potential implicit type change that system engineers should be aware of
11 * when processing serialized data, especially from untrusted sources.
12 */
13function demonstrateUnserializeLargeNumberHandling(): void
14{
15    // Display the maximum integer value for the current PHP environment.
16    echo "System's PHP_INT_MAX: " . PHP_INT_MAX . "\n";
17    echo "System's integer size: " . (PHP_INT_SIZE * 8) . "-bit\n\n";
18
19    // --- Scenario 1: A number within PHP_INT_MAX ---
20    // We create a serialized string for an integer that is well within the system's limit.
21    $safeNumber = PHP_INT_MAX > 1000 ? PHP_INT_MAX - 100 : 100; // Ensure it's a reasonable safe number
22    $serializedSafeInt = 'i:' . $safeNumber . ';';
23
24    echo "Input (integer within limits): '" . $serializedSafeInt . "'\n";
25    $unserializedSafe = unserialize($serializedSafeInt);
26    echo "Unserialized value: " . $unserializedSafe . "\n";
27    echo "Output type: " . gettype($unserializedSafe) . "\n\n";
28
29    // --- Scenario 2: A number exceeding PHP_INT_MAX ---
30    // Craft a string representing a number that is guaranteed to be larger than PHP_INT_MAX.
31    // By appending '1' to the string representation of PHP_INT_MAX, we create such a number.
32    // Example: if PHP_INT_MAX is 9223372036854775807, this creates "92233720368547758071".
33    $overflowCandidateString = (string)PHP_INT_MAX . '1';
34
35    // We manually construct a serialized string using the 'i:' (integer) prefix
36    // even though the value itself exceeds the integer limit.
37    $serializedOverflowInt = 'i:' . $overflowCandidateString . ';';
38
39    echo "Input (integer string exceeding limits): '" . $serializedOverflowInt . "'\n";
40    $unserializedOverflow = unserialize($serializedOverflowInt);
41    echo "Unserialized value: " . $unserializedOverflow . "\n";
42    echo "Output type: " . gettype($unserializedOverflow) . "\n\n";
43
44    echo "Observation:\n";
45    echo "When the integer value in the serialized string ('i:...') exceeds PHP_INT_MAX,\n";
46    echo "PHP's `unserialize` function automatically converts it to a 'float' type.\n";
47    echo "This is PHP's mechanism to prevent a hard integer overflow for very large numbers.\n";
48    echo "System engineers should be aware of such implicit type conversions, as they\n";
49    echo "can lead to unexpected behavior if strict integer types are assumed.\n";
50}
51
52// Execute the demonstration function.
53demonstrateUnserializeLargeNumberHandling();

unserialize関数は、PHPのserialize関数などで文字列化(シリアライズ)されたデータを、元のPHPのデータ型と値に戻すための関数です。引数には復元したいシリアライズ済みのstringデータを指定し、オプションで挙動を変更するarrayを渡すこともできます。戻り値は復元されたmixed型の値となります。

このサンプルコードは、unserialize関数がPHPの最大整数値(PHP_INT_MAX)を超える数値をどのように扱うかを示しています。通常の整数範囲内の数値をシリアライズしてunserializeすると、期待通りint型として復元されます。しかし、シリアライズされたデータの中で整数型(i:プレフィックス)として表現されていても、その値がPHP_INT_MAXを超過している場合、unserialize関数はそれを自動的にfloat型へと変換して復元します。

これは、PHPが非常に大きな整数値を扱う際に、従来の整数オーバーフロー(値が一周する現象)を避け、精度は失われる可能性がありますが、より広い範囲の数値を保持するために浮動小数点数に型を変換する挙動です。システムエンジニアを目指す方々は、特に外部からのデータを処理する際に、このような暗黙の型変換が発生しうることを認識し、予期せぬ挙動やデータの不整合を防ぐための注意が必要です。

PHPのunserialize関数では、シリアライズされたデータ中の整数値がシステムが扱える最大整数値PHP_INT_MAXを超えると、その値は自動的にfloat型(浮動小数点数)に変換されます。これは一般的な整数オーバーフローとは異なり、PHPが大きな数値を扱うための暗黙的な型変換の仕組みです。システムエンジニアを目指す方々は、この挙動に特に注意が必要です。プログラムが厳密な整数型を前提としている場合、予期しない動作や計算結果の不整合につながる可能性があります。外部からの信頼できないデータをデシリアライズする際は、処理後のデータ型をgettype()などで常に確認し、意図しない型変換を考慮した堅牢なコード設計を心がけましょう。

関連コンテンツ

関連プログラミング言語

【PHP8.x】unserialize関数の使い方 | いっしー@Webエンジニア