9

I have a PDF export that takes a while to create the PDF. I want the user to be able to click the export link and be presented with a download dialog right away. This way they can start the download and just wait for it to complete. Instead of clicking the link, wait for the generation and then wait for the download again.

Here's a very simple example in PHP:

<?php

header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename=test.pdf');
flush();

// time consuming PDF creation happens here
sleep(15);
echo 'pdf contents would be here';

The idea is to send the appropriate headers, flush() them to the browser, slowly create the PDF and finally send it to the browser.

This works perfectly in chrome. The Download Dialog pops up immeadiately and the sleep is part of the download waiting time.

In Firefox and InternetExplorer this does not work. Those browsers wait the full 15 seconds before showing the download dialog.

Any idea how to make the download dialog pop up immeadiately would be greatly appreciated.

Andreas Gohr
  • 4,617
  • 5
  • 28
  • 45

2 Answers2

3

Some browsers wait for the actual content before showing the download dialog. So, the solution is simple: send some PDF content before creating the PDF content.

Wait a minute. How do you send something before you have it? That sounds like it would require a time machine, right? Don't worry, there is a way to get around it.

PDF content starts with %PDF, thus you simply have to send %PDF before calling flush(). After the PDF creation completes, remove the first 4 bytes of the newly created PDF content before echoing it.

<?php
// disable output buffering
while (@ob_end_clean());

header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename=test.pdf');

// send some content to trigger the download dialog
echo '%PDF';
flush();

// time consuming PDF creation happens here
sleep(15);
$pdfContent = '%PDF-pdf contents would be here';
echo substr($pdfContent, 4);

This solution works in any language because it doesn't rely on any PHP-only feature.

If you want to do the absolute minimum, you can also send 1 byte % and then remove just the first byte before echoing. Same result.

Rei
  • 6,263
  • 14
  • 28
  • That was my guess, too. I tried this already but it doesn't work. Just to be sure, I tried your code in Firefox again. It still waits 15 seconds before popping up the download dialog. – Andreas Gohr Dec 03 '17 at 09:05
  • @AndreasGohr I assumed you're using only `flush()` because you already have your output buffering disabled. The fact that it doesn't work means you haven't. I updated the code to make it work regardless of output buffering configurations. – Rei Dec 03 '17 at 17:35
  • Weird. You're right, I thought I had no output buffering enabled, but with your addition it does work! Thanks a lot! – Andreas Gohr Dec 04 '17 at 14:44
-2

This is a general problem and not related to any particular language. We are making a process to wait for some time until the PDF Generation is being made and then start our Download Process.

So in order to wait for PDF Generation, we will be using a sleep() function to allow the process to wait for a specified period - 15 as mentioned.

sleep(15)

Now we can't flush() the empty content before head the pdf is generated to the browser. So we can send some static content before head and start our flush process.

And after successfully PDF Generation we can then remove the content added before and echo the updated content to the flush() function the browser.

So the overall code would be,

<?php

// Initialize the Basic Header

ob_start(); // Start Buffering
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename=test.pdf');

// Adding content before the PDF Generation Process
echo 'demo';

// Flushing content to the Browser

ob_end_flush();
ob_flush(); 
flush();

// time consuming PDF creation happens here
sleep(15);

$Content = 'demoother pdf content';

// Removind the Added Content
echo substr($Content, 4);

?>
Mohd Belal
  • 1,119
  • 11
  • 23
  • "*So in order to wait for PDF Generation, we will be using a sleep() function*". That's not the purpose of `sleep()` in the question. Not even close. You should read the question again and ask if you still don't understand. – Rei Dec 03 '17 at 19:46