从ZIP字符串中提取一个文件

问题描述 投票:20回答:6

我有一个包含一个单独的XML文件的zip文件的BASE64字符串。

我如何能得到XML文件的内容,而无需处理磁盘上的文件的任何想法?

我很想让整个过程在存储器中作为XML只有1-5k。

这将是恼人的有写的zip,提取XML,然后加载它,并删除所有内容。

php
6个回答
16
投票

研究几个小时后,我认为这是令人惊讶的不是可能做处理拉链没有临时文件:

  1. 第一次尝试与php://memory都不行,怎么一回事,因为它是无法通过像file_get_contents()ZipArchive::open()功能来读取流。在意见是对的PHP错误追踪系统的链接缺乏这一问题的文件。
  2. 没有与ZipArchive流支持::getStream()但按照手册中的规定,它仅支持一个打开的文件读取操作。所以你不能建立一个归档与上即时。
  3. zip://包装也只读:Create ZIP file with fopen() wrapper
  4. 我也做了一些尝试与其他PHP包装/ protocolls像 file_get_contents("zip://data://text/plain;base64,{$base64_string}#test.txt") $zip->open("php://filter/read=convert.base64-decode/resource={$base64_string}") $zip->open("php://filter/read=/resource=php://memory") 但对我来说他们没有在所有的工作,即使有这样的手册中的例子。所以,你必须吞下药丸,并创建一个临时文件。

原来的答案:

这是临时存储的原来的样子。我希望你管理你自己的XML的拉链处理和分析。

使用PHP php://memorydoc)包装。要知道,这仅仅是有用的小文件,因为它存储在存储器 - 明显。否则,使用php://temp代替。

<?php

// the decoded content of your zip file
$text = 'base64 _decoded_ zip content';

// this will empty the memory and appen your zip content
$written = file_put_contents('php://memory', $text);

// bytes written to memory
var_dump($written);

// new instance of the ZipArchive
$zip = new ZipArchive;

// success of the archive reading
var_dump(true === $zip->open('php://memory'));

12
投票

我有一个类似的问题,我最后做手工。 https://www.pkware.com/documents/casestudies/APPNOTE.TXT

这提取单个文件(只是第一个),无误差/ CRC检查,假定使用DEFLATE。

// zip in a string
$data = file_get_contents('test.zip');

// magic
$head = unpack("Vsig/vver/vflag/vmeth/vmodt/vmodd/Vcrc/Vcsize/Vsize/vnamelen/vexlen", substr($data,0,30));
$filename = substr($data,30,$head['namelen']);
$raw = gzinflate(substr($data,30+$head['namelen']+$head['exlen'],$head['csize']));

// first file uncompressed and ready to use
file_put_contents($filename,$raw);

3
投票

toster-CX说得对,你要奖励他的点,这是那里的拉链来自SOAP响应作为一个字节数组(二进制)为例,内容是一个XML文件:

$objResponse = $objClient->__soapCall("sendBill",array(parameters));
$fileData=unzipByteArray($objResponse->applicationResponse);
header("Content-type: text/xml");
echo $fileData;
function unzipByteArray($data){
  /*this firts is a directory*/
  $head = unpack("Vsig/vver/vflag/vmeth/vmodt/vmodd/Vcrc/Vcsize/Vsize/vnamelen/vexlen", substr($data,0,30));
  $filename = substr($data,30,$head['namelen']);
  $if=30+$head['namelen']+$head['exlen']+$head['csize'];
 /*this second is the actua file*/
  $head = unpack("Vsig/vver/vflag/vmeth/vmodt/vmodd/Vcrc/Vcsize/Vsize/vnamelen/vexlen", substr($data,$if,30));
  $raw = gzinflate(substr($data,$if+$head['namelen']+$head['exlen']+30,$head['csize']));
  /*you can create a loop and continue decompressing more files if the were*/
  return $raw;
}

1
投票

如果你知道的.zip里面的文件名,只是这样做:

<?php
$xml = file_get_contents('zip://./your-zip.zip#your-file.xml');

如果你有一个普通的字符串,只是这样做:

<?php
$xml = file_get_contents('compress.zlib://data://text/plain;base64,'.$base64_encoded_string);

[编辑]文档有:http://www.php.net/manual/en/wrappers.php

从评论:如果你没有一个base64编码字符串,你需要使用data://包装之前来urlencode()它。

<?php
$xml = file_get_contents('compress.zlib://data://text/plain,'.urlencode($text));

[编辑2]即使你已经发现了一个文件的解决方案,有一个解决方案(测试)我没有在你的答案,请参阅:

<?php
$zip = new ZipArchive;
$zip->open('data::text/plain,'.urlencode($base64_decoded_string));
$zip2 = new ZipArchive;
$zip2->open('data::text/plain;base64,'.urlencode($base64_string));

1
投票

如果你是在Linux上运行,并有系统的管理。你可以使用tmpfs的,标准的file_get / put和ZipArchive功能将工作,那么,只是它不写入到磁盘安装一个小的虚拟盘,将其写入内存。把它永久准备,fstab的是一样的东西:

/media/ramdisk tmpfs nodev,nosuid,noexec,nodiratime,size=2M 0 0

所以它适合你设置相应的大小和位置。使用PHP安装一个ramdisk使用完之后将其删除(如果它甚至有权限)可能不仅仅是写入磁盘,除非你有文件数量庞大的一次过处理效率较低。虽然这不是一个纯PHP解决方案,也不是可移植的。您仍然需要使用后删除“文件”,还是有OS清理旧文件。他们将粗了重新启动或RAMDisk的重新装载不会持续。


-1
投票

如果你想读的拉链像和XML里面你768,16看看这个我用它来计算从DOCX字(至极是一个zip文件)的文件内容

if (!function_exists('docx_word_count')) {
    function docx_word_count($filename)
    {
        $zip = new ZipArchive();
        if ($zip->open($filename) === true) {
            if (($index = $zip->locateName('docProps/app.xml')) !== false) {
                $data = $zip->getFromIndex($index);
                $zip->close();
                $xml = new SimpleXMLElement($data);
                return $xml->Words;
            }
            $zip->close();
        }
        return 0;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.