PHP: read and present a PDF file to download via PHP is generating corrupted files in some cases
I am using the following to read and present a PDF file to the user:
$file='file.pdf';
$filepath="/path-to-download-folder/$file";
if(!is_file($filepath)) die('Ops!');
$f=fopen($filepath,'r');
if($f){
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Content-Type: '.mime_content_type($filepath));
header('Content-Length: '.filesize($filepath));
header('Content-Disposition: attachment; filename="'.$file.'"');
fpassthru($f);
}else die("Ops!");
fclose($f);
However some folks are reporting that the PDF file is corrupted when they try to open it.
Am I doing something wrong or forgetting some important header? Is there a better way to achieve the same?
UPDATE:
I sent the PDF file via email and the users got to open the file. So it must be something with the way PHP and Nginx are serving the file.
So I turned off gzip on Nginx but the error continues.
I also applied the tips bellow so the code is now like this:
$file='file.pdf';
$filepath="/path-to-download-folder/$file";
if(!file_exists($filepath)){
header('HTTP/1.1 404 Not Found');
exit;
}elseif(!is_file($filepath) or !is_readable($filepath)){
header('HTTP/1.1 403 Forbidden');
exit;
}else{
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Content-Type: '.mime_content_type($filepath));
header('Content-Length: '.filesize($filepath));
header('Content-Disposition: attachment; filename="'.$file.'"');
set_time_limit(0); // Big files/slow connections may result in incomplete downloads
readfile($filepath);
die;
}
However I still am receiving this error: http://mlkshk.com/r/8FGS
UPDATE:
I made a diff among the files:
compare -verbose -debug coder Dicas1.pdf Dicas1A.pdf -compose src OUT.tmp
With this output:
"gs" -q -dQUIET -dPARAN开发者_开发百科OIDSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 "-sDEVICE=pnmraw" -dTextAlphaBits=4 -dGraphicsAlphaBits=4 "-r72x72" "-sOutputFile=/tmp/magick-XXuCqreY" "-f/tmp/magick-XXNkQbcr" "-f/tmp/magick-XXoICX9T"
**** Warning: File has some garbage before %PDF- .
**** Error: Cannot find a %%EOF marker anywhere in the file.
**** Warning: An error occurred while reading an XREF table.
**** The file has been damaged. This may have been caused
**** by a problem while converting or transfering the file.
**** Ghostscript will attempt to recover the data.
So I opened it in Leafpad:
Original file:
%PDF-1.5
%Çì¢
1 0 obj
<<
/Type /Catalog
/Outlines 3 0 R
/Pages 4 0 R
/Dests 5 0 R
/AcroForm 6 0 R
/Names 7 0 R
/Threads 8 0 R
/PageLayout /SinglePage
/ViewerPreferences
<<
/PageDirection /L2R
>>
>>
endobj
2 0 obj
<<
/Creator (Scribus 1.5.0.svn)
/Producer (Scribus PDF Library 1.5.0.svn)
/Title <>
/Author <>
/Subject <>
/Keywords <>
/CreationDate (D:20111016162546Z)
/ModDate (D:20111016162546Z)
/Trapped /False
>>
endobj
9 0 obj
<<
/Length 154566
/Length1 275572
/Filter /FlateDecode
>>
stream
File served by PHP and Nginx:
6Wm931Ja.G46X5WID+1K9G93F.3FD.2IXCWm<br>%PDF-1.5
%Çì¢
1 0 obj
<<
/Type /Catalog
/Outlines 3 0 R
/Pages 4 0 R
/Dests 5 0 R
/AcroForm 6 0 R
/Names 7 0 R
/Threads 8 0 R
/PageLayout /SinglePage
/ViewerPreferences
<<
/PageDirection /L2R
>>
>>
endobj
2 0 obj
<<
/Creator (Scribus 1.5.0.svn)
/Producer (Scribus PDF Library 1.5.0.svn)
/Title <>
/Author <>
/Subject <>
/Keywords <>
/CreationDate (D:20111016162546Z)
/ModDate (D:20111016162546Z)
/Trapped /False
>>
endobj
9 0 obj
<<
/Length 154566
/Length1 275572
/Filter /FlateDecode
>>
stream
So this is the garbage PHP is puting in the begining of the file:
6Wm931Ja.G46X5WID+1K9G93F.3FD.2IXCWm<br>
And I found that a session value was being echoed in another part of the code and that was the real problem since the beginning.
Thanks.
By far and away the most common cause of problems like this is leading/trailing whitespace before/after the <?php ?>
tags. Note that you probably don't need a ?>
tag, which helps avoid this problem.
Next most common cause is forgetting to call exit
/die
after outputting the file.
Please check both of the above points.
EDIT
Here is how I would write that code:
$file = 'file.pdf';
$filepath = "/path-to-download-folder/$file";
if (!file_exists($filepath)) {
header('HTTP/1.1 404 Not Found');
exit;
} else if (!is_file($filepath) || !is_readable($filepath)) {
header('HTTP/1.1 403 Forbidden');
exit;
}
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Content-Type: '.mime_content_type($filepath));
header('Content-Length: '.filesize($filepath));
header('Content-Disposition: attachment; filename="'.$file.'"');
set_time_limit(0); // Big files/slow connections may result in incomplete downloads
readfile($filepath);
exit;
Also, you should open the PDF file in binary mode:
$f = fopen($filepath, 'rb');
(Or you could just use readfile()
.)
精彩评论