2013-04-08 18 views
7

Mam problem, który wielokrotnie pojawiał się na SO, ale nie mogę znaleźć rozwiązania do mojego! Próbuję dostarczyć plik PDF do klienta bez otwierania go w przeglądarce, pobierania plików, ale jest uszkodzony, gdy go otworzę i brakuje sporo bajtów z oryginalnego pliku. Próbowałem już kilku takich metod pobierania pliku, ale pokażę ci tylko najnowsze, z których korzystałem i mam nadzieję, że otrzymam informację zwrotną.Wymuszenie pobrania pliku PDF, uszkodzony plik

Mam również otwarty pobrany plik PDF w edytorze tekstu i nie ma błędów PHP na górze tego, co widzę!

Jestem również świadomy, że readfile() jest znacznie szybszy, ale do celów testowych jestem zdesperowany, aby uzyskać wszystko działa, więc użyłem podejścia while (! Feof())!

wystarczająco Zresztą wędrówki, herezje kod (zaczerpnięte z why my downloaded file is alwayes damaged or corrupted?):

$file  = __DIR__ . '/reports/somepdf.pdf'; 
$basename = basename($file); 
$length = sprintf("%u", filesize($file)); 

header('Content-Description: File Transfer'); 
header('Content-Type: application/octet-stream'); 
header('Content-Disposition: attachment; filename="' . $basename . '"'); 
header('Content-Transfer-Encoding: binary'); 
header('Connection: Keep-Alive'); 
header('Expires: 0'); 
header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
header('Pragma: public'); 
header('Content-Length: ' . $length); 

ob_clean(); 
set_time_limit(0); 
readfile($file); 

również zauważyć, była różnica w wielkości pliku:

Original: 351,873 bytes 
Downloaded: 329,163 bytes 
+1

Próbowałaś 'ReadFile()'? – barbashov

+0

@ DavidC799: Jeśli chcesz przedyskutować odpowiedź na poprzednie pytanie, zostaw tutaj komentarz. Nie tylko upuść tutaj kod i powiedz nam "to nie działa". Pamiętaj, że tylko ktoś inny zaakceptował tę odpowiedź, to nie znaczy, że kod też musi działać dla ciebie. W celu testowania zredukuj kod do niezbędnego minimum, aby sprowokować problem. Na przykład. nie ma funkcji, po prostu na sztywno nazwaną nazwę pliku. Użyj pliku readfile. – hakre

+0

@barbashov tak Próbowałem kilka różnych metod. – DavidC799

Odpowiedz

7

Upewnij się, że nie używasz żadnej kompresji wyjściowe buforujące procedury obsługi, takie jak ob_gzhandler. Miałem podobny przypadek i musiałem wyłączyć buforowanie wyjścia, aby działał prawidłowo

+0

Rzeczywiście, naprawdę jestem! Gdy o tym wspomniałeś, zobaczyłem, że ktoś inny wspomniał o tym w innym poście. Spróbuję kilka rzeczy i dam ci znać, jak to działa. Przepraszam za kłopot! – DavidC799

+0

Sukces! Wielkie dzięki za twoją pomoc, zawsze coś tak prostego :( – DavidC799

+0

@ DavidC799: Cóż, po prostu przeczytaj inne pytania, większość odpowiedzi na stronie już musisz tylko je znaleźć;) – hakre

6

Używasz ob_gzhandler na buforze wyjściowym.

Działa za pomocą fragmentów kodu gzencoding pliku wyjściowego. Wyjście to jest wtedy strumieniem zakodowanych fragmentów.

Każdy fragment musi pobrać kilka bajtów, aby uzyskać kodowanie, więc dane wyjściowe są nieco buforowane, dopóki nie będzie dostępnych wystarczających bajtów.

Jednak na końcu skryptu odrzucasz pozostały bufor zamiast go spłukiwać.

Użyj ob_end_flush() zamiast ob_clean(), a plik przechodzi całkowicie i nie jest uszkodzony.

Używasz kodowania transferu ob_gzhandler, gdy przesyłane pliki nie mają żadnych problemów, jeśli nie zniszczysz bufora wyjściowego, zanim mogło to być zrobione.

Jest to również to samo, jeśli inne buforowanie wyjścia, które działa, zostało włączone włączone.

Przykładowy kod:

$file  = __DIR__ . '/somepdf.pdf'; 
$basename = basename($file); 
$length = sprintf("%u", filesize($file)); 

header('Content-Description: File Transfer'); 
header('Content-Type: application/octet-stream'); 
header('Content-Disposition: attachment; filename="' . $basename . '"'); 
header('Content-Transfer-Encoding: binary'); 
header('Connection: Keep-Alive'); 
header('Expires: 0'); 
header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
header('Pragma: public'); 
header('Content-Length: ' . $length); 

ob_end_flush(); // <--- instead of ob_clean() 

set_time_limit(0); 
readfile($file); 

return; 

(FYI: faktycznie nawet ob_end_flush(); nie jest konieczne, ważne jest to, aby nie tylko kopać wyjściowy bufor zanim mogła zrobić to praca)

+0

Mogę potwierdzić, że kod hakre działa zgodnie z oczekiwaniami; dziękuję za szczegółowe wyjaśnienie. – periklis

+0

Również właśnie sprawdziłem źródło readfile() w PHP i powinieneś (jeśli możesz) zawsze używać go zamiast robić własne odczyt fopen/buffered jak w pytaniu. 'readfile()' jest znacznie lepszy dla wyników pobierania plików, ponieważ może korzystać z korzyści w SAPI, które nie są możliwe w kodzie użytkownika. – hakre

-1

I walczyłem z użyciem content-disposition, aby przesłać PDF do pobrania na dwa dni, zanim znajdę rozwiązanie mojego problemu. Moje pliki PDF również były mniejsze i uszkodzone - jednak mogłem je otworzyć w Windows Preview - po prostu nie Adobe. Po wielu wykrytych problemach odkryłem, że Adobe oczekuje pliku% PDF w pierwszych 1024 bajtach pliku. Robiłem wszystkie moje sprawdzenia typów plików w moim kodzie php przed utworzeniem nagłówków. Wyjąłem większość kodu przed nagłówkami, a mój plik PDF został naprawiony.

nie Możecie być ustawienie go w ten sam sposób co ja, ale może to być ten sam problem:

http://helpx.adobe.com/acrobat/kb/pdf-error-1015-11001-update.html

Powiązane problemy