PDF

PDF-Dokumente mit PHP erzeugen

12. Februar 2009
von

PDF-Dateien zu erstellen, ist schon lange kein Problem mehr. Spätestens seit OpenOffice die Möglichkeit bot, Textdokumente ins PDF-Format zu konvertieren (und möglicherweise aufgrund dessen andere namhafte Anbieter nachzogen), ist es für jedermann leicht möglich, seine Informationen in Form eines PDF-Dokumentes anzubieten. Anders sieht es aus, wenn man mal schnell auf seiner Website aktuelle Inhalte “zur Laufzeit” dynamisch in einer PDF-Datei anbieten möchte.

Das wäre zum Beispiel nötig, wenn man Benutzereingaben aus Formularen in diese PDF-Datei integrieren muss. Ein mögliches Szenario wäre ein Bestellformular, welches nach erfolgter Bestellung dem Benutzer die Möglichkeit bietet, eine Bestellung als PDF-Datei auszudrucken/herunterzuladen.

Lösungsansatz / Alternativen

Wie immer gibt es mehrere Lösungen. In unserem Fall wird die PDF-Erzeugung durch Verwendung der Klasse FPDF gezeigt. Diese Klasse ist frei erhältlich und darf sowohl für private als auch für kommerzielle Zwecke genutzt werden. Das ist der erste Grund, weshalb wir FPDF hier verwenden, der zweite ist die Stabilität. Die FPDF-Klasse wird seit 2001 entwickelt und kann sich heute auf die Fahne schreiben, eine relativ einfach zu verwendende, erprobte und stabile PHP-Klasse zu sein. Eine Doku zu FPDF gibt es hier.

Als Alternative zu FPDF muss an erster Stelle PDFlib genannt werden. Diese Klasse ist jedoch nicht auf jedem Webserver verfügbar und Einrichtung und Umfang sind nicht trivial.  Wer sich die Sache trotzdem ansehen möchte, kann diese schön geschriebene Anleitung lesen. Eine andere interessante Alternative könnte TCPDF sein. Der Vollständigkeit halber seien “PDFlib Lite”, “CPDF” und “Zend_Pdf” für das Zend-Framework erwähnt.

Grundlagen / eigene Klasse

Für unsere Übung sollte auf Ihrem Webserver PHP5 laufen. Falls Sie keine Möglichkeit haben PHP5 zu nutzen, sind ein paar kleine Änderungen am Quellcode notwendig, dass die Skripte auch auf PHP4 lauffähig sind. Dazu am Ende mehr.

Am Besten legen Sie sich für die folgenden Versuche ein neues Verzeichnis an (so können Sie dieses eventuell schnell und problemlos wieder löschen, wenn Ihnen die Sache am Ende nicht gefällt). In dieses Verzeichnis entpacken Sie die FPDF-Klasse, die Sie hier herunterladen. Erstellen Sie ein weiteres Verzeichnis neben dem soeben entpackten fpdf-Verzeichnis und nennen es twpdf. Dies ist nur ein Vorschlag, Sie haben freie Auswahl. Manchmal jedoch ist es vorteilhaft, bei den selbst erstellten Verzeichnis-, Datei-, Funktions- und Variablennamen eine Art Vorzeichen anzuhängen, um im Code immer schnell erkennen zu können, was eigene Tests und was vorgegebene, erprobte Dinge sind. Alles was wir in unseren Übungen “probieren” erhält die “Vorsilbe” tw, so beugen wir dem versehentlichen Löschen der FPDF-Klasse vor.

Am Ende sollten Sie jedenfalls eine Verzeichnisstruktur ähnlich der im folgenden Bild vorliegen haben:

ss001 foto

Testklasse01

Beginnen wir mit einer kleinen Testklasse um die grundlegenden Dinge kennenzulernen und gleichzeitig eine Art Vorlage für alle späteren Arbeiten zu haben.

