8

I have a problem with reading pdf file in Chrome by using PHP.

The following code is how I do in PHP

$path = "actually file path";
header("Pragma: public");
header("Expires: 0");
header("Content-type: $content_type");
header('Cache-Control: private', FALSE);
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Disposition: inline; filename=\"$filename\"");
header('Content-Transfer-Encoding: binary');
header('Content-Length' . filesize($path));
ob_clean();
flush();
readfile($path);

In here, I set the Content-Disposition to inline. Because I want to display the pdf file if user browser have build-in pdf viewer plugin. As you may know, Chrome has build-in pdf viewer.

The problem is I have bunch of pdf files on the server. Only some of them can be viewed by Chrome. I can't figure out why others can not work the same way. I have checked the permission of each files. It looks like not the permission problem.

Is there anyone know what the problem is? Thank you.

Frankie
  • 24,627
  • 10
  • 79
  • 121
easycoder
  • 305
  • 2
  • 3
  • 12
  • 2
    Change to forcing a download (Content-disposition: attachment/Content-type: application/octet-stream), download/save the good PDF and a bad pdf, and compare what got saved to what's on the server. – Marc B Apr 14 '11 at 23:21
  • @Marc I try that. Both of them can be downloaded and look like the same. I also compare that with the file in the server. They are the same. When I switch back to Content-disposition: inline. It just doesn't work. :( I even compare the response header. They are the same. – easycoder Apr 14 '11 at 23:30
  • What happens if you try to view one directly instead of going through your script? – Marc B Apr 14 '11 at 23:33
  • @Marc you can view that directly without going through the script. – easycoder Apr 14 '11 at 23:36
  • Then what's the point of the script? – Marc B Apr 15 '11 at 14:22
  • @Marc to do some permission check... – easycoder Apr 18 '11 at 17:47
  • But if the files are directly accessible, the script can be bypassed and the files downloaded anyways. – Marc B Apr 18 '11 at 18:26
  • @Marc yes. but I will change that can not be access directly after I make sure I can do that in this way. :) – easycoder Apr 20 '11 at 19:25
  • HEY! Still gettting the error? yeah, i was too. [GO TRY Kal's SOLUTION!](https://stackoverflow.com/questions/5670785/chrome-has-failed-to-load-pdf-document-error-message-on-inline-pdfs#answer-26874965) below. – WEBjuju Feb 21 '21 at 23:23

8 Answers8

12

I've been wrestling with this same issue. This is as close as I got to consistent results across browsers. I think that the reason you could be having problems is if some PDF's are too large for readfile() to handle correctly. Try this:

$file = "path_to_file";
$fp = fopen($file, "r") ;

header("Cache-Control: maxage=1");
header("Pragma: public");
header("Content-type: application/pdf");
header("Content-Disposition: inline; filename=".$myFileName."");
header("Content-Description: PHP Generated Data");
header("Content-Transfer-Encoding: binary");
header('Content-Length:' . filesize($file));
ob_clean();
flush();
while (!feof($fp)) {
   $buff = fread($fp, 1024);
   print $buff;
}
exit;
smhg
  • 2,159
  • 19
  • 26
mingala
  • 284
  • 3
  • 7
  • 1
    Does this not work for any browser or just Chrome? You could try modifying the size of the buffer from 1024 to something smaller. If $file is set to full path to your document this should work. Also, note the $myFileName variable in one of the headers. That needs to be set or removed. – mingala Apr 26 '11 at 17:46
  • 1
    I seem to be getting an infinite load screen. – Base Desire Sep 24 '13 at 17:42
  • 1
    Good call on the ob_clean() and flush() – eklingen May 31 '16 at 16:32
  • This solution worked well for me, although i am getting the content for the PDF from a database, I have used file_get_contents() to get the content from the PDF when entering it into the DB. – user1620090 Jun 30 '16 at 14:01
  • I'm having an issue here. The title of my pdf is not as i've set in the header header("Content-Disposition: inline; filename=".$myFileName.""); Any clue how that can be done? – Deepak Singh Jul 04 '18 at 13:46
2

For me adding the following header fixed this annoying Chrome bug (?):

    header('HTTP/1.1 200 OK');
1

I had similar issue but I noticed the order matters. Seems that ; filename= must have quotes around it, Content-Disposition: attachment Try this:

    $file = "/files/test.pdf";
    $finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
    $mime = finfo_file($finfo, $file);

    header('Pragma: public');
    header('Expires: 0');
    header('Content-Type: $mime');
    header('Content-Description: File Transfer');
    header('Content-Disposition: attachment; filename="'.basename($file).'"'));
    header('Content-Transfer-Encoding: binary');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Content-Length' . filesize($file));
    ob_clean();
    flush();
    readfile($file);
