it-swarm.com.de

Wie generieren Sie Massen PDF von HTML-Vorlagen bereit für beidseitigen Druck in PHP?

Ich habe lange damit zu kämpfen und fühle mich hilflos Prestashop verwendet tcpdf , um Rechnungen und Lieferscheine aus mit Smarty gefüllten HTML-Vorlagen zu generieren. Wir arbeiten an der Aktualisierung des Rechnungsdesigns und haben festgestellt, dass tcpdf an CSS-Unterstützung fehlt. Nach einiger Recherche entschieden wir uns für wkhtmltopdf als das richtige Werkzeug für die Konvertierung der HTML/CSS-Vorlagen in PDF.

Das Problem

Das Geschäft verfügt über eine Funktion zum Exportieren mehrerer Rechnungen in ein einzelnes PDF. Mit TCPDF konnte ich die Stapeldatei für den beidseitigen Druck vorbereiten, indem nach jeder Rechnung eine leere Seite eingefügt wurde, die vor der Generierung der Datei eine ungerade Anzahl von Seiten hatte. Aber jetzt, da wir zu wkhtmltopdf gewechselt sind, kann ich nicht dasselbe Ergebnis erzielen.

Das entscheidende Problem ist, dass, während wkhtmltopdf die Verwendung mehrerer HTML-Vorlagen zulässt, es scheinbar keinen zuverlässigen Weg für Anzahl der Seiten gibt, die jeweils vor der Generierung der Datei vorliegen. Die Kopf- und Fußzeilenvorlagen können die Seitenzahl erhalten, mit der die Rechnung endet, sie sind jedoch vom Hauptinhalt getrennt und daher kann ich keinen Seitenumbruch einfügen. 

Ich habe auch versucht, den height of the contentPDF page height zu berechnen, aber es gab verschiedene Probleme damit, sobald ich mit dem Export mehrerer Vorlagen begonnen hatte (in Ordnung mit einer einzigen Vorlage). Dieser Ansatz ist auch nicht besonders gut, da durch das Einfügen einer leeren Seite in den Inhalt selbst die Fußzeile auf der neuen Seite angezeigt wird. Dies ist nicht das, was ich will.

_/Mein bester Versuch

Der einzige Weg, wie ich herausgefunden habe, dass ich diese Probleme lösen könnte, ist sehr ineffizient. Jedes Mal, wenn eine Vorlage zum Stapel hinzugefügt wird, konnte ich sie mithilfe einer separaten Instanz von wrapper für wkhtmltopdf vorab generieren, den temporären Dateinamen abrufen, ermitteln, wie viele Seiten mit pdfinfo vorhanden sind, und einen leeren HTML-Code hinzufügen Vorlage an die Hauptinstanz entsprechend. Hier ist ein draft einer Funktion, um die Anzahl der Seiten der zuletzt hinzugefügten Vorlage zu ermitteln (von einer Klasse, die den Wrapper erweitert, basierend auf anderen pdfinfofragen , die ich in SO gefunden habe):

/**
* Return the number of pages in the last invoice template added
* $complete === true => return the length of the entire document
*/
public function getNumPages($complete = false)
{
    if (!$complete) {
        // Generate PDF of last template added

        $tmpPdf = new WKPdf($this->_options);
        $tmpPdf->addPage($this->content, Array(
            'footer-html' => $this->footer
        ));

        /**
           The createPdf method is protected so I need to get 
           the content as string here to force the wrapper to 
           call wkhtmltopdf.
        */
        $tmpPdf->toString();
        $document = $tmpPdf->getPdfFilename();
    } else {

        // Generate entire batch
        $this->createPdf();
        $document = $this->getPdfFilename();
    }

    // Use pdfinfo to get the PDF page count
    $cmd = 'pdfinfo';
    exec("$cmd \"$document\"", $output);

    $pagecount = 0;
    foreach($output as $op)
    {
        // Extract the number
        if(preg_match("/Pages:\s*(\d+)/i", $op, $matches) === 1)
        {
            $pagecount = intval($matches[1]);
            break;
        }
    }

    return $pagecount;
}

