#php #serialization #architecture #integer-overflow
#php #сериализация #архитектура #целое число-переполнение
Вопрос:
Я пытался отменить сериализацию на 32-разрядном сервере объекта, который был сериализован на 64-разрядном сервере. Я выделил свою проблему в целое число в объекте. Вот небольшое воспроизведение проблемы.
На 64-разрядной машине:
$i = serialize('20110510134021'); //i:20110510134021;
На 32-разрядной машине:
$i = unserialize('i:20110510134021;');
Выдает ошибку
Notice: unserialize(): Error at offset 0 of 16 bytes
Теперь я понимаю, что этот метод сериализации не следует использовать для межсистемной передачи данных. Однако мы просто пытаемся перенести данные в другую систему, а не активно использовать их для передачи. Это одноразовая вещь.
Я бы подумал, что это может быть связано с переполнением целых чисел, но даже на 32-разрядном сервере я могу сделать что-то вроде
$i = 20110510134021;
echo $i;
И это будет работать нормально. Я предполагаю, что целочисленные типы PHP масштабируются до некоторого двойного типа или что-то в этом роде. Но почему он этого не делает, когда он отменяет сериализацию?
Как я могу отменить сериализацию этих объектов? Если я не могу, есть ли какой-нибудь способ преобразовать их во что-то другое? Наконец, кто-нибудь написал метод десериализации в самом PHP? Или есть подробности о протоколе? Я мог бы использовать это и иметь пользовательский регистр для этих целых чисел.
Спасибо.
Примечание: у меня нет доступа к исходным данным, только к сериализованному результату.
Комментарии:
1. Возможно, попробуйте использовать JSON в качестве транспорта? Это использует совершенно другую кодовую базу и может не так сильно перегружать большие целые числа при декодировании строки в 32-битной системе.
2. Можете ли вы преобразовать это во временную строковую переменную и сериализовать ее вместо этого? ($i = serialize(‘20110510134021’); фактически сериализует строку ..)
3. Согласно документации PHP, целые числа масштабируются до плавающих значений при переполнении: php.net/manual/en/language.types.integer.php .
4. @MarcB я унаследовал эти данные. Если бы это был мой выбор, я бы никогда не использовал эти ужасные методы сериализации.
5. @jlb У меня нет доступа к исходным данным, только к сериализованному результату.
Ответ №1:
Максимальное целое число в 32-разрядной системе равно 4294967296
; $i = 20110510134021;
работает, потому что PHP преобразует переменную в double .
Поэтому замените i
на d
$i = unserialize('d:20110510134021;');
Если вы запустите этот скрипт, вы увидите правильное представление переменной в системе, которую вы запускаете (d: в 32-разрядной системе, i: в 64-разрядной системе):
$int = 20110510134021;
var_dump(serialize($int));
Комментарии:
1. Я как раз собирался попробовать это. Это работает. Я попрошу регулярное выражение просмотреть мои существующие сериализованные строки и изменить их. Спасибо.
Ответ №2:
Простое решение, если вы знаете, что существует вероятность того, что данные, сериализованные на 64-разрядной машине, будут несериализованы на 32-разрядной машине, — это преобразовать их в (double) перед сериализацией.
Тогда оно будет несериализовано как double, что даст вам больше бит на целое число, чем стандартное 4-байтовое целое число (32 бита)
После несериализации просто работайте с этим числом как с двойным. В 99% случаев это хорошее решение. Все еще существует вероятность того, что для очень большого числа количество битов, выделенных для «реальной» части числа в double на 32-разрядной машине, будет недостаточным. Я думаю, что это 56 бит, поэтому максимальное целое число все еще значительно больше, чем 32 бита для типа int.
Комментарии:
1. К сожалению, у меня нет доступа к исходным данным. Я унаследовал сериализованную форму и должен ее использовать.
Ответ №3:
Как насчет:
$serialized = 'i:20110510134021';
if (preg_match('/i:([d] )/', $serialized, $match))
{
$unserialized = $match[1];
}
Комментарии:
1. Это часть очень сложного объекта, содержащего массивы и строки, а что нет. Мне нужно иметь возможность отменить сериализацию этого объекта в целом.
2. Извините, мой плохой — удалил мой комментарий.
3. Кстати, являются ли исходные данные сериализованным массивом или объектом?