Создание сценария, который может восстановить поврежденную сериализованную строку в PHP - PullRequest
2 голосов
/ 13 ноября 2011

Хорошо, у меня есть это:

a:1:{i:0;a:3:{s:7:"address";s:52:"Elågåresgude 41, 2200 Københamm N";s:12:"company_name";s:14:"Kaffe og Kluns";s:9:"telephone";s:0:"";}}

Это не работает с десериализацией ($ string);

Я знаю, где ошибка. Это номер перед адресом. Это должно быть не 52, а 36.

Я добрался до этого числа, посчитав строку (которая дала мне 33), а затем плюс с 1 на каждом å или ø, который существует в строке.

Когда я заменю 52 на 36, будет ли он просто рассекречен.

Теперь я хотел бы написать скрипт, чтобы сделать это для всех моих адресов.

Но как я могу это сделать? Извлечь адрес / имя_компании / телефонную строку, когда ее «испортили»?

Ответы [ 4 ]

4 голосов
/ 13 ноября 2011
function fix_corrupted_serialized_string($string) {
    $tmp = explode(':"', $string);
    $length = count($tmp);
    for($i = 1; $i < $length; $i++) {    
        list($string) = explode('"', $tmp[$i]);
        $str_length = strlen($string);    
        $tmp2 = explode(':', $tmp[$i-1]);
        $last = count($tmp2) - 1;    
        $tmp2[$last] = $str_length;         
        $tmp[$i-1] = join(':', $tmp2);
    }
    return join(':"', $tmp);
}

рабочая демоверсия: http://codepad.viper -7.com / GNbM25

1 голос
/ 08 апреля 2019

Эта проблема является классическим случаем, когда кто-то пытается выполнить ярлык при обновлении значения в сериализованной строке.Урок, который быстро усвоили, чтобы избежать этой головной боли, состоит в том, чтобы десериализовать ваши данные, изменить ваши значения, а затем повторно сериализовать их.проанализировать поврежденную сериализованную строку.Чтобы быть совершенно ясным, мой фрагмент будет обновлять только количество байтов / символов;если у вас есть сериализованная строка, которая повреждена каким-либо другим способом, это не будет решением проблемы.

Вот простой вызов preg_replace_callback(), который захватывает только подстроку значения и безоговорочно заменяет все числа байтов в сериализованномстрока:

Код: ( Демо )

$corrupted_byte_counts = <<<STRING
a:1:{i:0;a:3:{s:7:"address";s:52:"Elågåresgude 41, 2200 Københamm N";s:12:"company_name";s:14:"Kaffe og Kluns";s:9:"telephone";s:0:"";}}
STRING;

$repaired = preg_replace_callback(
        '/s:\d+:"(.*?)";/s',
        function ($m) {
            return 's:' . strlen($m[1]) . ":\"{$m[1]}\";";
        },
        $corrupted_byte_counts
    );

echo "corrupted serialized array:\n$corrupted_byte_counts";
echo "\n---\n";
echo "repaired serialized array:\n$repaired";
echo "\n---\n";
print_r(unserialize($repaired));

Вывод:

corrupted serialized array:
a:1:{i:0;a:3:{s:7:"address";s:52:"Elågåresgude 41, 2200 Københamm N";s:12:"company_name";s:14:"Kaffe og Kluns";s:9:"telephone";s:0:"";}}
---
repaired serialized array:
a:1:{i:0;a:3:{s:7:"address";s:36:"Elågåresgude 41, 2200 Københamm N";s:12:"company_name";s:14:"Kaffe og Kluns";s:9:"telephone";s:0:"";}}
---
Array
(
    [0] => Array
        (
            [address] => Elågåresgude 41, 2200 Københamm N
            [company_name] => Kaffe og Kluns
            [telephone] => 
        )

)

Я даже пошел немного дальшедля устранения возможного дополнительного случая. Без реализации расширения шаблона в этой ссылке приведенный выше фрагмент будет работать по желанию для строк с:

  • многобайтовыми символами
  • символами новой строки
  • двоеточия
  • точки с запятой
  • запятые
  • одинарные кавычки
  • двойные кавычки

Разрывается только когда строкадля сопоставления содержит "; - в этом случае моя ссылка выше пытается обратиться к этой возможности.

0 голосов
/ 13 ноября 2011

Похоже, ошибка в функции при работе с многобайтовыми символами. Вы также можете попробовать явно кодировать строку как utf-8 перед сериализацией.

В качестве обходного пути вы можете base64 кодировать адрес перед его сериализацией, а затем base64 декодировать его при десериализации.

0 голосов
/ 13 ноября 2011

Я думаю, что одно решение должно проверять, сработала ли десериализация. Если нет, удалите его и выполните повторную сериализацию.

$yourserializestring = '...';

$data = @unserialize($yourserializestring);
if ($yourserializestring === 'b:0;' || $data !== false) {
    // Something didn't work, you should recreate it
} else {
    echo "ok";
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...