// unsere Testklasse erbt von der FPDF-Klasse
class Testklasse01 extends FPDF {

	// hier werden die Variablen für diese Klasse deklariert (also: "bekanntgemacht")
	private $twVariable01 = "";
	private $twVariable02 = ""; 

	// der Konstruktor dieser Klasse
	function __construct() {
		// Konstruktor der vererbenden Klasse aufrufen (also den von FPDF)
		parent::__construct("P", "mm", "A4"); // L=Querformat(Landscape), P=Hochformat(Portrait)

		// hier werden die Variablen dieser Klasse initialisiert (also: "gefüllt")
		$this->twVariable01 = "Hallo, ich bin der Probetext aus Testklasse01";
		$this->twVariable02 = date("d.m.Y");

		// Einstellungen für das zu erstellende PDF-Dokument
		$this->SetDisplayMode(100);      // wie groß wird Seite angezeigt(in %)

		// Seite erzeugen (sozusagen: starten)
		$this->AddPage();
	}	

	// eine Funktion zur Anzeige des Inhalts
	function Header() {
		$this->SetFont("Arial","B","16");                    // Schrift
		$this->SetTextColor(255, 000, 000);                  // Schriftfarbe
		$this->SetXY(20, 50);                                // Position
		$this->Cell(90, 10, $this->twVariable01, 1, 1, "L"); // Box(Textbox)
	}	

	function Footer() {
		// Farben und Schrift allgemein
		$this->SetFont("Courier","I","9");
		$this->SetTextColor(180);
		$this->SetXY(25, 288);
		$this->Cell(170, 5, "dieses Dokument wurde am ". $this->twVariable02. " erstellt", 1, 1, "R");
	}
}
// ACHTUNG: darf kein Zeichen hinter phpend sein (auch kein Leerzeichen) !!!

Testklasse01.php

Diese kleine Testklasse könnte einfacher aufgebaut sein, doch für umfangreichere PDF-Dokumente später ist es ratsam, sich schon jetzt diesen Aufbau mit Variablendeklarationen, Konstruktor, Header uns Footer anzugewöhnen. Der abgebildete Quellcode sollte anhand der eingefügten Kommentare selbsterklärend sein. Trotzdem an dieser Stelle Erläuterungen zu den FPDF-Funktionen:

  • Zeile 12: Ruft den Konstruktor der (vererbenden) FPDF-Klasse auf und setzt dabei das Papierformat, Maßeinheit und Papiergröße.
  • Zeile 19: SetDisplayMode() legt fest, wie das Dokument angezeigt werden soll, also mit welchem Zoomfaktor.
  • Zeile 22: AddPage() Erzeugt eine neue Seite im Dokument (beziehungsweise überhaupt eine Seite).
  • Zeilen 26 bis 32: Header() Erzeugt den Header der Seite. Kann jedoch auch für den gesamten Seiteninhalt verwendet werden.
    • SetFont() Bestimmt Schriftart, Style (B=fett, I=kursiv, U=unterstrichen) und die Schriftgröße. Die geringe Auswahl an Schriftarten ist derzeit das größte Manko von FPDF, aber mal Hand aufs Herz, wieviele verschiedene Schriftarten verwendet man schon in einem Dokument?
    • SetTextColor() Bestimmt die Textfarbe. Angabe bsp. (220, 000, 110) oder nur (220) (steht für (220, 220, 220)).
    • SetXY() Position von linken oberen Seitenrand (x=horizontal, y=vertikal). Bestimmt den Punkt, an dem es weitergeht.
    • Cell() Zeichnet eine neue Zelle (oder halt Box) im Dokument. Diese kann optional Text, einen Rahmen und einen Hintergrund erhalten. Die linke obere Ecke beginnt an dem zuvor mit SetXY() zugewiesenem Punkt. Die Zellenbreite und -höhe wird in den beiden ersten Parametern festgelegt.
  • Zeilen 35 bis 41: Footer() Die Fußzeile sozusagen.

