在一个旨在处理通用共享LAMP托管的PHP脚本中,我使用require()
作为函数从文件中读取数据。数据文件如下所示:
<?php
# storage.php
return [
// Rotating secrets
'last_rand' => '532e89355b78aafdb85f5f01f0eed20440d6bd9e0a2d6ae1bd17be4e1d7d21c7bb7a822a2077e3f4',
];
我这样读了:
$data = require($root . '/storage.php');
$lastRand = $data['last_rand'];
在我的脚本中,我将使用此方法从配置文件中读取信息。在某些情况下,操作将重新编写新的配置文件(使用file_put_contents()
),然后再次使用require()
重新读取它。
到目前为止,这已经在各种LAMP主机上运行良好,但今天我发现了一个网络主机require()
似乎没有注意到文件中的变化。这个主机使用PHP 5.6,而我测试的所有其他主机都使用7 +。
奇怪的是require()
获取文件的旧内容,即使file_get_contents()
可以看到新版本,就像require()
正在进行自己的内部缓存一样。
我甚至试图等待require()
赶上,以防某些底层缓存需要时间到期:
$ok = true;
$t = microtime(true);
while ($oldRandom != $this->getFileService()->requirePhp($this->getStoragePath())['last_rand'])
{
$elapsedTime = microtime(true) - $t;
if ($elapsedTime > 4) // Wait 4 seconds
{
$ok = false;
break;
}
usleep(1000);
}
这也不起作用(超时刚过期而require()
带来的结果没有变化)。
但是,在下一次运行PHP脚本时,require()
会突然看到新文件内容。
我还尝试在重新阅读之前删除storage.php
文件,这也没有效果!我真的希望能帮到你。
所以,我根本不明白这种行为。为了解决这个问题,我可以:
file_get_contents()
而不是require()
(因为相当沉闷的原因,它不那么方便,但我会更喜欢可靠的工作)。然而,这些都觉得我忽略了一个错误,我应该调查原因。我碰巧也知道这个主机(一个免费的)几乎总是在CPU负载很重的情况下。它是一个64位服务器,在相当旧的2.6内核上运行Linux,而phpinfo()
表示CGI / FastCGI服务器API已生效。
以前有没有人遇到过这个问题,可以做些什么来缓解它?
一些有用的评论者认为这个问题可能与opcaching有关,这似乎符合require()
的一般目的。我在重写配置的file_put_contents()
之后添加了这段代码:
$reset = opcache_reset(); // Returns true
$invalid = opcache_invalidate($this->getStoragePath()); // Returns false
然而,它没有任何区别 - require()
顽固地读取相同的值。我通过在文件写入之前和之后执行require()
以及file_get_contents()
来确认这一点,以获取真实内容。
答案 0 :(得分:1)
当我最初遇到这个错误时,我对于解决这个问题犹豫不决,因为它感觉就像一个不容忽视的关键错误。但是,现在罪魁祸首很可能是opcaching(因此与require()
具体相关),我认为通过将值保存在内存中来解决它并不是一个糟糕的解决方案。我必须记住,require()
仅适用于每个HTTP请求的一次调用,即使对于所有PHP安装都不适用。
我也意识到,如果我确实试图解决这个问题,我将不得不面对一些opcache失效机制,这比我所熟悉的更复杂。