使用 PHP 合并 PDF 文件 [关闭]
Posted
技术标签:
【中文标题】使用 PHP 合并 PDF 文件 [关闭]【英文标题】:Merge PDF files with PHP [closed] 【发布时间】:2011-06-15 05:33:46 【问题描述】:我的概念是 - 一个网站中有 10 个 pdf 文件。用户可以选择一些 pdf 文件,然后选择合并以创建包含所选页面的单个 pdf 文件。我怎样才能用 php 做到这一点?
【问题讨论】:
相关问题(顺便回答):***.com/questions/2713701/… @Webnet 实际上,64% 是可以的。我会说 0 - 25% = 失败,但我想这就是它变得主观的地方 可以用命令行工具吗? 你可以使用 Zend 框架吗? ***.com/questions/4254218/… 在哪里可以找到“pdftk-112-1i386.rpm”文件以及如何将其安装到服务器上? 【参考方案1】:我以前做过。我有一个用 fpdf 生成的 pdf,我需要在其中添加可变数量的 PDF。
所以我已经设置了一个 fpdf 对象和页面 (http://www.fpdf.org/) 我使用 fpdi 导入文件(http://www.setasign.de/products/pdf-php-solutions/fpdi/) FDPI是通过扩展PDF类来添加的:
class PDF extends FPDI
$pdffile = "Filename.pdf";
$pagecount = $pdf->setSourceFile($pdffile);
for($i=0; $i<$pagecount; $i++)
$pdf->AddPage();
$tplidx = $pdf->importPage($i+1, '/MediaBox');
$pdf->useTemplate($tplidx, 10, 10, 200);
这基本上使每个 pdf 成为图像以放入您的其他 pdf。它非常适合我的需要。
【讨论】:
我无法理解您的代码。你能解释更多细节吗?我也没有在 fpdf 手册中找到“setSourceFile”和“importPage”函数。 我回过头来更详细地查看了我的解决方案。我希望这更有帮助。今天早上写这篇文章的时候,我完全忘记了 fdpi 部分,它只是我写的一个相当复杂的 PDF 生成器的一小部分。 @Christa 注意 FPDI 只会解析某些 PDF 文件。我遇到了一个问题,FPDI 不会解析高于 v 1.4 的 PDF 文件,而 FPDI 让我购买他们的解析器来处理 > v1.4 ... yar .... 你不认为 $i = 0 和 $i 【参考方案2】:下面是php PDF合并命令。
$fileArray= array("name1.pdf","name2.pdf","name3.pdf","name4.pdf");
$datadir = "save_path/";
$outputName = $datadir."merged.pdf";
$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$outputName ";
//Add each pdf file to the end of the command
foreach($fileArray as $file)
$cmd .= $file." ";
$result = shell_exec($cmd);
我忘记了我找到它的链接,但它工作正常。
注意:您应该安装 gs(在 linux 上,也可能在 Mac 上)或 Ghostscript(在 windows 上)才能正常工作。
【讨论】:
它对我来说没有问题,也没有安装外部库作为 FPDI 或其他库。 这个解决方案最适合我。在我的服务器上安装 Ghostscript 非常容易。这只是“yum install ghostscript”。而且您的脚本运行良好 我得到一个空白的 pdf 页面 :( 你需要安装 Ghostscript,否则它会静默失败。 你应该解释它的实际作用。它实际上并不是真正的 php 方式来完成任务,在 php 中你只准备数据然后你执行一个 shell 脚本,它执行实际任务。你也应该在你的答案中包括,应该安装 gs(在 linux 和可能的 Mac 上)或 Ghostscript(在 Windows 上)才能工作。我仍然非常喜欢这个解决方案,因为我认为 gs 默认包含在 Ubuntu 中,我不必安装它。【参考方案3】:我建议 github.com 的 PDFMerger,就像 ::
一样简单include 'PDFMerger.php';
$pdf = new PDFMerger;
$pdf->addPDF('samplepdfs/one.pdf', '1, 3, 4')
->addPDF('samplepdfs/two.pdf', '1-2')
->addPDF('samplepdfs/three.pdf', 'all')
->merge('file', 'samplepdfs/TEST2.pdf'); // REPLACE 'file' WITH 'browser', 'download', 'string', or 'file' for output options
【讨论】:
这基本上是某人对@Christa 的回答(FPDF+FDPI)的实现,太好了:)谢谢! 它也不适用于某些 PDF 上的某些类型的压缩。 将它与 DOMPDF 一起使用,它很有魅力,谢谢! 我收到“FPDF 错误:无法找到外部参照表。”有什么解决办法吗? 它可以工作,但有时会在下面显示错误... FPDF 错误:本文档 (samplepdfs/four.pdf) 可能使用了 FPDI 附带的免费解析器不支持的压缩技术。【参考方案4】:myokyawhtun 的解决方案最适合我(使用 PHP 5.4)
您仍然会收到错误 - 我使用以下解决方案:
fpdf_tpl.php 的第 269 行 - 将函数参数更改为:
function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='',$align='', $resize=false, $dpi=300, $palign='', $ismask=false, $imgmask=false, $border=0)
我也在 fpdf.php 的第 898 行做了同样的修改
【讨论】:
【参考方案5】:$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=".$new." ".implode(" ", $files);
shell_exec($cmd);
Chauhan 回答的简化版
【讨论】:
这对我来说在 hostgator centos 专用服务器上工作得很好,所以必须已经安装了 ghostscript 也应该被标记为正确答案,因为它太简单了。 FPDF 和 FPDI 无法正确加载的时间。你救了我的命。只需要在服务器上安装“imagemagick”(在 debian/ubuntu 上:apt install imagemagick)就可以了。干杯!【参考方案6】:我在 FPDI 上创建了一个抽象层(可能适应其他引擎)。 我根据库和库本身将它发布为 Symfony2 包。
The bundle
The Library
用法:
public function handlePdfChanges(Document $document, array $formRawData)
$oldPath = $document->getUploadRootDir($this->kernel) . $document->getOldPath();
$newTmpPath = $document->getFile()->getRealPath();
switch ($formRawData['insertOptions']['insertPosition'])
case PdfInsertType::POSITION_BEGINNING:
// prepend
$newPdf = $this->pdfManager->insert($oldPath, $newTmpPath);
break;
case PdfInsertType::POSITION_END:
// Append
$newPdf = $this->pdfManager->append($oldPath, $newTmpPath);
break;
case PdfInsertType::POSITION_PAGE:
// insert at page n: PdfA=p1; p2; p3, PdfB=pA; pB; pC
// insert(PdfA, PdfB, 2) will render p1; pA; pB; pC; p2; p3
$newPdf = $this->pdfManager->insert(
$oldPath, $newTmpPath, $formRawData['insertOptions']['pageNumber']
);
break;
case PdfInsertType::POSITION_REPLACE:
// does nothing. overrides old file.
return;
break;
$pageCount = $newPdf->getPageCount();
$newPdf->renderFile($mergedPdfPath = "$newTmpPath.merged");
$document->setFile(new File($mergedPdfPath, true));
return $pageCount;
【讨论】:
【参考方案7】:这在 Windows 上对我有用
-
从https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/免费下载PDFtk
将文件夹 (PDFtk) 放入 c: 的根目录
将以下内容添加到您的 php 代码中,其中 $file1 是第一个 PDF 文件的位置和名称,$file2 是第二个 PDF 文件的位置和名称,$newfile 是目标文件的位置和名称
$file1 = ' c:\\\www\\\folder1\\\folder2\\\file1.pdf';
$file2 = ' c:\\\www\\\folder1\\\folder2\\\file2.pdf';
$file3 = ' c:\\\www\\\folder1\\\folder2\\\file3.pdf';
$command = 'cmd /c C:\\\pdftk\\\bin\\\pdftk.exe '.$file1.$file2.$newfile;
$result = exec($command);
【讨论】:
有一个 PHP 包装器可以让这变得更干净。见github.com/mikehaertl/php-pdftk 注意:PdfTK 不适用于 RHEL 7 或 Cent OS 7 对我来说,它只能像这样工作:$command = "cmd /c C:\\pdftk\\bin\\pdftk.exe $file1 $file2 cat output $new";
注意额外的 cat 输出。见PDFtk examples【参考方案8】:
我的软件也遇到过类似的问题。我们希望将多个 PDF 文件合并为一个 PDF 文件并将其提交给外部服务。我们一直在使用 Christa 的解决方案中所示的 FPDI 解决方案。
但是,我们一直使用的输入 PDF 的版本可能高于 1.7。我们决定评估 FPDI 商业插件。然而,事实证明,我们办公室复印机扫描的一些文档的索引格式不正确,这导致商业 FPDI 插件崩溃。所以我们决定使用 Ghostscript 解决方案,就像 Chauhan 的回答一样。
但是我们在输出的 PDF 属性中得到了一些奇怪的元数据。
最后,我们决定加入两个解决方案,让 Ghostscript 合并和降级 PDF,但元数据由 FPDI 设置。我们还不知道它如何与一些高级格式化的 pdf 一起工作,但对于扫描,我们使用它工作得很好。这是我们的课程摘录:
class MergedPDF extends \FPDI
private $documentsPaths = array();
public function Render()
$outputFileName = tempnam(sys_get_temp_dir(), 'merged');
// merge files and save resulting file as PDF version 1.4 for FPDI compatibility
$cmd = "/usr/bin/gs -q -dNOPAUSE -dBATCH -dCompatibilityLevel=1.4 -sDEVICE=pdfwrite -sOutputFile=$outputFileName";
foreach ($this->getDocumentsPaths() as $pdfpath)
$cmd .= " $pdfpath ";
$result = shell_exec($cmd);
$this->SetCreator('Your Software Name');
$this->setPrintHeader(false);
$numPages = $this->setSourceFile($outputFileName);
for ($i = 1; $i <= $numPages; $i++)
$tplIdx = $this->importPage($i);
$this->AddPage();
$this->useTemplate($tplIdx);
unlink($outputFileName);
$content = $this->Output(null, 'S');
return $content;
public function getDocumentsPaths()
return $this->documentsPaths;
public function setDocumentsPaths($documentsPaths)
$this->documentsPaths = $documentsPaths;
public function addDocumentPath($documentPath)
$this->documentsPaths[] = $documentPath;
这个类的用法如下:
$pdf = new MergedPDF();
$pdf->setTitle($pdfTitle);
$pdf->addDocumentPath($absolutePath1);
$pdf->addDocumentPath($absolutePath2);
$pdf->addDocumentPath($absolutePath3);
$tempFileName = tempnam(sys_get_temp_dir(), 'merged');
$content = $pdf->Render();
file_put_contents($tempFileName, $content);
【讨论】:
顺便提一下,我在 Windows 环境中使用了相同的代码。并且不要忘记将程序文件夹放入“而不是参数。$cmd = "\"C:\\Program Files\\gs\\gs9.20\\bin\\gswin64c.exe\" -q -dNOPAUSE -dBATCH -dCompatibilityLevel=1.4 -sDEVICE=pdfwrite -sOutputFile=[....your parameters...]" ;
【参考方案9】:
我已经尝试过类似的问题并且工作正常,试试吧。它可以处理 PDF 之间的不同方向。
// array to hold list of PDF files to be merged
$files = array("a.pdf", "b.pdf", "c.pdf");
$pageCount = 0;
// initiate FPDI
$pdf = new FPDI();
// iterate through the files
foreach ($files AS $file)
// get the page count
$pageCount = $pdf->setSourceFile($file);
// iterate through all pages
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++)
// import a page
$templateId = $pdf->importPage($pageNo);
// get the size of the imported page
$size = $pdf->getTemplateSize($templateId);
// create a page (landscape or portrait depending on the imported page size)
if ($size['w'] > $size['h'])
$pdf->AddPage('L', array($size['w'], $size['h']));
else
$pdf->AddPage('P', array($size['w'], $size['h']));
// use the imported page
$pdf->useTemplate($templateId);
$pdf->SetFont('Helvetica');
$pdf->SetXY(5, 5);
$pdf->Write(8, 'Generated by FPDI');
【讨论】:
这给了Undefined index: w
确保您已正确配置 FPDF
我的参数是 $size['width'] 和 $size['height'] 而不是 $size['w'] 和 $size['h']【参考方案10】:
接受的答案甚至 FDPI 主页似乎都提供了拙劣或不完整的示例。这是我的,它有效且易于实施。正如预期的那样,它需要 fpdf 和 fpdi 库:
FPDF:http://www.fpdf.org/en/download.php FPDI:https://www.setasign.com/products/fpdi/downloadsrequire('fpdf.php');
require('fpdi.php');
$files = ['doc1.pdf', 'doc2.pdf', 'doc3.pdf'];
$pdf = new FPDI();
// iterate over array of files and merge
foreach ($files as $file)
$pageCount = $pdf->setSourceFile($file);
for ($i = 0; $i < $pageCount; $i++)
$tpl = $pdf->importPage($i + 1, '/MediaBox');
$pdf->addPage();
$pdf->useTemplate($tpl);
// output the pdf as a file (http://www.fpdf.org/en/doc/output.htm)
$pdf->Output('F','merged.pdf');
【讨论】:
嗨@billynoah 我喜欢这个,但它不适用于横向,似乎只合并第一页。 @GeraldoIsaaks - 我随后在自己的应用程序中添加了对多页文档的支持。我已经更新了答案。不确定景观问题 - 我没有遇到过。 自 FPDI 早期就可用的 this 示例中的内容是什么? @Setasign - 我从未见过,但感谢分享。 @billynoah 感谢 SO 中清晰且更新的简单代码示例。它让我开始了。我最终使用了 setasign 示例中的更多代码(setasign.com/products/fpdi/demos/concatenate-fake,上面的评论中很容易错过链接)。他们在 addPage 调用中的逻辑使我的特定连接页面看起来更好。尽管我没有测试过,但可能也可以更好地处理肖像/风景。但是我没有找到带有搜索的示例,并且直到我看到你的答案才知道我感兴趣。以上是关于使用 PHP 合并 PDF 文件 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 php mpdf 库将多个 PDF 文件合并为一个 PDF