IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Créer un PDF en PHP, la solution ultime ?

Date de publication : 27/04/2010 , Date de mise à jour : 27/04/2010

Par Olivier Van Hoof (ovh) (Mes autres articles)
 

Produire des documents PDF est un besoin récurrent pour beaucoup de sites web, et en général assez pénible à réaliser. Cet article présente une solution universelle, simple et très puissante de conversion HTML en PDF : wkhtmltopdf. Basé sur le célèbre moteur webkit, cet outil produit un rendu inégalé comparé à toutes les autres solutions existantes.

               Version PDF   Version hors-ligne

1. Présentation de wkhtmltopdf
2. Comparaison avec d'autres outils classiques en PHP
3. Définition de la solution retenue et installation des outils
4. Utilisation en PHP avec Zend Framework
4.1. Réaliser la vue HTML
4.2. Création de la classe PHP
4.3. Appel de la classe et rendu du PDF
5. Conclusion


1. Présentation de wkhtmltopdf

wkhtmltopdf est un outil exécutable en ligne de commande qui convertit une URL quelconque en document PDF, et accepte un nombre élevé de paramètres (orientation et dimensions de la page, marges, en-tête, pied de page, etc.), le tout sous licence libre (GPL). Son principal atout est un rendu impeccable : il supporte parfaitement le html et css et même le javascript ! Il suffit donc de produire une vue html avec toutes les assistances modernes pour la mise en page (css... ) pour obtenir un PDF qui est une véritable impression d'écran de ce qu'on verrait sur un navigateur web. Ce logiciel apporte un gain de productivité énorme comparé aux solutions classiques de création de PDF avec des fonctions de dessin, ou même comparé aux autres outils de conversion qui n'offrent qu'un support très faible voire inexistant pour les css ou l'html évolué.

Avantages
  • Rendu d'une qualité quasi parfaite, inégalé par les autres outils existants : supporte tout le html, css et même le javascript
  • Rapide
  • Universel : utilisable en ligne de commandes, donc indépendant du langage utilisé
