【发布时间】:2020-10-06 05:19:34
【问题描述】:
有没有办法在内存/大小限制的情况下使用unserialize?
目前我们有:
$data = unserialize($_SESSION['visits']);
我们偶尔会得到:
PHP 致命错误:第 0 行 Unknown 中允许的内存大小为 134217728 字节已用尽(尝试分配 17645568 字节)
当访问者在短时间内进行了多次访问时(会话值存储有关访问的每个页面的信息)。
如果$_SESSION['visits'] 的长度超过一百万个字符,则会导致问题,因此我可以对此进行简单检查,但是否有比这更好的解决方案:
if(strlen($_SESSION['visits']) <= 1000000) {
$data = unserialize($_SESSION['visits']);
} else {
$data = array();
}
我认为try catch 可能会表现得更好,但它没有被抓住:
try{
$data = unserialize($_SESSION['vists']);
} catch(\Exception $exception){
error_log('Caught memory limit');
}
这个问题的答案不是增加内存大小。
【问题讨论】:
-
unserialize没有限制,可用内存除外。这是RFC for PHP 7,它介绍了从错误到异常的变化。如果您向下滚动到并非所有错误都已转换,您会看到一条说明,即与内存相关的错误不会转换为异常。 “有些是不可能的,比如内存限制”。尽管您可以使用register_shutdown_function,但您所能做的就是吐出一条快速死亡的消息并记录一些内容。您可以在序列化时处理大小限制,而不是捕获反序列化吗? -
内存限制错误是致命错误而不是异常,这就是您无法捕获它的原因。此外,没有办法将内存限制为仅用于一项功能。 memory_limit 是一个全局变量
-
不完全正确:您可以捕获和后处理“致命”错误,但不能在 try/catch 块中,而且您也无法返回到原来的位置。您所能做的就是记录并...在新分支上做其他事情。但内存不足错误实际上是最难处理的错误之一,因为您无法在处理程序中执行任何使用更多内存的操作。
-
会话数据在存储在文件系统中时已经在后台序列化/反序列化。您是否有“双重序列化”会话变量的特殊原因?另外,我想知道你到底在那儿存储了什么(以及为什么),以获得每个用户 100 万个字符的值得访问数据?我可以想到一些在块中实现反序列化的肮脏方法(当内存最大化时会导致部分数据),但似乎改变策略(和问题)是一种(更好)的前进方式。
-
@user3783243 如果您需要 14 年,请将 SessionID 保留在 Session 对象中,并为所有数据使用数据库。每次调用服务器时,您是否需要 PHP 真正解析所有这些数据?放入数据库意味着您只在需要时获得所需的数据,而无需处理更多数据。您也可以进行其他查询,例如访问类型。 (我们所有的会话处理都是这样处理的,除非项目没有附加数据库。在顶部使用内存缓存,它非常有效。)
标签: php memory serialization