php-Skript, welches das PDF-Dokument ausgibt, indem es die Testklasse01 benutzt

Es folgt der Code für die php-Datei. Erläuterungen folgen im Anschluss.

// ACHTUNG: darf kein einziges Leerzeichen vor phpstart sein, wegen header!

// FPDF-Klasse und das Verzeichnis der FPDF-Schriftarten einbinden
define("FPDF_FONTPATH","fpdf16/font/");
include_once('fpdf16/fpdf.php');

// unsere selbsterstellte Testklasse01 einbinden
include_once("twpdf/Testklasse01.php");

// pdf erzeugen (aus unserer selbsterstellten Testklasse01)
$pdf = new Testklasse01();  

// pdf ausgeben (im Browser oder in Datei schreiben)
$pdf->Output();   // Ausgabe (wenn in Datei schreiben, dateiname in Klammer)

// ACHTUNG: in der aufgerufenen Klasse darf kein Leerzeichen hinter phpende sein!

testseite01.txt

  • Zeile 4 und 5: Hier werden die FPDF-Klasse und die Schriftarten eingebunden.
  • Zeile 8: Hier binden wir unsere selbst erstellte Klasse ein.
  • Zeile 11: Ein Objekt erzeugen von der Testklasse01.
  • Zeile 14: Output() Output gibt das PDF-Dokument aus, beziehungsweise, wenn man als Argument einen Dateiname angibt, dann wird eine PDF-Datei auf dem Server angelegt.

Wenn Sie kein PHP5 auf Ihrem Webserver nutzen können

Wenn Ihnen kein PHP5 zur Verfügung steht, benutzen Sie für dieses Beispiel folgende Dateien.

Der Unterschied dieser beiden Dateien zu den vorgestellten Dateien ist gering. Hier wurden nur die “private/public-Angaben” umgeändert in “var” und der Konstruktoraufruf der vererbenden Klasse hat eine andere Syntax. Diese kleinen Unterschiede in den Dateien haben jedoch keinen Einfluss auf unsere Beispiele. Also, falls Sie beim Testen unserer Beispiele eine ähnliche Fehlermeldung wie die folgende erhalten, dann läuft auf Ihrem Webserver kein PHP5.

ss002 foto

Ein erstes Beispiel

An dieser Stelle könnte jetzt ein Anwendungsbeispiel erscheinen. Man könnte eine einfache Rechnung zu generieren – so es wie dieses Beispiel zeigt. Aber vielleicht haben Sie ganz andere Ideen…

 foto

Thomas Weise

Thomas Weise ist gelernter Anwendungsentwickler. Ihn zog es aber immer schon in Richtung Internet und Webentwicklung. Seine Artikel auf drweb sind Gastartikel, selbst bloggt er auf

