2013-02-28 17 views
20

Mam ciąg BASE64 pliku zip, który zawiera jeden plik XML.Wyodrębnij plik z ciągu ZIP

Jakieś pomysły, w jaki sposób mogę uzyskać zawartość pliku XML bez konieczności zajmowania się plikami na dysku?

Chciałbym bardzo, aby cały proces w pamięci, ponieważ XML ma tylko 1-5k.

Byłoby denerwujące, aby napisać kod pocztowy, wyodrębnić XML, a następnie załadować go i usunąć wszystko.

Odpowiedz

15

po kilku godzinach badań Myślę, że to nie jest możliwe, należy dotykać zaskakująco zip bez pliku tymczasowego:

  1. pierwsza próba z php://memory nie będzie działać, beacuse to strumień, który nie może być odczytany przez funkcje jak file_get_contents() lub ZipArchive::open(). W komentarzach znajduje się link do php-bugtracker z powodu braku dokumentacji tego problemu.
  2. Istnieje wsparcie strumienia ZipArchive z ::getStream(), ale jak stwierdzono w instrukcji, obsługuje tylko czytanie na otwartym pliku. Więc nie możesz z tym zbudować archiwum "w locie".
  3. zip:// owinięcie jest również read-only: Create ZIP file with fopen() wrapper
  4. Zrobiłem też kilka prób z innymi owijarki PHP/protocolls jak

    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") 
    

    ale dla mnie one nie działają w ogóle, nawet jeśli są takie przykłady w podręczniku. Musisz więc połknąć pigułkę i stworzyć tymczasowy plik.


Original Odpowiedź:

To jest właśnie sposób czasowego składowania. Mam nadzieję, że samodzielnie zarządzasz obsługą zip i parsowaniem xml.

Użyj opakowania typu php php://memory (doc). Należy pamiętać, że jest to przydatne tylko dla małych plików, ponieważ jest to oczywiście zapisane w pamięci. W przeciwnym razie użyj zamiast tego 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')); 
+1

Mam problem. Otwarcie zipem nie powiedzie się, mimo że wydaje się, że zapisał plik zip do pamięci. Próbowałem file_get_contents z php: // memory i jest string (0) ... – transilvlad

+2

Tak, przepraszam - mój kod jest w tym przypadku błędny. Metody file_put_contents() nie działają na strumieniach i/o: https://bugs.php.net/bug.php?id=50886&edit=2. Tak więc musisz pracować z 'fopen()', 'fwrite()' i 'stream_get_contents()', aby napisać/przeczytać do 'php: // memory' – HenningCash

+1

Podobno już się dowiedziałeś: To niemożliwe. Właśnie dodałem kilka powodów do odpowiedzi. Powodzenia w każdym razie! – HenningCash

-1

jeśli chcesz przeczytać zawartość pliku z zip jak i XML wewnątrz ty powinien spojrzeć na tę Używam go policzyć słowa z docx (wich jest 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; 
    } 
} 
+0

Mam ciąg BASE64 archiwum Zip Nie chcę pisać na dysku, aby rozpakować. – transilvlad

1

Jeśli znasz nazwę pliku wewnątrz .zip, tylko to zrobić:

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

Jeśli masz zwykły sznurek, po prostu to zrobić:

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

[edytuj] Dokumentacja jest dostępna: http://www.php.net/manual/en/wrappers.php

Z komentarzy: jeśli nie masz zakodowanego ciągu base64, musisz urkać je() przed użyciem opakowania data://.

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

[edit 2] Nawet jeśli już znalazł rozwiązanie z plikiem, istnieje rozwiązanie (do testu) nie widzę w swojej odpowiedzi:

<?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)); 
+2

Właśnie sprawdziłem twój drugi przykład. '$ xml' wydaje się być danymi binarnymi (w zasadzie zip), a nie wyodrębnionym plikiem XML. – pixelistik

+1

Testowałem na ten sam wynik. – transilvlad

+0

Hum. Może powinieneś połączyć zip: // i dane: // zamiast compress.zlib. – Savageman

10

Miałem podobny problem, skończyło się robienie tego ręcznie.
https://www.pkware.com/documents/casestudies/APPNOTE.TXT

Wyciąga pojedynczy plik (tylko pierwszy), nie sprawdza błędów/crc, zakłada, że ​​deflate zostało użyte.

// 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); 
2

toster-cx miał rację, należy przyznać mu punkty, to jest przykładem, gdzie zip pochodzi z odpowiedzi mydło jako tablicy bajtów (binarnym), zawartość jest plikiem 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; 
} 
Powiązane problemy