Я знаю, что это старый вопрос, но, полагаю, лучше поздно, чем никогда. Недавно я столкнулся с этой проблемой, унаследовав базу данных, в которой поиск/замена выполнялась для сериализованных данных. После многих часов исследований я обнаружил, что это произошло из-за того, что счетчик строк был выключен. К сожалению, было так много данных с большим количеством экранирований и новых строк, и я не знал, как считать в некоторых случаях, и у меня было так много данных, что мне нужно было что-то автоматизированное.
По пути я наткнулся на этот вопрос, и пост Бенуберда помог мне направить меня на правильный путь. Его пример кода не работал в производственной среде со сложными данными, содержащими множество специальных символов и 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/catch, потому что в моем случае попытка увенчалась успехом, но просто вернула пустую строку. Итак, вместо этого я проверяю наличие пустых данных.
- Я пробовал множество регулярных выражений, но только мод на Benubird точно обрабатывал все случаи. В частности, мне пришлось изменить часть, которая проверяла наличие ";" потому что это будет соответствовать CSS, как «ширина: 100%; высота: 25 пикселей;» и сломал вывод. Итак, я использовал положительный просмотр вперед, чтобы соответствовать только тогда, когда «;» был вне набора двойных кавычек.
- В моем случае было много новых строк, HTML и экранированных двойных кавычек, поэтому мне пришлось добавить блок, чтобы очистить это.
- Было несколько странных ситуаций, когда данные неправильно заменялись регулярным выражением, а затем сериализация также считала их неправильно. Я НИЧЕГО не нашел на каких-либо сайтах, чтобы помочь с этим, и, наконец, подумал, что это может быть связано с кэшированием или чем-то в этом роде, и попытался сбросить буфер вывода (ob_end_flush()), что сработало, слава богу!
Надеюсь, это кому-то поможет... У меня ушло почти 20 часов, включая исследования и решение странных проблем! :)
person
Brandon Elliott
schedule
03.04.2016