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 で問題なし。

試しに問題の配列に同じ日本語文字列をいれたところなぜかデータを復元できた。
でも実際は様々なデータが入ってくるので、それぞれに応じて対処しなければいけない。
様々な方法を試みたが結局解決しませんでしたが、「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 さん!

コメント

  1. teradaさんのコメント

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

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

  2. NO NAMEさんのコメント

    ありがとうございます。

    ラッキーな事に10分でこの解決策にたどり着けました。