Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: dekompresja (gzip) strumienia http
Forum PHP.pl > Forum > PHP
pi_r
W skrypcie w pewnym momencie muszę pobrać wiekszą ilość danych z serwera http. Aby usprawnić prace skryptu chcę pobierać z serwera skompresowane dane, wysyłam więc w nagłówku :
Kod
Accept-Encoding: gzip

W odpowiedzi otrzymuje:
Kod
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 25150
Content-Type: text/html


Następnie pobieram podaną ilość danych do stringa.
Problem zaczyna się, gdy chce dekodowac otrzymane dane, nie radzi z tym sobie funkcja gzuncompress() generując nastepujący błąd:
Kod
Warning: gzuncompress(): data error in [...]update.php on line 113


Efektów także nie widać gdy czytam za pomoca gzread() bezpośrednio z gniazda (zamiast kodu html pojawiają się losowe znaki).

Ktoś zna może jakieś inne rozwiazanie? A może ja gdzieś robię błąd? ;-)
SongoQ
Co masz w lini 113?

Wyslij kawalek kodu jak to robisz bedzie latwiej zidentyfikowac blad.
pi_r
W małym uproszczeniu:

  1. <?php
  2.  
  3. $p = fsockopen($host, 80); 
  4.  
  5. fputs($p, $ask);  // wysylam zapytanie
  6.  
  7. do {  
  8. $line=fgets($p, 1024);  // odczytuje odpowiedz
  9.  
  10.  ...  // nieistotne, przetwarzanie nagłówków itp.
  11.  
  12. } while ( $line != &#092;"rn\" );
  13.  
  14. $file=fread($p,$length); // probowalem takze z gzread($p,$length);
  15.  
  16. $file=gzuncompress($file);  // jesli nie uzylem wczesniej gzread(); BTW: jest to linia 113
  17.  
  18.  
  19. ?>


Dodam, ze bez kompresji jest wszystko ok.

EDIT:
Problem rozwiązany po przejrzeniu RFC ;-)
1: Dane należy pobierac za pomocą stream_get_contents() zamiast fread(), ponieważ ta druga jest "binarnie bezpieczna"
2: Należy "obciąć" nagłówek, w wielkości 10 bajtów *
3: Należy użyć funkcji gzinflate() do zdekodowania danych

*może być dluższy, ale to już odsyłam do rfc:
http://www.gzip.org/zlib/rfc-gzip.html#file-format

Przykładowy poprawny kod:

  1. <?php
  2.  
  3. $plik = stream_get_contents($f, $length); // Pobieramy dane ze strumienia
  4. $plik = substr($plik, 10); // obcinamy naglowek
  5. $plik = gzinflate($plik); // dekodujemy
  6.  
  7. ?>
dopy
Aktualnie pracuje nad rozpracowaniem tego problemu i niestety zastosowalem sie do rad powyzej, ale i tak coś jest nie tak.

Jak tobie następująco:
- pobieram z socketa poprzez fgets (serwer nie ma php5, wiec czym by pobierac w php4?) do zmiennej
- dziele zmienna poprzez explode, odliczam sobie dlugosc naglowkow
- ucinam naglowki ze zmiennej
- przekazuje zmienna do dekompresji

I to co mi zwraca troche mnie zadziwia - nie mam bledu o zlych danych przekazanych do skryptu, nie ma tez innych komunikatow, jedn zwraca mi...
Cytat
XP


W którym momencie popełniem błąd ?
Pozdrawiam.


------------edit:

Cytat
When retrieving mod_gzip'ed content and using gzinflate() to decode the data, be sure to strip the first 10 chars from the retrieved content.

$dec = gzinflate(substr($enc,10));


tak mowi manual, jednak jak ucinam to 10 znakow, to otrzymuje blad o blednych danych...
NuLL
@pi_r - zmien naglowek Content-Type - to co wysylasz to nie jest HTML smile.gif Przegladarka to przyjmuje jako HTML a powinna to przepuscic jako dane binarne przeciez smile.gif
dopy
Egh męcze się z tym juz 3 dzień - czuje że robie jakiś głupi błąd... Może ktoś jednak wie co robie źle ?

+ edit:
No nie wierze ze jest to problem nie do rozwiązania :/ Napisałem nawet na 3 zagranicznych forach i wszędzie w moim temacie cisza...

+ rozwiązanie
Po naprawde ciężkich poszukiwaniach, przypadkiem trafiłem na grupy dyskusyjne google, czytając natrafiłem na rozwiązanie:
  1. <?php
  2.  
  3. // my server sends gzipped data if client allows
  4. $url = "www.byteshift.de";
  5.  
  6. function gzdecode($string){
  7. $string = substr($string, 10);
  8. return gzinflate($string);
  9. }
  10.  
  11. function get_gzipped_data($url){
  12. $http_response = '';
  13. $fp = fsockopen($url, 80);
  14. fputs($fp, "GET / HTTP/1.1rn");
  15. fputs($fp, "Accept-Encoding: gziprn");
  16.  
  17. fputs($fp, "Host: $urlrnrn");
  18. while (!feof($fp))
  19. $http_response .= fgets($fp, 128);
  20. fclose($fp);
  21. return $http_response;
  22. }
  23.  
  24. preg_match("/^(.+)r?nr?nw+r?n(.+)$/s",
  25.  get_gzipped_data($url),
  26.  $matches);
  27. $header = $matches[1];
  28. $body  = $matches[2];
  29. $html  = gzdecode($body);
  30. $strlen_uncomp = strlen(file_get_contents("http://$url/"));
  31. $strlen_decomp = strlen($body);
  32.  
  33. echo "
  34. strlen_uncomp: $strlen_uncomp Kb
  35. strlen_decomp: $strlen_decomp Kb
  36. =============================
  37. $html
  38. ";
  39. ?>


W zasadzie pewnie chodzi tutaj głównie o sposób rozdzielenia od nagłówków, ale ważne że działa. To tak dla przyszłych pokoleń.
Pozdrawiam.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.