1つの単一のXMLファイルを含むzipファイルのBASE64文字列があります。
ディスク上のファイルを処理せずにXMLファイルのコンテンツを取得する方法について何かアイデアはありますか?
XMLには1〜5kしかないので、プロセス全体をメモリに保持したいと思います。
zipを記述し、XMLを抽出してから、それをロードしてすべてを削除しなければならないのは面倒です。
1つの単一のXMLファイルを含むzipファイルのBASE64文字列があります。
ディスク上のファイルを処理せずにXMLファイルのコンテンツを取得する方法について何かアイデアはありますか?
XMLには1〜5kしかないので、プロセス全体をメモリに保持したいと思います。
zipを記述し、XMLを抽出してから、それをロードしてすべてを削除しなければならないのは面倒です。
私は同様の問題を抱えていました、私はそれを手動で行うことになりました。
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);
数時間の調査の後、一時ファイルなしでzipを処理することは驚くほど不可能だと思います。
php://memory
のような関数で読み取ることができないストリームであるため、最初の試行は機能しません。コメントには、この問題のドキュメントが不足しているphp-bugtrackerへのリンクがあります。file_get_contents()
ZipArchive::open()
ZipArchive
、::getStream()
マニュアルに記載されているように、開いているファイルの読み取り操作のみをサポートします。したがって、それを使用してオンザフライでアーカイブを構築することはできません。zip://
ラッパーも読み取り専用です:fopen()ラッパーを使用してZIPファイルを作成します私はまた、他の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")
しかし、私にとっては、マニュアルにそのような例があったとしても、それらはまったく機能しません。したがって、ピルを飲み込んで一時ファイルを作成する必要があります。
元の回答:
これは一時的な保存の方法にすぎません。zipの処理とxmlの解析を自分で管理してください。
php php://memory
(doc)ラッパーを使用します。これはメモリに保存されているため、小さなファイルにのみ役立つことに注意してください。それ以外の場合は、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'));
toster-cxは正しかったので、彼にポイントを与える必要があります。これは、zipがバイト配列(バイナリ)として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;
}
.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));
Linuxで実行していて、システムを管理している場合。tmpfsを使用して小さなRAMディスクをマウントできます。標準のfile_get/putとZipArchive関数が機能しますが、ディスクに書き込まず、メモリに書き込みます。永続的に準備するために、fstabは次のようになります。
/media/ramdisk tmpfs nodev,nosuid,noexec,nodiratime,size=2M 0 0
それに応じてサイズと場所を設定し、自分に合ったものにします。一度に処理するファイルが大量にある場合を除いて、phpを使用してRAMディスクをマウントし、使用後に削除する(特権がある場合でも)場合は、ディスクに書き込むよりも効率が悪い可能性があります。これは純粋なphpソリューションではありませんが、移植性もありません。使用後に「ファイル」を削除するか、OSに古いファイルをクリーンアップさせる必要があります。それらは、RAMディスクの再起動または再マウントを超えても持続しません。
zip likeからファイルのコンテンツを読み取りたい場合は、内部のxmlを参照してください。これを使用して、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;
}
}
このアイデアは、toster-cx
不正な形式のzipファイルにアプローチする場合にも非常に役立ちます。
ヘッダーにデータが欠落しているものがあったので、彼の方法を使用して中央ディレクトリファイルのヘッダーを抽出する必要がありました。
$CDFHoffset = strpos( $zipFile, "\x50\x4b\x01\x02" );
$CDFH = unpack( "Vsig/vverby/vverex/vflag/vmeth/vmodt/vmodd/Vcrc/Vcsize/Vsize/vnamelen/vexlen", substr( $zipFile, $CDFHoffset, 46 ) );