使用内存/大小约束反序列化

use*_*243 5 php memory serialization

有没有办法使用unserialize内存/大小限制?

目前我们有:

$data = unserialize($_SESSION['visits']);
Run Code Online (Sandbox Code Playgroud)

我们偶尔会得到:

PHP Fatal error: Allowed memory size of 134217728 bytes in the Unknown on line 0 (尝试分配 17645568 字节)

当访问者在短时间内进行了大量访问时(会话值存储有关访问的每个页面的信息)。

如果 的长度$_SESSION['visits']超过一百万个字符,则会导致问题,因此我可以对此进行简单检查,但是否有比这更好的解决方案:

 if(strlen($_SESSION['visits']) <= 1000000) {
    $data = unserialize($_SESSION['visits']);
} else {
    $data = array();
}
Run Code Online (Sandbox Code Playgroud)

我认为try catch可能表现得更好,但没有被抓住:

try{
    $data = unserialize($_SESSION['vists']);
} catch(\Exception $exception){
    error_log('Caught memory limit');
}
Run Code Online (Sandbox Code Playgroud)

这个问题的答案不是增加内存大小。

Mvo*_*sek 6

有两种选择:

a) 在另一个 phpprocess 中反序列化

这可能会因内存限制错误而失败,并且可能仅返回您感兴趣的数据。

如何?

  1. 创建自定义 php 脚本/文件:
    1. 调用自动加载器/初始化应用程序
    2. 通过文件反序列化传递的值或$argv
  2. 使用调用该脚本exec()

为了解决问题要求,您可以:

  • 从自定义脚本返回内存使用情况(并检查该内存在父脚本中是否可用)
  • 或者仅通过文件或标准输出返回您感兴趣的数据

b) 使用自定义解析器

就像https://github.com/xKerman/restricted-unserialize一样,它允许:

  • 按单个值反序列化并检查之前是否有足够的内存(同样的问题,但对于小数据,您可以检查得更好)
  • 遍历数据而不完全反序列化它们(因此不使用额外的内存)

c) 使用数据库

上述两个选项可以满足您的要求。然而,我强烈的建议是将会话/访问数据存储在数据库中,然后仅存储它们的唯一 ID。