PHP挂起来解压缩GZipped文件?

时间:2012-06-27 15:58:40

标签: php gzip pipe tar hang

我正在解压缩.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)大。

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

我在2.6.32-5-amd64 linux机器上运行php5-cli版本5.3.3-7 + squeeze3(使用Suhosin 0.9.32.1)。

2 个答案:

答案 0 :(得分:3)

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

你有tar在stdout上给你数据(文件名)。你应该清空那个缓冲区。 (我通常只是阅读它。)

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

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

如果您使用的是Linux,我喜欢

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

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

答案 1 :(得分:1)

你的问题是缓冲区之一,如@EPB所说。清空流缓冲区(例如:在非阻塞模式下使用fread上的$pipes[1];或者只需删除v开关。

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

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

否则,最终$datapos总是大于$datalen