Php 始终在同一行上运行内存不足

Php 始终在同一行上运行内存不足,php,performance,memory,optimization,joomla,Php,Performance,Memory,Optimization,Joomla,首先,我不是在寻找“检查PHP内存限制”或“需要添加更多内存”之类的答案。。。我在一台专用机器上,有8GB的RAM;512MB是内存限制。我总是在一行中出现内存不足错误: 澄清:这部分代码属于CMS 这是Joomla缓存的一部分。。。此函数用于读取缓存文件并删除阻止直接访问文件的第一行,然后返回其余数据 如您所见,该行使用preg_replace删除缓存文件中的第一行,该行始终为: <?php die("Access Denied"); ?> 之后,正则表达式使用substr()尝

首先,我不是在寻找“检查PHP内存限制”或“需要添加更多内存”之类的答案。。。我在一台专用机器上,有8GB的RAM;512MB是内存限制。我总是在一行中出现内存不足错误:

澄清:这部分代码属于CMS

这是Joomla缓存的一部分。。。此函数用于读取缓存文件并删除阻止直接访问文件的第一行,然后返回其余数据

如您所见,该行使用preg_replace删除缓存文件中的第一行,该行始终为:

<?php die("Access Denied"); ?>
之后,正则表达式使用
substr()
尝试了相同的语句。内存使用方面的差异非常小。几乎没有


这是为了感谢您的贡献,我仍在试图找出发生这种情况的原因。

不要使用字符串函数替换大字符串中的某些内容。您可以在文件的各行之间循环,在找到要查找的内容后,只需中断即可。 请在此处查看PHP文档:


基本上是@cbuckley刚刚说的:p

我建议您在包括缓存文件在内的文件中使用此选项:

define('INCLUDESALLOW', 1);
在将包含的文件中:

if( !defined('INCLUDESALLOW') ) die("Access Denied");

然后只需使用
include
而不是
file\u get\u contents
。这将在包含的中运行PHP代码,但不能100%确定这是否是您所需要的。

如果您只想删除文件的第一行并返回其余部分,则应使用:


使用substr可避免内存不足
preg\u replace()
,如下所示:

$data = substr($data, strpos($data, '?>') + 3);
<?php
ini_set('memory_limit', '64M');
...
作为一般建议,如果可以使用其他字符串/数组函数执行相同的任务,则不要使用正则表达式,因为正则表达式函数比核心字符串/数组函数速度慢,占用的内存更多

PHP文档中也明确警告了这一点,请参见一些示例:


有时,您将使用比8MB php分配的内存更多的内存。如果您无法通过提高代码的效率来使用更少的内存,那么您可能必须增加可用内存。这可以通过两种方式实现

可以在php.ini中将限制设置为全局默认值:

memory_limit = 32M
或者可以在脚本中覆盖它,如下所示:

$data = substr($data, strpos($data, '?>') + 3);
<?php
ini_set('memory_limit', '64M');
...

与使用
fgets()
组合使用
fopen()
,而不是使用一次获取整个文件的
file\u get\u contents()
,后者可能太大,无法在其上运行regexps。此函数逐行获取文件

然后可以选择在特定行上执行regexp。或者在你的情况下,跳过整行

因此,不是:

$data = file_get_contents($path);
if($data) {
    // Remove the initial die() statement
    $data   = preg_replace('/^.*\n/', '', $data); // Out of memory here
}
试试这个:

$fileHandler = fopen($path,'r');
$lineNumber = 0;
while (($line = fgets($fileHandler)) !== false) {
    if($lineNumber++ != 0) { // Skip the initial die() statement
        $data .= $line; // or maybe echo out $line directly so $data doesn't take up too much memory as well.
    }
}

为什么要使用regexp从文件中删除第一行?“现在您有两个问题。”我认为您的regexp正在将所有行替换为空。最终耗尽了所有内存。@Wooble我添加了一个说明,说明这段代码属于Joomla@nl-x不,只需删除第一行即可。我在前后转储了$数据,但它没有改变任何其他内容。@AhmadAlfy在regexp期间内存不足时,你怎么能在前后转储?我不是regexp专家,但我认为您的表达式从一行(^)开始一直到换行(\n)。如果不指定count参数,它将更改所有出现的情况。现在我知道
preg\u replace()
是一个内存占用器。我将进行测试,并再次提供结果。ThanksI使用
memory\u get\u usage()
来比较
substr
preg\u replace()
之间的内存使用情况,发现差异非常小。我已经更新了问题;谢谢你的帮助。我刚刚意识到,在把你的答案读得足够好之前,我给出了和你一样的答案。你(和我)的答案与cbuckley的答案基本上不一样,因为我们的答案不涉及一次阅读整个文件。Cbuckley的答案是一次读取整个文件(并将其拆分为一个数组)。我会试试看,谢谢。我认为
$lineNumber++
缺少一个
:)啊!你说得对,对不起。但是请不要调用处理程序FileLocation,因为它不会试图告诉您文件在哪里。但它是一个指针,告诉您在文件中的位置。希望你明白这一点。指针从文件的开头开始。每次调用fgets()时,指针都会移动到下一个换行符,并返回中间的所有内容。(顺便说一句,我将lineNumber++移到了if()中)内存消耗比我在最后一行评论的
preg_replace
@AhmadAlfy更高,而不是执行
$data.=$line也可以直接输出数据。这避免了将整个文件放入内存。问题的第一句话是:“首先,我不是在寻找一个说“检查您的PHP内存限制”或“您需要添加更多内存”或诸如此类的答案…”
$fileHandler = fopen($path,'r');
$lineNumber = 0;
while (($line = fgets($fileHandler)) !== false) {
    if($lineNumber++ != 0) { // Skip the initial die() statement
        $data .= $line; // or maybe echo out $line directly so $data doesn't take up too much memory as well.
    }
}