解压缩或膨胀php://输入流?

时间:2017-07-08 02:03:06

标签: php input stream unzip inflate

我正在尝试直接从php://input流解压缩zip文件。我正在运行Laravel Homestead,PHP 7.1.3-3+deb.sury.org~xenial+1,端点位于myproject.app/upload,这是curl命令:

curl --request POST \
  --url 'http://myproject.app/upload' \
  --data-binary "@myfile.zip" \

以下列出了我尝试过的所有方法,但都失败了:

dd(file_get_contents('compress.zlib://php://input'));

file_get_contents():无法将输入类型的流表示为文件描述符

$fh = fopen('php://input', 'rb');

stream_filter_append($fh, 'zlib.inflate', STREAM_FILTER_READ, array('window'=>15));

$data = '';

while (!feof($fh)) {
    $data .= fread($fh, 8192);
}

dd($data);

“”

$zip = new ZipArchive;

$zip->open('php://input');
$zip->extractTo(storage_path() . '/' . 'myfile');
$zip->close();

ZipArchive :: extractTo():无效或未初始化的Zip对象

以下是我在该主题上找到的所有链接:

http://php.net/manual/en/wrappers.php#83220

http://php.net/manual/en/wrappers.php#109657

http://php.net/manual/en/wrappers.compression.php#118461

https://secure.phabricator.com/rP42566379dc3c4fd01a73067215da4a7ca18f9c17

https://arjunphp.com/how-to-unpack-a-zip-file-using-php/

我开始认为使用PHP的内置zip功能在流上操作是不可能的。编写临时文件的开销和复杂性将非常令人失望。有谁知道怎么做,或者它是一个错误?

1 个答案:

答案 0 :(得分:3)

经过更多的研究,我发现了答案,但并不令人满意。由于现代世界的一大错误, gzip和zip格式不一样。 gzip对单个文件进行编码(这就是我们经常看到tar.gz的原因),而zip则对文件和文件夹进行编码。我试图上传一个zip文件并用gzip解码它,这是行不通的。更多信息:

https://stackoverflow.com/a/20765054/539149

https://stackoverflow.com/a/1579506/539149

此问题的另一部分是 PHP忽略了为gzip提供流过滤器

https://stackoverflow.com/a/11926679/539149

即使gzopen('php://temp', 'rb')有效,gzopen('php://input', 'rb') 也不会,因为输入流不可重绕。这使得无法对内存中的流进行操作,因为无法将数据写入流,然后在与该流的单独gzip连接上读取解压缩的数据。这意味着以下代码工作:

$input = fopen("php://input", "rb");
$temp = fopen("php://temp", "rb+");
stream_copy_to_stream($input, $temp);
rewind($temp);
dd(stream_get_contents(gzopen('php://temp', 'rb')));

人们已尝试过各种变通方法,但它们都有点摆弄:

http://php.net/manual/en/function.gzopen.php#105676

http://php.net/manual/en/function.gzdecode.php#112200

我确实设法获得了一个纯粹的内存解决方案,但由于无法使用流,因此会发生不必要的复制:

// works (stream + string)
dd(gzdecode(file_get_contents('php://input')));

// works (stream + file)
dd(stream_get_contents(gzopen(storage_path() . '/' . 'myfile.gz', 'rb')));

// works (stream + file)
dd(file_get_contents('compress.zlib://' . storage_path() . '/' . 'myfile.gz'));

// doesn't work (stream)
dd(stream_get_contents(gzopen('php://input', 'rb')));

// doesn't work (stream + filter)
dd(file_get_contents('compress.zlib://php://input'));

如果没有一个工作示例,我必须假设 PHP的zip实现不完整,因为它无法在流上运行。如果有人有更多信息,我很乐意再次访问。请发布任何通过流实现压缩上传/下载的示例或存储库,谢谢!