PDF-Dateien mit PHP zusammenführen [geschlossen]

83

Mein Konzept ist - es gibt 10 PDF-Dateien auf einer Website. Der Benutzer kann einige PDF-Dateien auswählen und dann Zusammenführen auswählen, um eine einzelne PDF-Datei zu erstellen, die die ausgewählten Seiten enthält. Wie kann ich das mit PHP machen?

Imrul.H
quelle
Verwandte Frage (übrigens beantwortet): stackoverflow.com/questions/2713701/…
Fran Verona
3
@Webnet eigentlich sind 64% in Ordnung. Ich würde sagen 0 - 25% = scheitern, aber ich denke, dort wird es subjektiv
Sean Patrick Floyd
Können Sie ein Befehlszeilenprogramm verwenden?
Pekka
Können Sie Zend Framework verwenden? stackoverflow.com/questions/4254218/…
Pekka
Wo finde ich die Datei "pdftk-112-1i386.rpm" und wie installiere ich sie auf dem Server?
Imrul.H

Antworten:

28

Ich habe das schon mal gemacht. Ich hatte ein PDF, das ich mit fpdf erstellt hatte, und ich musste eine variable Anzahl von PDFs hinzufügen.

Ich hatte also bereits ein fpdf-Objekt und eine Seite eingerichtet (http://www.fpdf.org/) und importierte die Dateien mit fpdi (http://www.setasign.de/products/pdf-php-solutions/). fpdi /) FDPI wird durch Erweitern der PDF-Klasse hinzugefügt:

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

Dies macht im Grunde jedes PDF zu einem Bild, das Sie in Ihr anderes PDF einfügen können. Es funktionierte erstaunlich gut für das, wofür ich es brauchte.

Christa
quelle
Ich kann Ihren Code nicht verstehen. Können Sie uns bitte etwas näher erläutern? Ich habe auch die Funktionen "setSourceFile" und "importPage" im fpdf-Handbuch nicht gefunden.
Imrul.H
Ich ging zurück und sah mir meine Lösung etwas genauer an. Ich hoffe das ist hilfreicher. Ich habe den fdpi-Teil heute Morgen völlig vergessen, als ich ihn schrieb, es ist ein kleiner Teil eines ziemlich komplizierten PDF-Generators, den ich geschrieben habe.
Christa
6
@Christa Beachten Sie, dass FPDI nur bestimmte PDF-Dateien analysiert. Ich habe ein Problem, bei dem FPDI PDF-Dateien über Version 1.4 nicht analysiert und FPDI mich dazu bringt, ihren Parser zu kaufen, um> Version 1.4 zu verarbeiten ... yar ....
n0nag0n
Glaubst du nicht, es ist besser, $ i = 0 und $ i <= $ pagecount zu machen? Es macht es besser zu lesen, denke ich. Tolles Beispiel übrigens, hat mir wirklich geholfen
Nebulosar
123

Unten ist der PHP PDF Merge Befehl.

$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);

Ich habe den Link vergessen, von dem ich ihn gefunden habe, aber er funktioniert einwandfrei.

Hinweis: Sie sollten gs (unter Linux und wahrscheinlich Mac) oder Ghostscript (unter Windows) installiert haben, damit dies funktioniert.

Sanjeev Chauhan
quelle
4
Es funktionierte für mich ohne Probleme und ohne externe Bibliotheken als FPDI oder andere zu installieren.
Memochipan
4
Diese Lösung hat bei mir am besten funktioniert. Es war sehr einfach, Ghostscript auf meinem Server zu installieren. Es war nur "yum install ghostscript". Und Ihr Skript hat perfekt funktioniert
Theo Kouzelis
1
Ich
bekomme
2
Sie müssen Ghostscript installiert haben, andernfalls schlägt es stillschweigend fehl.
Pascal Klein
2
Sie sollten erklären, was es tatsächlich tut. Es ist eigentlich keine PHP-Methode, um die Aufgabe zu erledigen. In PHP bereiten Sie nur Daten vor und führen dann ein Shell-Skript aus, das die eigentliche Aufgabe ausführt. Außerdem sollten Sie in Ihre Antwort aufnehmen, dass gs (unter Linux und wahrscheinlich Mac) oder Ghostscript (unter Windows) installiert sein sollten, damit dies funktioniert. Trotzdem gefällt mir diese Lösung sehr gut, da gs standardmäßig in Ubuntu enthalten ist Ich musste es nicht installieren.
Vulgo Alias
39

