Tags:, Posted in PHP Leave a Comment

例えば64bit OS上で、あるデータを serialize します。
次に32bit OSでこの値を取得して unserialize した場合のお話。
レアなケースとは思いますが、それにハマってしまったので一応共有。

現象

64bit OSから、例えば次のようなコードで、配列をシリアライズして memcache に保存します。

$x = '1062430001292';
$a[$x] = $x; 
$v = serialize($a);
$m->set('test', $v);

本来 memcache::set を使うなら serialize 不要ですが、ここは分り易くするために。
で、この値を32bit OS側から取得してやります。

$v = $m->get('test');
$a = unserialize($v);
print_r($a);

すると、結果は次のようになってしまいます。

Array
(
    [1573079180] => 1062430001292
) 

添え字と値は同じものを指定していたはずですが、全く異なる値になってしまいます。

原因

書き込む前の、64bit OS上での $a を var_dump してみます。

array(1) {
  [1062430001292]=>
  string(13) "1062430001292"
}

そして、serialize した $v の値を見てみましょう。

a:1:{i:1062430001292;s:13:"1062430001292";} 

一見良さそうですが、問題点が潜んでいます。

a:1:{i:1062430001292;s:13:"1062430001292";} 

そう、添え字が int となってしまっています。
明示的にキャストしたり、色々と試してみましたが、添え字の中身が全て数値の場合はどうしても int と識別してしまう様子。
そのため、32bit OSの int では桁が足りず、32bit分だけの数値になってしまうワケですね。

対処方法

我々のプロジェクトでは、添え字の値は捨てることで対応可能でした。
しかしいつもそういった対応が可能とは限りません。
出来るならば、例えばアタマに “id” と付けるなど、イヤでも文字列になるような対処も方法のひとつだと思います。

$x = '1062430001292';
$a["id:{$x}"] = $x; 

それも難しければ、serialize した後で文字列に無理矢理変換する方法もあるかもしれませんが、オススメはしにくいですよね。

a:1:{i:1062430001292;s:13:"1062430001292";}

a:1:{s:13:"1062430001292";s:13:"1062430001292";}
このエントリーをはてなブックマークに追加
Bookmark this on Yahoo Bookmark
Bookmark this on Livedoor Clip
Share on FriendFeed
Share on StumbleUpon
Newsing it!

Related posts:

  1. [PHP] 配列やオブジェクトの値渡しと参照渡し

2009 年 5 月 22 日