PHP 中的 HTML2PDF - 转换实用程序和脚本 - 示例和演示
Posted
技术标签:
【中文标题】PHP 中的 HTML2PDF - 转换实用程序和脚本 - 示例和演示【英文标题】:HTML2PDF in PHP - convert utilities & scripts - examples & demos 【发布时间】:2012-04-12 05:59:40 【问题描述】:我有一个非常复杂的 html/CSS 布局,我想在我的服务器上将其转换为 PDF。我已经尝试过 DOMPDF,不幸的是它没有将 HTML 转换为正确的布局。我考虑过 HTMLDOC,但我听说它在很大程度上忽略了 CSS,所以我想布局也会与该工具分开。
我的问题是 - 是否有其他工具(如 wkhtmltopdf 即)的在线演示可以用来验证我的 HTML 是如何转换的?在我的余生一一安装和测试之前?
很遗憾,我无法更改 HTML 布局以适应这些工具。或者说得更好——我可以,如果他们中的任何一个能接近可接受的结果......
【问题讨论】:
wkhtmltopdf 不需要太多安装 - 我认为他们实际上建议您只需下载静态 32 位或 64 位版本并使用它。测试它不应该超过 2 分钟,它可能是可用的最高质量的解决方案。我们有一些半复杂的 HTML/CSS 转换为 PDF 用于打印目的,wkhtmltopdf 还没有让我们失望。 wkhtmltopdf 真的很容易安装(而且我认为它甚至是静态链接的二进制文件,因此不需要额外的库)......结果与 webkit 引擎渲染相同(它在引擎盖下) - 只是无头) 嘿伙计们,thanx,我会再尝试 2 样东西 - TCPDF 和 wkhtmltopdf :) 你们都对,所有的东西都很容易安装,但它需要时间来测试它,阅读文档:) 【参考方案1】:不是真正的答案,而是针对上面的问题,但我会尝试提供一些我的经验,也许它会在未来的某个地方对某人有所帮助。
wkthmltopdf 确实是唯一对我有用的解决方案,它可以产生我所说的可接受的结果。尽管如此,还是必须对 CSS 进行一些小的修改,但是,它在渲染内容时工作得非常好。如果您有一个包含一个基本表格等的相当简单的文档,那么所有其他软件包实际上才适用。没有机会让它们在具有设计元素、css、多个重叠图像等的复杂文档上产生公平的结果。如果复杂的文档在游戏中- 不要花时间(像我一样) - 直接转到 wkhtmltopdf。
当心 - wkhtmltopdf 安装很棘手。这对我来说并不像他们在 cmets 中所说的那样容易(原因之一可能是我对 Linux 不太熟悉)。由于某种我无法解释的原因,静态二进制文件对我不起作用。我怀疑版本存在问题 - 显然不同操作系统和处理器的版本之间存在差异,也许我有 vrong 版本。首先要安装非静态版本,您必须对服务器具有 root 访问权限,这很明显。 我使用 PuTTy 使用 apt-get
安装了它,运行良好。我很幸运我的服务器已经具备了安装 wkhtmltopdf 的所有条件。所以这对我来说很容易:)(顺便说一句,你不必像许多教程告诉你的那样关心符号链接或包装器 - 我花了几个小时试图弄清楚如何做那部分,最后我给了它起来,一切正常)
安装后我得到了著名的Cannot connect to X server
错误。这是因为 我们需要在 'virtual' x server 上无头运行 wkhtmltopdf。解决这个问题也很简单(如果不关心符号链接)。 我用apt-get install xvfb
安装它。这对我来说也很顺利,没有问题。
完成此操作后,我能够运行 wkhtmltopdf
。当心 - 我花了一些时间才发现尝试运行 xvfb
是错误的方式 - 相反你必须运行 xvfb-run
。我的 php 代码现在看起来像这样 exec("xvfb-run wkhtmltopdf --margin-left 16 /data/web/domain.com/source.html /data/web/domain.com/target.pdf");
(请注意 wkhtmltopdf
的 --margin-left 16
命令行选项 - 它使我的内容更加居中;我将其留在原处以演示如何使用命令行选项)。
我还想保护生成的 PDF 文件不被编辑(在我的情况下,打印保护也是可能的)。在做了一些研究后,我从 ID 安全套件中找到了 this class。首先,我必须说 - 它已经过时了(我正在运行 PHP 5+)。不过,我对它做了一些改进。首先 - 它是FPDF 库的包装器,所以包中有一个名为 fpdf.php 的文件。我用我得到的最新 FPDF 版本 from here 替换了这个文件。它使我的 PHP 警告看起来更具可持续性。我还更改了 $pdf =& new FPDI_Protection();
并删除了 &
标志,因为我收到了已弃用的警告。然而,还有更多的人来。我没有搜索和修改代码,而是使用error_reporting(0);
将错误报告 lvl 设置为 0(尽管仅关闭警告就足够了)。现在有人会说这不是“好习惯”。我在内部系统上使用这整个东西,所以我真的不必关心。当然可以修改脚本以匹配最新要求。对我来说,我不想再花几个小时在上面工作。 请注意脚本中提到的$pdf->SetProtection(array('print'), '', $password);
(如您所见,我允许打印我的文档)。我花了一段时间才弄清楚第一个参数是权限。 第二个是用户密码 - 如果您提供此密码,则文档将需要密码才能打开(我将其留空)。 第三个是所有者密码 - 这是使文档“安全”以防编辑、复制等操作所需的密码。
我的整个代码现在看起来像:
// 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 );
希望这可以帮助某人在将来节省一些时间。整个解决方案花了我大约 12 个小时来实施到我们的发票系统中。对于像我这样不太熟悉 Linux/UNIX 的用户,如果在 wkhtmltopdf
上有更好的信息,我可以节省一些时间。
但是 - 杀不死你的东西会让你变得更强大 :) 所以我现在完成了这次比赛,变得更加完美了 :)
【讨论】:
您是否在强制模式下运行 SELinux?以上是关于PHP 中的 HTML2PDF - 转换实用程序和脚本 - 示例和演示的主要内容,如果未能解决你的问题,请参考以下文章