PHP 将整数从 64 位非序列化为 32 位

发布于 2024-12-12 07:16:06 字数 747 浏览 0 评论 0原文

我一直试图在 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 本身编写了反序列化方法吗?或者有协议的详细信息吗?我可以使用它并为这些整数定制一个案例。

谢谢。

注意:我无权访问原始数据,只能访问序列化结果。

I have been trying to unserialize on a 32-bit server an object that was serialized on a 64-bit server. I have isolated my problem to an integer in the object. Here is a small reproduction of the problem.

On a 64-bit machine:

$i = serialize('20110510134021'); //i:20110510134021;

On a 32-bit machine:

$i = unserialize('i:20110510134021;');

Gives the error

Notice: unserialize(): Error at offset 0 of 16 bytes

Now I understand that those serialization method shouldn't be used for cross system data transmition. However, we are merely trying to migrate the data to another system, not use it actively for transfers. This is a one time thing.

I would think that this might be due to integer overflow, but even on the 32-bit server I can do something like

$i = 20110510134021;
echo $i;

And it will work fine. I'm guessing PHP integer types scale to some double type or something like that. But why doesn't it do that when it unserializes?

How can I unserialize those objects? If I can't, is there any way to convert them to something else? Finally, has anyone written a deserialize method in PHP itself? Or has details on the protocol? I could use that and have a custom case for those integers.

Thanks.

Note: I do not have access to the original data, only the serialized result.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

柠檬色的秋千 2024-12-19 07:16:07

32位系统上最大整数为4294967296
$i = 20110510134021; 之所以有效,是因为 PHP 将变量转换为 double。

因此,将 i 替换为 d

$i = unserialize('d:20110510134021;');

如果运行此脚本,您将在正在运行的系统上看到变量的正确表示(d: 在 32 位系统上,i:在 64 位系统上):

$int = 20110510134021;
var_dump(serialize($int));

The max integer on 32 bit system is 4294967296;
$i = 20110510134021; works because PHP converts the variable to double.

So replace i with d

$i = unserialize('d:20110510134021;');

If you run this script, you will see the correct represenation of the variable on the system you are running (d: on 32 bit system, i: on 64 bit system):

$int = 20110510134021;
var_dump(serialize($int));
始终不够 2024-12-19 07:16:07

简单的解决方案是,如果您知道在 64 位上序列化的数据有可能在 32 位计算机上反序列化,则可以在序列化之前将其转换为 (double)。

然后它将被反序列化为双精度数,为每个整数提供比标准的每个整数 4 字节(32 位)更多的位数。

反序列化后,只需将该数字作为双精度数使用。在 99% 的情况下,这是一个很好的解决方案。对于非常大的数字,在 32 位机器上分配给双精度数字的“实数”部分的位数仍然有可能不够。我认为它是 56 位,因此最大整数仍然明显大于 int 类型的 32 位。

The simple solution is if you know that there is a chance that data serialized on 64 bit will be unserialized on 32 bit machine is to cast it to (double) before serializing.

Then it will be unserialized as a double, giving you more bits per integer than a standard 4-byte per integer (32 bits)

Once unserialized just work with that number as a double. In 99% of the cases this is a good solution. There is still a chance that for a very large number the number of bits allocated to the 'real' part on the number to a double on a 32 bit machine will not be enough. I think it's 56 bits, so the maximum integer is still significantly larger that the 32bits for the int type.

赠我空喜 2024-12-19 07:16:07

怎么样:

$serialized = 'i:20110510134021';

if (preg_match('/i\:([\d]+)/', $serialized, $match))
{
    $unserialized = $match[1];
}

How about:

$serialized = 'i:20110510134021';

if (preg_match('/i\:([\d]+)/', $serialized, $match))
{
    $unserialized = $match[1];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文