Dies ist sehr ineffizient - es dauert etwa 80 Sekunden, bis ein Stapel von 25 Rechnungen erstellt wird, da ich wkhtmltopdf 25-mal aufrufen muss, um die temporären PDF -Dateien zu erstellen, sodass ich pdfinfo 25-mal aufrufen kann, um ihre individuelle Länge und Einfügung zu erhalten ggf. leere Seiten und generieren Sie das endgültige Dokument. 

Der Vorteil von TCPDF besteht darin, dass Sie die Anzahl der Seiten im laufenden Betrieb erhalten können. Eine ähnliche Funktion dauert etwa 5 Sekunden, um eine Stapeldatei mit 25 Rechnungen zu erstellen.

Hat jemand eine Idee, wie man die Dinge beschleunigen kann? Oder eine bessere Idee, dies insgesamt zu tun. Ich habe verschiedene Tools für die Generierung einschließlich dompdf betrachtet, aber wkhtmltopdf ist einfach das mächtigste. Die Batch-Generierung wird eigentlich nur vom Back-Office der Filialadmins verwendet, daher könnten sie vielleicht geduldig sein. Aber dennoch.

10
PeterTheLobster

Leider ist wkhtmltopdf die Bibliothek, die in C geschrieben ist, und wir können nicht dynamisch eine Seite hinzufügen, wie in PHP -Bibliotheken.

Zitat aus Ihrem Kommentar:Aufgrund der Anzahl der bestellten Artikel oder einer Vielzahl von Kundendaten kann jede Rechnung zwischen 1 und 3 Seiten umfassen.

Aus diesem Grund können wir die Anzahl der Seiten nicht vorberechnen und in eine Datenbank schreiben.

Ich denke, Sie haben nur eine Möglichkeit/Lösung: Sie müssen hinter jeder Rechnung eine leere Seite schreiben und nachdem das gesamte PDF erstellt wurde, müssen Sie es mit der kostenlosen PHP -Bibliothek bearbeiten wie FPDI. In Kombination mit FPDI können sogar PDF Dokumente bearbeitet werden.

Bei der Bearbeitung von PDF können Sie alle leeren Seiten löschen, die Sie nicht benötigen, wenn sie mit einer ungeraden Seitennummer beginnen (wie 3, 5 usw.). Und in FPDI haben Sie die Möglichkeit, eine Seitennummer zu ermitteln. Es ist viel schneller als die Lösung, die Sie jetzt verwenden.

Und die leeren (oder leeren) Seiten, die Sie mit FPFI auf content length erkennen konnten, sind wie folgt:

<?php
require('fpdf.php');
require_once('setasign/Fpdi/autoload.php');

class Pdf extends \setasign\Fpdi\Fpdi
{
    private $pdfReader;
    function Header()
    {
        if(is_null($this->pdfReader))
        {
            $readerId = $this->getPdfReaderId('blank-pages.pdf');
            $this->pdfReader = $this->getPdfReader($readerId);
        }

        $page_fpdi = $this->pdfReader->getPage($this->PageNo());
        $this->content = $page_fpdi->getContentStream();

        $this->Cell(0, 15, 'page content length: '.strlen($this->content));
    }

    protected function _putimages(){}
}

$pdf = new Pdf();
$pdf->SetFont('Arial', '', 12);
$pdf->AddPage(); //page content length: 70 // page with 'Hello World!' string
$pdf->AddPage(); //page content length: 30 // empty page
$pdf->AddPage(); //page content length: 30 // empty page
$pdf->Output();
?>

Mein blank-pages.pdf habe ich mit FPDF mit folgendem Code generiert:

<?php
require('fpdf.php');

$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial','B',16);
$pdf->Cell(40,10,'Hello World!');
$pdf->AddPage();
$pdf->AddPage();
$pdf->Output();
?>
2
Bharata