Kal
  • 948
  • 17
  • 30
  • Yes, download opens from finder, but not the Chrome download bar (unless using "system viewer") produced "Failed to load PDF document". After dozens of examples _including solutions on this page_...this is the one that stopped the CHROME "Error Failed to load PDF document. Reload" popup. here is what i originally started with: `header('HTTP/1.1 200 OK'); header('Content-type:application/pdf'); header('Content-Disposition:attachment; filename="'.basename($f).'"');` and worked fine in Firefox. – WEBjuju Feb 21 '21 at 23:22
1

i've fixed this way

$path = 'path to PDF file';
header("Content-Length: " . filesize ( $path ) ); 
header("Content-type: application/pdf"); 
header("Content-disposition: inline; filename=".basename($path));
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
ob_clean();
flush();
readfile($path);
1

Had the same problem, chrome didn't display the inline PDF, stuck at loading. The solution was to add header('Accept-Ranges: bytes').

My complete code:

header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="'.$title.'"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($file));
header('Accept-Ranges: bytes');
header('Expires: 0');
header('Cache-Control: public, must-revalidate, max-age=0');
xor
  • 11
  • 1
0

After hours wasted this...i added comments to point out that @Kal has the only solution that worked. But somehow that's not enough...this is such an impossible and frustrating problem when Chrome does this:

Error Failed to load PDF document. Reload

enter image description here

Here is the diff that ended the torture.

-        // Waste time with chrome:
-        header("Content-type:application/pdf");
-        header("Content-Disposition:attachment;filename=$file_basename");
-        readfile($file);
         exit();
---------------------------

+        // Deliver the file:
+        header('Pragma: public');
+        header('Expires: 0');
+        header('Content-Type: $mime');
+        header('Content-Description: File Transfer');
+        header('Content-Disposition: attachment; filename="'.basename($file).'"');
+        header('Content-Transfer-Encoding: binary');
+        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+        header('Content-Length'.filesize($file));
+        ob_clean();
+        flush();
+        readfile($file);
         exit();

For about thirty minutes i fooled with various variations of this...but i could not pin it down to "Add HTTP 200", not to "add bytes", not to "quote your filename", not to "separate the file ending". None of those worked.

(Thank you again @Kal).

WEBjuju
  • 5,797
  • 4
  • 27
  • 36
0

I was having this issue, struggled for almost 6 hours and finally got it working. My solution is similar to the above answers but the above answers are not completed. There are three steps to solve this issue.

Step 1. Go to php.ini file and add this line.

output_buffering = False

Step 2. This error comes if you are opening a large PDF file. So, to solve this, just before adding headers, make sure you put these two lines.

set_time_limit(0); 
ini_set('memory_limit', '100M'); //the memory limit can be more or less depending on your file

Step 3. Add below headers and the code to read the file, so the final code would like this.

set_time_limit(0); 
ini_set('memory_limit', '100M');

$file = "path/to/file.pdf";
header('Content-Type: application/pdf');
header('Content-Disposition: inline; 
filename="yourfilename.pdf"'); //not the path but just the name
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($file));
header('Accept-Ranges: bytes');
header('Expires: 0');
header('Cache-Control: public, must-revalidate, max-age=0');
ob_clean();
flush();
readfile($file);
exit();

100% working solution. If you have any issues, let me know :)

za_ali33
  • 366
  • 2
  • 9
0

None of the solutions above worked for me, but the bellow code works. All you need to do is to send the file by chunk.

$fileSize = filesize($filePath);
header("Expires: 0");
header("Content-Type: application/pdf");
header("Content-Description: File Transfer");
header('Content-Disposition: inline; filename="' . $yourFileName.pdf . '"');
header("Cache-Control: private, max-age=0, must-revalidate");
header("Content-Length: $fileSize");
header("Accept-Ranges: bytes");
     
//Flush the output buffer immediately
//The following three lines is important. Without them, it will not load large files:
ob_end_flush();
ob_flush();
flush();

$handle = fopen($filePath, "r");
$chunkSize = 2024 * 2024; // 1MB (Adjust as needed)
while (!feof($handle)) {
    echo fread($handle, $chunkSize);
    ob_flush();
    flush();
}
fclose($handle);
exit();
ceci
  • 46
  • 4
  • I edited my answer. The code is not from GPT and I only used it to help me solve the problem. The code is based from the others posted from here and it does really work on my end. @EricAya – ceci Jul 23 '23 at 09:15