PHP中的HTML2PDF - 转换实用程序&脚本 - 示例&演示

时间:2012-03-28 15:37:44

标签: php pdf pdf-generation tcpdf wkhtmltopdf

我有一个非常复杂的HTML / CSS布局,我想在我的服务器上转换为PDF。我已经尝试过DOMPDF,遗憾的是它没有使用正确的布局转换HTML。我已经考虑过HTMLDOC,但我听说它在很大程度上忽略了CSS,所以我认为布局也会与该工具分开。

我的问题是 - 是否有其他工具(如wkhtmltopdf ie)的在线演示,我可以用来验证我的HTML是如何转换的?在我的余生安装和安装之前逐个测试?

不幸的是,我无法更改HTML布局以适应这些工具。或者更好地说 - 我可以,如果他们中的任何一个接近可接受的结果......

1 个答案:

答案 0 :(得分:11)

不是答案,但对于上面的问题,但我会尝试提供一些经验,也许这将有助于将来某些人。

  1. wkthmltopdf真的是唯一的解决方案对我有用,可以产生我称之为可接受的结果。尽管如此,必须对CSS进行一些小的修改,但是,在渲染内容时,它的效果非常好。所有其他包真的只适用于你有一个简单的文档与一个基本表等。没有机会让他们在复杂的文档与设计元素,CSS,多个重叠的图像等产生公平的结果。如果复杂的文档在游戏中 - 不要花时间(就像我一样) - 直接去wkhtmltopdf

  2. 注意 - wkhtmltopdf安装很棘手。对于我来说,这并不像他们在评论中所说的那样容易(其中一个原因可能是我对Linux不太熟悉)。由于某些我无法解释的原因,静态二进制文件对我不起作用。我怀疑该版本存在问题 - 显然不同操作系统和处理器的版本之间存在差异,也许我有错误的版本。首先,要安装非静态版本,您必须具有对服务器的root访问权限,这是显而易见的。 我用apt-get使用PuTTy 安装它,运行得很顺利。我很幸运,我的服务器已经具备了所有的优势来安装wkhtmltopdf。所以这对我来说很简单:)(顺便说一句,你不必像许多教程告诉你的那样关心符号链接或包装器 - 我花了好几个小时试图弄清楚如何做这个部分,最后我给了它尽管如此,一切运作良好)

  3. 安装后我收到了很有名的Cannot connect to X server错误。这是因为我们需要在'virtual' x server 上运行wkhtmltopdf无头。解决这个问题也很简单(如果不关心符号链接)。 我使用apt-get install xvfb 安装了它。这对我来说也很顺利,没问题。

  4. 完成此操作后,我可以运行wkhtmltopdf。请注意 - 我花了一些时间才弄清楚尝试运行xvfb是错误的方式 - 而是你必须运行xvfb-run 。我的PHP代码现在看起来像exec("xvfb-run wkhtmltopdf --margin-left 16 /data/web/domain.com/source.html /data/web/domain.com/target.pdf");(注意--margin-left 16的{​​{1}}命令行选项 - 它使我的内容更加集中;我把它留在原地以演示如何使用命令行选项)。

  5. 我还想保护生成的PDF文件免于编辑(在我的情况下,也可以进行打印保护)。在做了一些研究后,我发现了来自ID Security Suite的 this class 。首先,我要说 - 它是旧的(我正在运行PHP 5+)。但是,我对它做了一些改进。首先 - 它是FPDF的包装器,因此包中有一个名为fpdf.php的文件。我用最新的FPDF版本from here替换了这个文件。它使我的PHP警告看起来更具可持续性。我还更改了wkhtmltopdf并删除了$pdf =& new FPDI_Protection();符号,因为我收到了一个已弃用的警告。但是,还有更多的未来。我没有搜索和修改代码,只是将错误报告lvl变为0 &(尽管仅关闭警告应该足够)。现在有人会说这不是“好习惯”。我在内部系统上使用这些东西,所以我真的不必关心。确保脚本可以修改以匹配最新要求。对我来说,我不想再花上几个小时的工作。 在脚本显示error_reporting(0); 时要小心(我允许打印我的文档,如您所见)。我花了一段时间才弄清楚第一个参数是权限第二个是USER PASSWORD - 如果你提供这个,那么文档将需要一个密码才能打开(我把这个留空)。 第三个是所有者密码 - 这就是您需要使文档“安全”以防止编辑,复制等。

  6. 我的整个代码现在看起来像:

    $pdf->SetProtection(array('print'), '', $password);

    希望这可以帮助别人节省一些时间。整个解决方案花了我12个小时来实现我们的发票系统。对于像我这样熟悉Linux / UNIX的用户,// get the HTML content of the file we want to convert $invoice = file_get_contents("http://www.domain.com/index.php?s=invoices-print&invoice_no=".$_GET['invoice_no']; // replace the CSS style from a print version to a specially modified PDF version $invoice = str_replace('href="design/css/base.print.css"','href="design/css/base.pdf.css"',$invoice); // write the modified file to disk file_put_contents("docs/invoices/tmp/".$_GET['invoice_no'].".html", $invoice); // do the PDF magic exec("xvfb-run wkhtmltopdf --margin-left 16 /data/web/domain.com/web/docs/invoices/tmp/".$_GET['invoice_no'].".html /data/web/domain.com/web/docs/invoices/".$_GET['invoice_no'].".pdf"); // delete the temporary HTML data - we don't need that anymore since our PDF is created unlink("docs/invoices/tmp/".$_GET['invoice_no'].".html"); // workaround the warnings error_reporting(0); // script from ID Security Suite function pdfEncrypt ($origFile, $password, $destFile){ require_once('libraries/fpdf/FPDI_Protection.php'); $pdf = new FPDI_Protection(); $pdf->FPDF('P', 'in'); //Calculate the number of pages from the original document. $pagecount = $pdf->setSourceFile($origFile); //Copy all pages from the old unprotected pdf in the new one. for ($loop = 1; $loop <= $pagecount; $loop++) { $tplidx = $pdf->importPage($loop); $pdf->addPage(); $pdf->useTemplate($tplidx); } //Protect the new pdf file, and allow no printing, copy, etc. and //leave only reading allowed. $pdf->SetProtection(array('print'), '', $password); $pdf->Output($destFile, 'F'); return $destFile; } //Password for the PDF file (I suggest using the email adress of the purchaser). $password = md5(date("Ymd")).md5(date("Ymd")); //Name of the original file (unprotected). $origFile = "docs/invoices/".$_GET['invoice_no'].".pdf"; //Name of the destination file (password protected and printing rights removed). $destFile = "docs/invoices/".$_GET['invoice_no'].".pdf"; //Encrypt the book and create the protected file. pdfEncrypt($origFile, $password, $destFile ); 有更好的信息,我可以节省一些花在这上面的时间。

    但是 - 什么不会杀死你会让你更强大:)所以我现在运行得更加完美了:))