私はこれが古い質問であることを知っていますが、決してしないよりは遅いほうがいいと思います。最近、シリアル化されたデータに対して検索/置換が実行されたデータベースを継承した後、この問題に遭遇しました。何時間も調査した結果、これは文字列の数がずれているためであることがわかりました。残念ながら、大量のエスケープと改行を含む非常に多くのデータがあり、場合によっては数え方がわからず、データが多すぎて自動化が必要でした。
その過程で、私はこの質問に出くわし、Benubird の投稿が私を正しい道に導いてくれました。彼のコード例は、多数の特殊文字と HTML を含み、ネストが非常に深いレベルの複雑なデータの本番環境では機能せず、特定のエスケープ文字とエンコーディングを適切に処理しませんでした。そのため、私はそれを少し変更し、追加のバグに数え切れないほどの時間を費やして、私のバージョンがシリアル化されたデータを「修正」できるようにしました。
// do some DB query here
while($res = db_fetch($qry)){
$str = $res->data;
$sCount=1; // don't try to count manually, which can be inaccurate; let serialize do its thing
$newstring = unserialize($str);
if(!$newstring) {
preg_match_all('/s:([0-9]+):"(.*?)"(?=;)/su',$str,$m);
# preg_match_all("/s:([0-9]+):(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")(?=;)/u",$str,$m); // alternate: almost works but leave quotes in $m[2] output
# print_r($m); exit;
foreach($m[1] as $k => $len) {
/*** Possibly specific to my case: Spyropress Builder in WordPress ***/
$m_clean = str_replace('\"','"',$m[2][$k]); // convert escaped double quotes so that HTML will render properly
// if newline is present, it will output directly in the HTML
// nl2br won't work here (must find literally; not with double quotes!)
$m_clean = str_replace('\n', '<br />', $m_clean);
$m_clean = nl2br($m_clean); // but we DO need to convert actual newlines also
/*********************************************************************/
if($sCount){
$m_new = $m[0][$k].';'; // we must account for the missing semi-colon not captured in regex!
// NOTE: If we don't flush the buffers, things like <img src="http://whatever" can be replaced with <img src="//whatever" and break the serialize count!!!
ob_end_flush(); // not sure why this is necessary but cost me 5 hours!!
$m_ser = serialize($m_clean);
if($m_new != $m_ser) {
print "Replacing: $m_new\n";
print "With: $m_ser\n";
$str = str_replace($m_new, $m_ser, $str);
}
}
else{
$m_len = (strlen($m[2][$k]) - substr_count($m[2][$k],'\n'));
if($len != $m_len) {
$newstr='s:'.$m_len.':"'.$m[2][$k].'"';
echo "Replacing: {$m[0][$k]}\n";
echo "With: $newstr\n\n";
$str = str_replace($m_new, $newstr, $str);
}
}
}
print_r($str); // this is your FIXED serialized data!! Yay!
}
}
私の変更に関するちょっとマニアックな説明:
- Benubird のコードをベースとして数えようとすると、大規模なデータセットに対して不正確すぎることがわかりました。
- 私の場合、try は成功しますが、空の文字列を返すだけなので、try/catch を避けました。そのため、代わりに空のデータをチェックします。
- 私は多数の正規表現を試しましたが、すべてのケースを正確に処理できるのは Benubird の mod だけでした。具体的には、「;」をチェックする部分を変更する必要がありました。「幅:100%; 高さ:25px;」のような CSS で一致するためです。そして出力を壊しました。そのため、「;」の場合にのみ一致するように前向き先読みを使用しました。二重引用符のセットの外にありました。
- 私のケースには改行、HTML、およびエスケープされた二重引用符がたくさんあったため、それをクリーンアップするためにブロックを追加する必要がありました。
- データが正規表現によって誤って置き換えられ、シリアライズでも誤ってカウントされるという奇妙な状況がいくつかありました。これに役立つサイトは何も見つかりませんでしたが、最終的にはキャッシングなどに関連している可能性があると考え、出力バッファー (ob_end_flush()) をフラッシュしようとしましたが、うまくいきました。
これが誰かの役に立てば幸いです...調査と奇妙な問題への対処を含めて、ほぼ20時間かかりました! :)