Inconvénients
  • Nécessite l'installation de dépendances, il faut donc avoir la main sur l'hébergement (serveur dédié ou virtuel requis, un hébergement mutualisé n'est pas suffisamment souple)
  • Requiert l'exécution d'un binaire externe à l'application web, brèche potentielle dans la politique de sécurité
Exemple d'utilisation :
wkhtmltopdf http://www.flickr.com exemple.pdf
La liste complète des paramètres et options possibles est disponible par la commande :
wkhtmltopdf --help
Pour plus d'informations, voyez le site officiel : http://code.google.com/p/wkhtmltopdf/


2. Comparaison avec d'autres outils classiques en PHP

Les outils de génération PDF peuvent se classer en plusieurs catégories :

  Conversion HTML vers PDF Création PDF (fonctions de dessin)
Exécutables externes wkhtmltopdf, html2ps  
Classes PHP DOMPDF, HTML2PDF FPDF, TCPDF, FPDI
Encore aujourd'hui, une des bibliothèques les plus connues pour générer du PDF en PHP est FPDF (écrite en PHP4). Elle offre déjà une solution certes plus conviviale que la lib PDF de base fournie avec PHP, mais cela nécessite toujours de décrire le PDF en utilisant des fonctions de dessin. Il faut donc calculer les dimensions et positions de tous les éléments au millimètre près, la génération de tableaux est un calvaire... TCPDF est une lib de seconde génération (PHP5), fortement inspirée de FPDF, mais quelque peu améliorée en ce sens qu'elle supporte de l'HTML très rudimentaire pour les cellules de texte. Mais cela reste toujours dans l'essentiel des fonctions de dessin peu pratiques.

Les convertisseurs html vers pdf tels que dompdf, html2pdf ou html2ps sont des solutions séduisantes en théorie, puisque la mise en page est réalisée entièrement en html (donc facile à faire), par contre la conversion est de qualité très médiocre, les CSS n'étant quasiment pas supportés, on est limité à un HTML très basique. Dompdf s'en sort le moins mal, html2pdf présentant l'inconvénient majeur d'exiger un code html parfaitement aux normes, il ne tolère absolument aucun écart, contrairement à tous les navigateurs. En pratique ces outils sont donc quasiment inutilisables sans de fastidieuses retouches et adaptations de vues html existantes coûteuses en temps.

FPDI est un peu à part, car c'est une surcouche à FPDF ou TCPDF (il fonctionne avec les 2) qui est fait pour fusionner plusieurs fichiers PDF (fonctionalité de templating). Ce qui offre une possibilité qui séduira immédiatement les professionnels : l'utilisateur (client) peut fournir un modèle PDF avec en-tête et pied de page de sa société réalisé avec n'importe quel logiciel de mise en page (et donc offrant toute liberté créative), le développeur n'a alors plus qu'à réaliser le contenu "brut" en PDF et le fusionner avec le modèle. Le PDF final est une instance d'un objet FPDF ou TCPDF, ce qui permet de le personnaliser directement avec les méthodes de la classe parente, par exemple pour réaliser des en-têtes/pieds de page automatiques (contenant le numéro de page, ou autre).


3. Définition de la solution retenue et installation des outils

Maintenant que nous avons fait le tour des solutions existantes, nous pouvons réaliser le scénario suivant dans le cadre d'une application web :

  • Le client fournit une maquette PDF aux couleurs de sa société, en laissant un grand blanc au milieu de la page où viendra se placer le contenu. Le modèle peut inclure un en-tête, un pied de page, un cadre décoré et des motifs graphiques quelconques...
  • Nous mettrons en page le contenu PDF au moyen d'une vue HTML utilisant quasiment les mêmes CSS que ceux de l'application web principale. Si on peut effectivement partir d'une page web normale, il faudra au minimum retirer tout ce qui est inutile comme les menus, ou certaines trames de fond qui ne sont pas faites pour l'impression. Le gain en productivité est cependant conséquent puisque nous manipulons de l'html/css normal, sans limitation, même le javascript est supporté en cas de besoin.
  • Le PDF du contenu est généré dans un fichier temporaire en appelant wkhtmltopdf, et ensuite nous utiliserons le couple FPDI / TCPDF pour le fusionner avec le template PDF fourni pour produire le document final. Un en-tête et pied de page sera ajouté à la demande, avec un affichage automatique du numéro de page courant par rapport au nombre de pages total du document.
  • Afin de permettre une réutilisation aisée, nous réaliserons le processus métier au moyen de classes de haut niveau, et nous intégrerons la vue "pdf" à une application Zend Framework pour illustrer une application MVC moderne.
Il faut donc télécharger les lib FPDI et TCPDF et les rendre disponible dans un répertoire dans notre application web. Pour wkhtmltopdf c'est un peu différent. Il faut d'abord télécharger le binaire pour notre environnement sur leur site. Ensuite il faut installer le moteur webkit de Qt, ce qui se fait très simplement sur un OS linux à base de Debian :
apt-get install libqt4-webkit
Cela peut se faire sans risque sur un serveur sans environnement graphique, aucun serveur X ni service quelconque ne sera installé, il y aura juste les lib graphiques indispensables :
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances      
Lecture des informations d'état... Fait
Les paquets supplémentaires suivants seront installés :
  defoma fontconfig fontconfig-config libaudio2 libfontconfig1 libfreetype6 libice6 libjpeg62 liblcms1 libmng1 libqt4-dbus libqt4-designer libqt4-network libqt4-qt3support libqt4-script libqt4-sql
  libqt4-sql-mysql libqt4-xml libqtcore4 libqtgui4 libsm6 libtiff4 libxi6 libxrandr2 libxrender1 libxt6 qt4-qtconfig ttf-dejavu ttf-dejavu-core ttf-dejavu-extra
Paquets suggérés :
  defoma-doc dfontmgr psfontmgr x-ttcidfont-conf nas libfreetype6-dev liblcms-utils libqt4-dev
Paquets recommandés :
  libft-perl
Les NOUVEAUX paquets suivants seront installés :
  defoma fontconfig fontconfig-config libaudio2 libfontconfig1 libfreetype6 libice6 libjpeg62 liblcms1 libmng1 libqt4-dbus libqt4-designer libqt4-network libqt4-qt3support libqt4-script libqt4-sql
  libqt4-sql-mysql libqt4-webkit libqt4-xml libqtcore4 libqtgui4 libsm6 libtiff4 libxi6 libxrandr2 libxrender1 libxt6 qt4-qtconfig ttf-dejavu ttf-dejavu-core ttf-dejavu-extra
0 mis à jour, 31 nouvellement installés, 0 à enlever et 6 non mis à jour.
Il est nécessaire de prendre 21,1Mo dans les archives.
Après cette opération, 50,2Mo d'espace disque supplémentaires seront utilisés.

4. Utilisation en PHP avec Zend Framework

Nous partons d'une application MVC standard du type de celle décrite dans ce tutoriel.

schéma workflow / relations objets

Au niveau de l'application web, le contrôleur nécessite 2 actions :

  • Une action qui rendra la vue html qui sera utilisée pour produire le PDF.
  • Une action qui appelera notre classe PDF pour effectuer le rendu et envoyer le résultat au client web.
D'autre part, le layout de la vue html doit être distinct du layout général de l'application, pour supprimer les blocs non désirés pour l'impression tels que le menu, l'en-tête, le pied de page...


4.1. Réaliser la vue HTML

Dans le contrôleur
public function pdfviewAction() {
    $this->_helper->layout->setLayout('pdf');
    // ici : charger les objets métiers et les rendre disponibles pour la vue (pdfview.phtml)
}
Difficile de présenter un code pour le layout de vue, cela dépend de votre présentation. Supprimez toutes les décorations inutiles à l'impression. Pour les CSS, vous pouvez utiliser un nouveau fichier CSS que vous chargerez en dernier et qui surchargera certains styles des vues standards :
Dans le header du layout
echo $this->headLink()->setStylesheet(
		'/gui/css/base.css',
		'all'
	)->appendStylesheet(
		'/gui/css/pdf.css',
		'all'
	);

4.2. Création de la classe PHP

blabla


4.3. Appel de la classe et rendu du PDF

blabla
Dans le contrôleur
public function pdfAction() {
	$this->getResponse()->clearBody();
	$this->_helper->layout->disableLayout();
	$this->_helper->viewRenderer->setNoRender();
	
	$url = 'http://www.monapplication.local/module/controleur/action/parametre/'.$this->getRequest()->getParam('parametre');

	$pdf = new Application_Tools_Pdf(array(
		   'url' => $url,
		   'margins' => array(
			   'top' => '15',
			   'left' => '10',
			   'right' => '10',
			   'bottom' => '10',
		   ),
		   'template' => 'template.pdf',
		   'orientation' => Application_Tools_Pdf::PORTRAIT,
		   'header' => array(
				   'position' => array(218, 22),
				   'align' => Application_Tools_Pdf::LEFT,
				   'content' => $this->_translate->_("Exemple d'en-tête"),
			   ),
		   'footer' => array(
				   'position' => array(0, -6),
				   'align' => Application_Tools_Pdf::RIGHT,
				   'content' => $this->_translate->_("Page {NumPage}/{CountPages}"),
			   ),
	   ));
	$pdf->output('facture.pdf');
}

5. Conclusion

wkhtmltopdf combiné à FPDI forme un couple gagnant permettant de produire rapidement des PDF visuellement attractifs répondant au plus près des besoins classiques des applications web professionnelles. Les classes que j'ai présentées ont pour but d'utiliser cette solution facilement dans n'importe quel projet PHP, Zend Framework en particulier (mais pas seulement), utilisez-les si bon vous semble. N'hésitez pas à me faire part de vos commentaires constructifs.



               Version PDF   Version hors-ligne

Valid XHTML 1.0 TransitionalValid CSS!

Copyright (c) 2005-2010 Olivier Van Hoof. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. Read the full license here : http://www.gnu.org/licenses/fdl.txt