シリアル化とエスケープ処理 (php:serialize / unserialize)


phpで「シリアライズ」したデータが「デシリアライズ」でエラーになる場合の注意点です。

現象

phpの連想配列内容をそのままCSV保存やDB登録したいので、php関数 「serialize」でシリアル化。そのシリアル化した文字列をphp関数 「unserialize」でデシリアライズするとエラー発生。
※シングルクォーテーションなどの特殊文字対策としてエスケープ処理済

Notice: unserialize() [function.unserialize]: Error at offset...

シリアル化 (シリアライズ) とは

IT用語辞典「e-Wors」サイトから引用します。

シリアライズとは、ソフトウェア内部で扱っているデータを丸ごと、ファイルで保存したりネットワークで送受信することができるように変換すること。
これとは逆に、ファイルに保存されているシリアライズされたデータや、ネットワークを通じて送られてきたシリアライズされたデータを、ソフトウェアで扱うことのできる元のデータ形式に復元することを「デシリアライズ」(deserialize)「デシリアライゼーション」(deserialization)という。

serialize / unserialize関数サンプル

<?
$value1 = 123;
$value2 = "abc";
$value3 = true;
$value4 = array("arr1"=>"a","arr2"=>"b");
$value5 = "テスト";

//■ serialize
echo ($seria1 = serialize($value1));
// 【結果】i:123
echo ($seria2 = serialize($value2));
// 【結果】s:3:"abc"
echo ($seria3 = serialize($value3));
// 【結果】b:1
echo ($seria4 = serialize($value4));
// 【結果】a:2:{s:4:"arr1";s:1:"a";s:4:"arr2";s:1:"b";}
echo ($seria5 = serialize($value5));
// 【結果】s:6:"テスト"

//■ unserialize
var_dump(unserialize($seria1));
var_dump(unserialize($seria2));
var_dump(unserialize($seria3));
var_dump(unserialize($seria4));
var_dump(unserialize($seria5));
?>

php関数「serialize」でのシリアライズでは生成後の文字列は主に「型 + 値」のような形になってます。
上記サンプルでは

10行目の結果:「123」は整数なので「i」です。実数なら「d」になります。
12行目の結果:「abc」は文字列なので「s」です。3の数字ですがバイト数のようです。
18行目の結果:同じく文字列で「テスト」と3文字ですが「s:6」と6になってます。
14行目の結果:ブーリアン型なので「b」です。true:1 false:0 になります。
16行目の結果:配列は「a」です。「a2」は配列で2要素あることを示しています。
{}内はキーと値が交互に並んでいます。

他にもオブジェクト型などいろいろあります。

エラーになるサンプル

<?
//▽エラーにならない
$value = "a'b'c";
echo ($value = addslashes($value));
// 【echo】a\'b\'c
echo ($seria = serialize($value));
// 【echo】s:7:"a\'b\'c";
echo stripslashes(unserialize($seria));
// 【echo】a\'b\'c

//▽エラーになる
$value = "a'b'c";
echo ($value = addslashes($value));
// 【echo】a\'b\'c
echo ($seria = serialize($value));
// 【echo】s:7:"a\'b\'c";
$seria = stripslashes($seria);
echo $seria;
// 【echo】s:7:"a'b'c";
echo unserialize($seria);
// 【ERROR】unserialize() [function.unserialize]:...
?>

2~9行目のサンプルと11~21行目のサンプルの違いは「stripslashes」 と 「unserialize」のタイミングの違いです。
6行目や15行目で「serialize」している文字列は「addslashes」でエスケープされています。バックスラッスを考慮してシルアル化されているので生成文字列は「s:7:"a\'b\'c";」 と文字列7バイト「s:7」となっています。
エラーになるサンプルでは17行目でシリアル化文字列を先に「stripslashes」しています。 シリアル化文字列は「s:7:"a'b'c";」 となり、「s:7」文字列7バイトと「"a'b'c"」文字列5バイトの不整合が起こっています。このシリアル化文字列を「unserialize」するとエラーになります。

// 【echo】s:7:"a\'b\'c";

結論

このエラーは単純なeasyミスです。シリアル化したときにエスケープ文字が含まれているかどうか考慮すれば解決です。

「addslashes →  serialize」
ならば 「unserialize → stripslashes」

「serialize →   addslashes」
ならば 「stripslashes → unserialize」

ファイルにしたり、DBに登録するとうっかりミスしてしまうことがあるので気をつけましょう。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です