Ich schlage PDFMerger von github.com vor , so einfach wie ::

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
AgelessEssence
quelle
3
Dies ist im Grunde jemandes Implementierung von @ Christas Antwort (FPDF + FDPI), was großartig ist :) Danke!
Nahuel
5
Es funktioniert auch nicht mit einigen Arten der Komprimierung auf einigen PDFs.
Theo Kouzelis
3
Verwenden Sie dies mit DOMPDF und es funktioniert ein Zauber, danke!
Matthew
1
Ich erhalte die Meldung "FPDF-Fehler: XRef-Tabelle konnte nicht gefunden werden." eine Lösung dafür?
Sameeraa4ever
1
Es funktioniert, zeigt aber manchmal den folgenden Fehler an ... FPDF-Fehler: Dieses Dokument (samplepdfs / four.pdf) verwendet wahrscheinlich eine Komprimierungstechnik, die vom mit FPDI gelieferten kostenlosen Parser nicht unterstützt wird.
Nikhil
11
$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=".$new." ".implode(" ", $files);
shell_exec($cmd);

Eine vereinfachte Version von Chauhans Antwort

Svetoslav Genov
quelle
Dies funktionierte gut für mich auf Hostgator Centos dedizierten Server, so dass Ghostscript bereits installiert sein muss
Mike Volmar
9

Sowohl die akzeptierte Antwort als auch die FDPI-Homepage scheinen verpfuschte oder unvollständige Beispiele zu geben. Hier ist meine, die funktioniert und einfach zu implementieren ist. Wie erwartet sind fpdf- und fpdi-Bibliotheken erforderlich:

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');
Billynoah
quelle
Hallo @billynoah, das gefällt mir, aber es funktioniert nicht im Querformat und scheint nur die ersten Seiten zusammenzuführen.
Geraldo Isaaks
2
@GeraldoIsaaks - Anschließend habe ich in meiner eigenen Anwendung Unterstützung für mehrseitige Dokumente hinzugefügt. Ich habe die Antwort aktualisiert. Ich bin mir bei Landschaftsproblemen nicht sicher - darauf bin ich nicht gestoßen.
Billynoah
Was steckt in diesem Beispiel, das seit den Anfängen von FPDI verfügbar ist?
Jan Slabon
@ Setasign - Ich habe das noch nie gesehen, aber danke fürs Teilen.
Billynoah
@billynoah Danke für das klare und aktualisierte einfache Codebeispiel hier in SO. Es hat mich dazu gebracht. Am Ende habe ich mehr Code aus dem setasign-Beispiel verwendet ( setasign.com/products/fpdi/demos/concatenate-fake , Link ist im obigen Kommentar leicht zu übersehen). Ihre Logik innerhalb des addPage-Aufrufs ließ meine speziellen verketteten Seiten besser aussehen. Vermutlich geht es auch besser mit Hoch- / Querformat, obwohl ich das nicht getestet habe. Aber ich habe das Beispiel bei Suchanfragen nicht gefunden und wusste nicht, dass ich interessiert bin, bis ich Ihre Antwort sah.
Anne Gunn
5

Ich hatte ein ähnliches Problem in meiner Software. Wir wollten mehrere PDF-Dateien zu einer PDF-Datei zusammenführen und an einen externen Dienst senden. Wir haben mit der FPDI Lösung wie in gezeigt Christa ‚s Lösung.