33 Kommentare zu „PDF-Dokumente mit PHP erzeugen

  1. Konrad am 12. Februar 2009 um 09:55

    Für alle, die auf die Textsatzqualitäten von LaTeX schwören, gibt es ein ebenfalls frei erhältliches Plugin für das Web-Framework Symfony.

    Hier eine Demo, wie HTML-Tags “zur Laufzeit” von LaTeX ansprechend in ein PDF-Formular umgesetzt werden:
    http://symfony.ibr-oss.de/demo/HtmlInput/

    Das Erklärung dazu (in englisch) hier:
    http://symfony.ibr-oss.de/article/how-to-use-rich-text-editing-with-pdflatex/

  2. Paul am 12. Februar 2009 um 10:30

    Ich möchte kurz auf die fehlerhaften Pfeile in den Methodenaufrufen aufmerksam machen.

    -> : ->

  3. Sylvia am 12. Februar 2009 um 11:02

    Ich benutze FPDF schon seit einiger Zeit – bin bis jetzt sehr zufrieden damit!

  4. Marco Philipeit am 12. Februar 2009 um 13:21

    FPDF ist eine klasse Sache, die ich schon seit längerem erfolgreich einsetze. Der einzige Nachteil ist, dass der Erstellungsprozess der PDF-Datei durch die begrenzten Möglichkeiten mit “Cell” etc. doch sehr langwierig ist und Funktionen, die versprechen aus HTML ein PDF zu erzeugen, diese Aufgabe nur sehr bedingt ausführen. Für Optimierungsvorschläge/Ideen zur schnelleren Erstellung wäre ich persönlich daher sehr dankbar!

  5. PDF-Dateien am webServer » Guru 2.0 am 12. Februar 2009 um 13:31

    [...] als pdf-Datei verfügbar sind. Eigentlich sollte dies kein Problem sein, aber…Daher habe ich bei Dr. Web eine gute Anleitung für die Verwendung von FPDF (Dokumentation zu FPDF) mit PHP gefunden. Damit sollte es eigentlich [...]

  6. PHP_User am 12. Februar 2009 um 14:04

    PD4ML ist auch eine gute Alternative. Ist zwar nicht kostenlos, aber wer eine schnelle Generierung von von HTML->PDF braucht, wird hier fündig. Es ist eine Java-Klasse (ergo braucht man die Möglichkeit Java auf dem Server zu installieren), aber es lohnt sich. Man kann der Klasse eine URL geben und diese Seite wird dann inkl. “aller” (ok nicht aller, aber fast) CSS-Eigenschaften gerendert. Somit umgeht man das zeitaufwendige Erstellen des PDF-Exports in FPDF. Außerdem ist man wesentlich flexibler, wenn etwas geändert werden muss. Z.B. wenn ein neues Design eingearbeitet werden muss. Ich will keine Werbung für das Tool machen, aber es hat mir für “nur” 160 Euro jede Menge Stress auf Arbeit erspart.
    http://pd4ml.com/php.htm

  7. Franz König am 12. Februar 2009 um 15:30

    super Sache!

  8. gossi am 12. Februar 2009 um 16:22

    Gibt es denn eine Möglichkeit, XML -> XSLT/FO -> pdf zu transformieren über php ohne den apache als post-processor? Kennt da jemand was?

  9. Thomas Weise am 12. Februar 2009 um 16:23

    @Paul: Danke für den Tipp, ich hatte das gar nicht bemerkt :(.
    Ich bekomms nur immer noch nicht weg. Der Code-Formatierer (das WP-Plugin WP-Syntax) hat Probleme damit, egal was ich für das “>” auch reinschreibe…
    Naja, ich such mal noch weiter, vielleicht kennt sich ja auch jemand mit dem Plugin aus.

  10. Christian Scholz-Flöter am 12. Februar 2009 um 20:10

    Ein sehr schönes Tutorial, das nebenbei auch gleich noch Einblick in Objekt orientierte Programmierung unter PHP gibt.
    Ich hoffe, dass alle LeserInnen, die deinen Beispielcode ausprobieren möchten, so pfiffig sind, die zerschossenen Zeichen (>) zu ersetzen.

    Vielen Dank!

    Thomas, verfasst du deine Artikel denn im “HTML”- oder “Visual”-Modus? Viele Syntax Highlighting-Skripte haben offenbar mit Letzterem Probleme. Im “HTML”-Modus könnte es vielleicht besser laufen, auch wenn der Komfort dann etwas eingeschränkt ist.

  11. Thomas Weise am 12. Februar 2009 um 22:06

    @Christian: Ich schreib im HTML-Modus.
    Hab das Problem nun auch ausgemacht: das Plugin “WP-Syntax” hat dieses Problem in seiner neuesten Version 0.9.2 schon behoben, diese Version is aber leider hier nicht lauffähig…

    Ich hab deshalb erstmal über die Quellcodebeispiele je einen Link gemacht. Wenn man den anklickt, kann man den richtigen Quellcode dann dort kopieren.

    Ich weiß, das ist vielleicht erstmal nicht die eleganteste Lösung…

  12. L-Roy am 13. Februar 2009 um 09:49

    Für unsere Praktikanten kommt der Artikel drei Wochen zu spät. *hehe*

  13. Nie Mand am 14. Februar 2009 um 15:21

    Hallo,
    FDPF ist eine feine Sache. Doch immer wieder eine PDF Datei zu generieren für wenig veränderten Inhalt ist nicht mein Ansatz. Ich versuche daher seit einiger Zeit mir einfach PDF-Templates erstellen, in denen der Inhalt über vorher eingefügte Formularfelder gesetzt wird…

    Kenn jemand eine – FREIE – Klasse die das einfügen von Daten in PDF-Formularfeldern ermöglicht?

  14. Stefan (Famkee GmbH) am 14. Februar 2009 um 22:20

    Vielen Dank für die tollen Tipps!

  15. Heinz Meyer am 21. Februar 2009 um 12:07

    Hallo,

    habe gerade das Testprogramm ausprobiert und bin erfreut dass es anstandslos funktioniert hat. Ich hätte mich noch über das Anwendungsbeispiel zum erzeugen einer Rechnung gefreut. Da ich so etwas vorhabe.

  16. Heinz Meyer am 26. Februar 2009 um 15:26

    Hallo,

    Habe inzwischen die ersten Formulare erstellt. Prima!!

  17. Thomas Weise am 27. Februar 2009 um 09:30

    Hab am Ende des Artikels noch einen Link eingefügt, wegen dem Syntaxhighlighting in der Quellcode-Darstellung.

  18. Tom am 3. März 2009 um 13:45

    Bitte um ein Anwendungsbeispiel / Klasse zum erzeugen einer Rechnung wie im letzten Abschnitt gezeigt. Wird dringend benötigt.

  19. Metanormal am 11. März 2009 um 04:38

    Moin Moin Nie Mand,

    >Kenn jemand eine – FREIE – Klasse die das einfügen von Daten
    >in PDF-Formularfeldern ermöglicht?
    Ich nutze sehr einfach die FPDF-Erweiterung FPDI für nicht ganz was du suchst.
    Ich habe ein fertiges “leeres” PDF und importiere mit der FPDI die fertigen PDFs und schreibe die Formular-Felder einfach nur drüber.
    Der Nachteil: keine dynamischen Form-Elemente am Ende.

    Ich kenne leider auch kein Tool, dass die Formular-Felder erhält.

    Viel Erfolg, Metanormal

  20. Inge am 12. März 2009 um 08:16

    Sie schreiben, dass hier ein Anwendungsbeispiel folgen könnte… Mich würde die PDF-Rechnung interessieren.

  21. Inge am 18. März 2009 um 14:24

    Ich möchte nicht aufdringlich sein, aber kann ich noch mit einem richtigen Anwendungsbeispiel rechnen?
    Das Generieren einer Rechnung würde mich sehr interessieren.

  22. Thomas Weise am 20. März 2009 um 15:34

    @Inge, @Tom, @Heinz: Ich werd noch einen Artikel über die PDF-Rechnung schreiben. Wenn ihr noch ca 2 Wochen warten könnt…?

  23. PDF-Rechnung mit PHP erzeugen am 8. Mai 2009 um 08:51

    [...] setzen den Artikel PDF-Dokumente mit PHP erzeugen fort und erstellen die Grundlage einer Rechnung im PDF-Format direkt auf dem Server. Zur Anwendung [...]

  24. PDF-Dokumente mit PHP erzeugen am 31. Mai 2009 um 17:59

    [...] the article here: PDF-Dokumente mit PHP erzeugen Share and [...]

  25. Sascha Tatomir am 9. Juli 2009 um 00:06

    Gelernter Anwendungsentwickler ???????? Thomas mit Schnurrrrbart, diese Hochstaplerei kann ich nicht verdauen

    Du hast wohl nicht soviel Ahnung von der Webapplikationsprogrammierung, weil du erstens zum Thema keine Lösung gegeben hast, obwohl die schon seit Lichtjahren bekannt ist und zweitens, diese Site eher eine
    Art indireckter Selbstdarstellung ist. Soll den Anschein von Professionalität erwecken.

    Gelernter Maurer passt eher zu dier, das gibts auch in der
    Realität.

  26. Thomas Weise am 22. Juli 2009 um 10:54

    @Sascha Tatomir: Danke für die Blumen ;-)
    Zu welchem Thema hab ich keine Lösung gegeben?
    Welche Seite meinst du mit “indireckter Selbstdarstellung”?
    Ich weiß wirklich nicht was du meinst.
    … Maurer hab ich nicht gelernt.

  27. Stanley am 28. November 2009 um 21:05

    Hallo,

    ich habe das Problem, das ich die Texte die ich mit fpdf erzeugt habe in Grafiken (kurven) umwandeln möchte, gibts da schon eine Lösung?

    Vielen Dank im Voraus

  28. [...] in dem Dr.Web-Artikel von Thomas Weise ausführlich auf die Installation von FPDF eingegangen wurde, kann ich mich hier zu diesem Thema sehr kurz fassen. Von der FPDF-Webseite die [...]

  29. Marko am 13. April 2010 um 01:26

    Hat das schon mal jemand mit einem Gambio Shop zum Laufen gebracht? Der eigene PDF-Editor lässt sich ja kaum konfigurieren.

  30. Steusi am 13. April 2010 um 12:55

    Ich habe schon sehr erfolgreich mit FPDF Rechnungen erstellt, funktioniert wunderbar und der Einstieg ist sehr einfach.
    Mein Problem momentan ist ein automatischer Ausdruck. Mittels JavaScript ist es soweit möglich, das der User nur noch OK klicken muss damit der Druck abläuft, doch bei 100 automatisch generierten PDF-Dateien, ist dies keine Lösung.
    Falls jemand einen Trick kenn, wie ich das Problem lösen kann, wäre ich sehr dankbar!

    Sonst geht es nur mittels system() um Befehle vom Webserver ausführen zu lassen!

  31. Dave Remmel am 25. Mai 2010 um 15:03

    Vielen Dank für das Tutorial!
    Imo ist es allerdings relativ witzlog eine PDF-Rechnung als Beispiel zu zeigen ohne das Script das sie erstellt hat. Wie eine Rechnung aussieht weiß ich auch so.

  32. Alex am 1. Juni 2010 um 07:18

    Hallo,

    ich habe eine Komplette Rechnungserstellung für dieses Script gebastelt.
    http://sourceforge.net/projects/php-pdf-invoice/
    Im Browser kann man über eine PHP Webseite eine Rechnung für Kunden erstellen. Das PDF wird ausgegeben oder direkt per E-Mail an den Kunden versendet. Das Programm wurde ursprünglich für Webhoster entwickelt. Jede andere Art der Rechnung ist aber problemlos, genau so möglich!
    Würde mich freuen irgend welche Feedbacks dazu bekommen. Was kann man noch verbessern/ändern?

    Grüße Alex

  33. johnny am 11. Juni 2010 um 18:52

    Wo schreib ich den link zur html rein?

Ein Kommentar? Schön!

Wir freuen uns immer über Leser, die durch nützliche und konstruktive Beiträge zum Thema eine Diskussion anstoßen oder den Artikel mit weiteren Informationen anreichern. Alle Kommentare werden in diesem Sinne moderiert. Zum Kommentar-Fairplay gehört für uns auch der Einsatz von rel="nofollow". Bitte verwenden Sie zudem als Namen weder eine Domain noch ein spamverdächtiges Wort. Vielen Dank!

*