PHP 在解压缩 GZipped 文件时挂起


PHP hangs at uncompressing a GZipped file?

我正在解压缩一个.gz文件,并使用php将输出放入tar。我的代码看起来像

$tar = proc_open('tar -xvf -', array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'a')), &$pipes);
$datalen = filesize('archive.tar.gz');
$datapos = 0;
$data = gzopen('archive.tar.gz', 'rb');
while (!gzeof($data))
{
    $step = 512;
    fwrite($pipes[0], gzread($data, $step));
    $datapos += $step;
}
gzclose($data);
proc_close($tar);

它工作得很好(tar 提取了几个目录和文件),直到压缩文件(根据我的$datapos)一半多一点,然后脚本将永远卡在fwrite($pipes...)行(我等了几分钟让它前进)。

压缩存档的大小为 8425648 字节 (8.1M),未压缩的存档大小为 36720640 字节 (36M)。

我在这里可能做错了什么,因为我没有找到任何考虑类似问题的资源?

我在 5.6.32-5-amd64 机器上运行 php5-cli 版本 5.3.3-7+squeeze3(带有 Suhosin 0.9.32.1)。

1 => array('pipe', 'w')

你有 tar 给你关于标准输出的数据(文件名)。 应清空该缓冲区。(我通常只是阅读它。

您也可以将其发送到文件,这样就不必处理它。

1 => array('file', '[file for filelist output]', 'a')

如果你在Linux上,我喜欢做

1 => array('file', '/dev/null', 'a')

[编辑:一旦它输出足够多,它将等待你从标准输出读取,这是你悬挂的地方。

你的问题是缓冲区问题之一,就像@EPB说的那样。清空流缓冲区(例如:在非阻塞模式下使用 fread on $pipes[1];或干脆移除v开关)。

但是,我想指出的是,$datalen将包含数据的压缩长度,而$datapos将包含未压缩的数据长度,因为传递给gzread$step是以字节为单位读取的未压缩长度。如果要使用实际的未压缩存档大小填充$datalen,请使用如下所示的内容:

$info = shell_exec('gzip -l archive.tar.gz');
$temp = preg_split('/'s+/', $info);
$datalen = $temp[6]; // the actual uncompressed filesize

否则你最终会得到$datapos总是比$datalen大。