使用 PHP 合并多个 PDF 文件 [已关闭]

问题描述 投票:0回答:10

场景: 在我的 Web 应用程序上,我有一些 PDF 文件,用户可以选择合并这些文件以创建包含所有页面的单个文件。

预期结果: 单个 PDF 文件


如何在PHP中解决这样的问题?我可以使用任何库来执行此操作吗?我是否需要使用某些特定的 PHP 框架,或某些特定的 PHP 版本?预先感谢

php pdf
10个回答
154
投票

注意:Ghostscript 需要每年 25,000 美元的巨额商业用途许可证,或者使用其 AGPL 许可证,您必须将代码作为开源发布。 来源

下面是使用 Ghostscript 命令合并 pdf 的 php 代码。

$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 上)才能正常工作。 注意:Ghostscript 需要 25,000 美元的年度许可证才能用于商业用途


50
投票

我建议来自 github.comPDFMerger,就像 ::

一样简单
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

30
投票

我以前做过这个。我有一个用 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 中。它非常适合我的需要。


15
投票
$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=".$new." ".implode(" ", $files);
shell_exec($cmd);

Chauhan 答案的简化版本


13
投票

接受的答案甚至 FDPI 主页似乎都给出了拙劣或不完整的示例。 这是我的,它有效并且易于实施。 正如预期的那样,它需要 fpdf 和 fpdi 库:

require('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');

4
投票

我的软件也遇到过类似的问题。我们想要将多个 PDF 文件合并为一个 PDF 文件并将其提交给外部服务。我们一直在使用 FPDI 解决方案,如 Christa 的解决方案所示。

但是,我们一直使用的输入 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);

3
投票

我已经尝试过类似的问题并且工作正常,请尝试一下。 它可以处理 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');
        }
    }

0
投票

我在 FPDI 上创建了一个抽象层(可能容纳其他引擎)。 我根据库将其作为 Symfony2 捆绑包以及库本身发布。

捆绑包

图书馆

用途:

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;
}

0
投票

这在 Windows 上对我有用

  1. https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/
  2. 免费下载 PDFtk
  3. 将文件夹 (PDFtk) 放入 c: 的根目录中
  4. 将以下内容添加到您的 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);
    

-2
投票

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 行做了同样的更改

© www.soinside.com 2019 - 2024. All rights reserved.