Reputation: 6613
I'm attempting to render a largish html table to pdf with dompdf. There is minimal css styling, but maybe 200 - 300 rows in the table. Each row has 4 td's with basic text.
I can generate a pdf of a smaller table with no issues but a larger table will exhaust memory limits and the script will terminate. What is the best way to approach this? I started a discussion on serverfault and one user suggested spawning a new process so as to not exhaust memory limits of php / apache? Would this be the best way to do this? That leads me to questions about how that would work, in that dompdf currently streams the download to the browser, but I'm assuming if I create a new process to generate the report, I can no longer send the output to the browser for the user to download?
Thanks to anyone who might be able to suggest a good way to tackle this!
Upvotes: 4
Views: 11553
Reputation: 13914
If you render your HTML using a secondary PHP process (e.g. using exec()
) the execution time and memory limits are eased. When rendering in this method you save the rendered PDF to a directory on the web site and redirect the user to the download (or even email them a link if you want to run a rendering queue). Generally I've found that this method does offer modest improvements in speed and memory use.
That doesn't, however, mean the render will perform significantly faster in your situation. Rendering tables with dompdf is resource intensive at present. What might work better, if you can, is to break the document into parts, render each of those parts separately (again using a secondary PHP process), combining the resulting collection of PDFs into a single file (using something like pdftk), then saving the PDF where the user can access it. I've seen a significant performance improvement using this method.
Or go with something like wkhtmltopdf (if you have shell access to your server and are willing to deal with the installation process).
Upvotes: 3
Reputation: 1745
I have had this trouble with many different generated file types, not just PDFs. Spawning processes did not help because the problem was in the sizes of the variables, and no matter how fresh the process, the variables were still too big. My solution was to create a file and write to it in manageable chunks, so that my variables never got above a certain size.
A basic, untested example:
$tmp = fopen($tmpfilepath, 'w');
if(is_resource($tmp)) {
echo 'Generating file ... ';
$dompdf = new DOMPDF();
$counter = 0;
$html = '';
while($line = getLineOfYourHtml()) {
$html .= $line;
$counter++;
if($counter%200 == 0) { //pick a good chunk number here
$dompdf->load_html($html);
$dompdf->render();
$output = $dompdf->output();
fwrite($tmp, $output);
echo round($counter/getTotalLines()).'%... '; //echo percent complete
$html = '';
}
}
if($html != '') { //the last chunk
$dompdf->load_html($html);
$dompdf->render();
$output = $dompdf->output();
fwrite($tmp, $output);
}
fclose($tmp);
if(file_exists($tmpfilepath)) {
echo '100%. Generation complete. ';
echo '<a href="'.$tmpfileURL.'">Download</a>';
} else {
echo ' Generation failed.';
}
} else {
echo 'Could not generate file.';
}
Because it takes a while to generate the file, the echoes appear one after another, giving the user something to look at so they don't think the screen has frozen. The final echoed link will only appear after the file has been generated, which means the user is automatically waiting until the file is ready before they can download it. You may have to extend the max execution time for this script.
Upvotes: 2