Die von uns verwendeten Eingabe-PDFs könnten jedoch eine höhere Version als 1.7 haben. Wir haben uns entschlossen, das kommerzielle FPDI-Add-On zu evaluieren. Es stellte sich jedoch heraus, dass einige der von unserem Bürokopierer gescannten Dokumente fehlerhafte Indizes aufwiesen, wodurch das kommerzielle FPDI-Add-On abstürzte. Deshalb haben wir uns entschieden, die Ghostscript- Lösung wie in Chauhans Antwort zu verwenden.

Aber dann haben wir einige seltsame Metadaten in den Ausgabe-PDF-Eigenschaften.

Schließlich haben wir uns entschlossen, zwei Lösungen zu verbinden, um PDFs von Ghostscript zusammenzuführen und herunterzustufen, aber die Metadaten werden von FPDI festgelegt. Wir wissen noch nicht, wie es mit einigen fortgeschrittenen formatierten PDFs funktionieren würde, aber für Scans, die wir verwenden, funktioniert es einwandfrei. Hier ist unser Klassenauszug:

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

Die Verwendung dieser Klasse ist wie folgt:

$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);
Artur Karczmarczyk
quelle
Nur um zu erwähnen, dass ich den gleichen Code unter Windows env verwendet habe. und vergessen Sie nicht, den Programmordner in "zu legen, aber nicht die Parameter.$cmd = "\"C:\\Program Files\\gs\\gs9.20\\bin\\gswin64c.exe\" -q -dNOPAUSE -dBATCH -dCompatibilityLevel=1.4 -sDEVICE=pdfwrite -sOutputFile=[....your parameters...]" ;
Frédéric Klee
3

Ich habe ein ähnliches Problem ausprobiert und funktioniert einwandfrei. Probieren Sie es aus. Es kann unterschiedliche Ausrichtungen zwischen PDFs verarbeiten.

    // 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');
        }
    }
Kevin Chui
quelle
Dies gibtUndefined index: w
senty
Stellen Sie sicher, dass Sie FPDF richtig konfiguriert haben
Kevin Chui
Die Parameter für mich waren $ size ['width'] und $ size ['height'] anstelle von $ size ['w'] und $ size ['h']
Gorillagoat
0

Ich habe eine Abstraktionsschicht über FPDI erstellt (möglicherweise für andere Engines). Ich habe es je nach Bibliothek als Symfony2-Bundle und als Bibliothek selbst veröffentlicht.

Das Paket

Die Bibliothek

Verwendung:

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;
}
juanmf
quelle
0

Dies funktionierte bei mir unter Windows

  1. Laden Sie PDFtk kostenlos von https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/ herunter.
  2. Legen Sie den Ordner (PDFtk) im Stammverzeichnis von c ab:
  3. Fügen Sie Ihrem PHP-Code Folgendes hinzu, wobei $ file1 der Speicherort und Name der ersten PDF-Datei ist, $ file2 der Speicherort und der Name der zweiten und $ newfile der Speicherort und Name der Zieldatei ist

    $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);
    
Stewart Kirkpatrick
quelle
Es gibt einen PHP-Wrapper, der dies viel sauberer macht. Siehe github.com/mikehaertl/php-pdftk
Sean the Bean
Hinweis: PdfTK funktioniert nicht mit RHEL 7 oder Cent OS 7
Ray
Bei mir hat es nur so funktioniert: $command = "cmd /c C:\\pdftk\\bin\\pdftk.exe {$file1} {$file2} cat output {$new}";Beachten Sie die zusätzliche Cat-Ausgabe . Siehe PDFtk Beispiele
maxpower9000
-1

Die Lösung von myokyawhtun funktionierte am besten für mich (mit PHP 5.4).

Sie werden trotzdem einen Fehler erhalten - ich habe Folgendes behoben:

Zeile 269 von fpdf_tpl.php - änderte die Funktionsparameter in:

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) { 

Ich habe diese Änderung auch in Zeile 898 von fpdf.php vorgenommen

Scott
quelle