PHP和dompdf -如何生成一个大的PDF没有我的服务器来急刹车


php and dompdf - how to generate a large pdf without having my server come to a screeching halt

我试图用dompdf渲染一个较大的html表到pdf。有最小的css样式,但可能200 - 300行在表中。每行有4个带有基本文本的td。

我可以生成一个较小的表的pdf没有问题,但一个较大的表将耗尽内存限制,脚本将终止。解决这个问题的最佳方法是什么?我在serverfault上开始了一个讨论,一个用户建议生成一个新的进程,以便不耗尽php/apache的内存限制?这是最好的办法吗?这让我产生了关于如何工作的问题,在dompdf当前将下载流式传输到浏览器中,但是我假设如果我创建一个新流程来生成报告,我就不能再将输出发送到浏览器以供用户下载了?

感谢任何可能提出解决这个问题的好方法的人!

如果使用二级PHP进程(例如使用exec())呈现HTML,则执行时间和内存限制将得到缓解。在用这种方法呈现时,您将呈现的PDF保存到网站上的一个目录中,并将用户重定向到下载处(如果您想运行呈现队列,甚至可以通过电子邮件向用户发送链接)。一般来说,我发现这种方法确实在速度和内存使用方面提供了适度的改进。

然而,这并不意味着渲染在你的情况下会执行得更快。目前使用dompdf呈现表是资源密集型的。如果可以的话,更好的方法是将文档分成几个部分,分别呈现每个部分(同样使用第二个PHP进程),将生成的PDF集合合并为单个文件(使用类似pdftk的东西),然后将PDF保存在用户可以访问的地方。使用这种方法,我已经看到了显著的性能改进。

或者使用wkhtmltopdf(如果您有访问服务器的shell权限并且愿意处理安装过程)。

我在生成许多不同类型的文件时都遇到过这个问题,而不仅仅是pdf。生成进程没有帮助,因为问题在于变量的大小,无论进程多么新鲜,变量仍然太大。我的解决方案是创建一个文件,并在可管理的块中写入它,这样我的变量就不会超过一定的大小。

一个基本的,未经测试的例子:

$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.';
}

因为生成文件需要一段时间,所以回声一个接一个地出现,给用户一些东西看,这样他们就不会认为屏幕已经冻结了。最后的回显链接只会在文件生成之后出现,这意味着用户会自动等待,直到文件准备好,然后才能下载它。您可能需要延长此脚本的最大执行时间。