PHP でシリアライズしたデータが壊れてしまう場合は base64_encode をする

本日 PHP で配列にデータを格納し serialize してデータの受け渡しをしていたら IE8 で unserialize してデータを復元することができないバグに遭遇しました。具体的には以下のようなエラーが発生。

Notice: unserialize() [function.unserialize]: Error at offset 0 of 2 bytes in /var/usr/to/path

うまく値の受渡しができていないのか、途中でデータが書き換わってしまったのか、様々な問題を調査しましたがどれも該当せず3時間。Web 上で情報を集めるもそれらしい問題に遭遇してる人がおらず解決できず。

どうしようもなくなったので、30個くらいある配列すべてをひとつずつ調べてチェックしていくと、どうやら30個の中の3配列が原因だということが判明しました。日本語の文字コードがおかしいのかと思って調査しましたが、すべて UTF-8 で問題なし。

試しに問題の配列に同じ日本語文字列をいれたところなぜかデータを復元できた。
でも実際は様々なデータが入ってくるので、それぞれに応じて対処しなければいけない。
様々な方法を試みたが結局解決せず。もうダメだと思って Twitter にもう無理です…タスケテ…と書いたところ @kiyotchi さんから神の言葉を授かりました。

@soraiy よく流れを見てないけど、IEに流したシリアル化データをunserializeするとエラーがでるということですか?例えば、base64エンコードしてやり取りするとかはどうかな?

できました。送信側は以下のようにして。

1
2
$data = serialize($array);
$data = base64_encode($data);

受け取り側をこうする。

1
2
$data = base64_decode($data);
$array = unserialize($data);

本当に助かりました。シリアライズは無敵だと信じていた私のミスでした。

どうやら HTTP経路上でバイト数が変わったりゴミデータを拾ったりすることがあるらしいです。そのため適宜データをやり取りする場合はなるべくエンコードしたほうが良さそうです。もう以下のような関数作って使ったほうが良いかもしれないですね。

1
2
3
4
5
6
7
8
9
10
11
12
13
// シリアライズしつつ base64 エンコードをする関数
function serialize_base64_encode($array) {
	$data = serialize($array);
	$data = base64_encode($data);
	return $data;
}
 
// base64 デコードしつつシリアライズされたデータを復元する関数
function unserialize_base64_decode($data) {
	$data = base64_decode($data);
	$array = unserialize($data);
	return $array;
}

まさか一日も時間を取られるなんて驚きました。
今回は同じようなことに苦しんでる人の助けになればいいと思って、この記事をかきました。
途中本当に泣きそうでした。ありがとう @kiyotchi さん!

Comments

  1. terada2010-7-30 (金) 16:30:52

    はじめまして。
    まさに同じ状況に陥っておりました。

    記事書いてくれてありがとうございます。
    助かりましたー

Leave a Comment

Trackback URL

コメントは承認待ちです。表示されるまでしばらく時間がかかるかもしれません。