Tutoriel : créer un fichier PDF avec FPDF

Tutoriel : créer un fichier PDF avec FPDF

Encore un billet en rapport avec un tutoriel. Mais cette fois-ci, c'est un brin plus compliqué à mettre en place. Sans vous livrer tous mes secrets de fabrication, je vais vous livrer quelques bases pour construire un fichier PDF à partir d'une base de données.

Utilisation de la librairie FPDF

Pour ce tutoriel, nous allons avoir besoin de la librairie FPDF. Grâce aux fonctions de base, nous allons pouvoir construire de nombreux types de documents. Pour ce tutoriel, je vais vous proposer un mélange d'informations afin d'utiliser au maximum les possibilités de FPDF. Uploadez la librairie FPDF sur votre serveur.

C'est parti ! Nous devons créer un fichier nommé pdf.php par exemple que l'on commence à remplir comme suit :

<?php
// Connexion à la BDD
$bddname = 'nom_de_la_base';
$hostname = 'localhost';
$username = 'utilisateur';
$password = 'mot_de_passe';
$db = mysqli_connect ($hostname, $username, $password, $bddname);

// Appel de la librairie FPDF
require("fpdf/fpdf.php");

A partir de là, nous pouvons commencer à afficher des données. Pour info, si votre base de données est en UTF-8, vous devrez utiliser la fonction utf8_decode pour tous les champs contenant du texte. Rien de bien sorcier, mais il faut y penser pour éviter les caractères exotiques.

Commençons par afficher un logo en header et les coordonnées en footer. Tout le code qui suit sera à ajouter au précédent. Ça m'évitera d'avoir des lignes de code trop longues. :)

// Création de la class PDF
class PDF extends FPDF {
    // Header
    function Header() {
        // Logo
        $this->Image('images/logo-infiniblog.jpg',8,2,80);
        // Saut de ligne
        $this->Ln(20);
    }
    // Footer
    function Footer() {
        // Positionnement à 1,5 cm du bas
        $this->SetY(-15);
        // Adresse
        $this->Cell(196,5,'Mes coordonnées - Mon téléphone',0,0,'C');
    }
}

Je vous ai perdu ? Ne partez pas, je vous explique. Pour le header, je souhaite afficher un logo. J'appelle donc mon image en indiquant le chemin. Le chiffre 8 correspond à la position à gauche du document, le 2 à la position en haut du document et le 80 à la largeur de l'image. La hauteur est calculée automatiquement.

Pour le footer, j'utilise la fonction Cell pour créer une ligne. Le chiffre 196 correspond à la largeur de la ligne et le chiffre 5 à la hauteur. Ensuite j'écris mon texte (ne pas oublier d'échapper les apostrophes). Le premier 0 indique que je ne souhaite pas de bordure, le second qu'il ne doit pas y avoir de retour à la ligne et le C indique que je souhaite centrer mon texte.

Avant d'afficher le PDF, il faut activer la classe et définir quelques paramètres tels que le format du PDF (portrait, en mm et A4) la police et sa taille, ainsi que la couleur du texte par défaut. La fonction AddPage créée le document et permet d'afficher notamment le logo et les coordonnées en pied de page.

// Activation de la classe
$pdf = new PDF('P','mm','A4');
$pdf->AddPage();
$pdf->SetFont('Helvetica','',11);
$pdf->SetTextColor(0);

Voilà concrètement ce que donne l'affichage des ces informations : voir le PDF.

Construire le document depuis la base de données

Nous partons du principe que nous possédons une base de données avec plusieurs tables. Pour l'exemple, je dispose de données clients et de données commandes.

Commençons par afficher deux blocs d'informations. Celui de la commande et les coordonnées du client.

$req = "SELECT id, id_client, date_com, reglement FROM table_commandes WHERE id=".$_GET['id'];
$rep = mysqli_query($db, $req);
$row = mysqli_fetch_array($rep);

// Infos de la commande calées à gauche
$pdf->Text(8,38,'N° de facture : '.$row['id']);
$pdf->Text(8,43,'Date : '.$row['date_com']);
$pdf->Text(8,48,'Mode de règlement : '.$row['reglement']);

Pour la fonction Text, les deux chiffres correspondent à la position gauche puis la position haut pour le placement des informations. Donc on cale ces infos à 8mm de la gauche et 43mm du haut du PDF pour la première ligne. On ajoute 5mm par ligne pour caler les infos les unes en dessous des autres.

$req1 = "SELECT nom, prenom, adresse, code_postal, ville FROM table_clients WHERE id=".$row['id_client'];
$rep1 = mysqli_query($db, $req1);
$row1 = mysqli_fetch_array($rep1);

// Infos du client calées à droite
$pdf->Text(120,38,utf8_decode($row1['prenom']).' '.utf8_decode($row1['nom']));
$pdf->Text(120,43,utf8_decode($row1['adresse']));
$pdf->Text(120,48,$row1['code_postal'].' '.utf8_decode($row1['ville']));

Pour afficher le bloc adresse à droite, j'ai remplacé le premier chiffre 8 par 120. A vous de peaufiner le calage selon vos besoins. Voyons ce que donne le PDF avec ces informations supplémentaires : voir le PDF.

Construction d'un tableau

La ça va nettement se compliquer puisque l'on va construire un tableau pour afficher les lignes de la commande avec un entête doté d'une couleur en background. Qui dit tableau, dit multi-colonnes et filets pour délimiter l'ensemble. Vous pouvez au choix prendre un Doliprane ou vous faire un café. ;)

On commence par créer l'entête du tableau avec quelques paramètres et une fonction dédiée selon le code suit :

// Position de l'entête à 10mm des infos (48 + 10)
$position_entete = 58;

function entete_table($position_entete){
    global $pdf;
    $pdf->SetDrawColor(183); // Couleur du fond
    $pdf->SetFillColor(221); // Couleur des filets
    $pdf->SetTextColor(0); // Couleur du texte
    $pdf->SetY($position_entete);
    $pdf->SetX(8);
    $pdf->Cell(158,8,'Désignation',1,0,'L',1);
    $pdf->SetX(166); // 8 + 96
    $pdf->Cell(10,8,'Qté',1,0,'C',1);
    $pdf->SetX(176); // 104 + 10
    $pdf->Cell(24,8,'Net HT',1,0,'C',1);
    $pdf->Ln(); // Retour à la ligne
}
entete_table($position_entete);

Le premier $pdf->SetX(8) est la position de la première colonne, soit 8mm de la gauche. La valeur 158 correspond à la largeur de la colonne, le 8 à la hauteur. Ensuite le libellé de la colonne, le 1 pour indiquer que l'on souhaite un filet de 1mm, le 0 pour le saut de ligne, le C pour centrer le texte et le 1 pour afficher la couleur de fond.

Vous suivez toujours ? Donc si c'est OK, nous allons afficher les détails de la commande. Pour ce faire, nous allons utiliser la fonction MultiCell, pour créer plusieurs lignes comme son nom l'indique. ;)

// Liste des détails
$position_detail = 66; // Position à 8mm de l'entête

$req2 = "SELECT libelle, qte, prix_ht FROM table_details WHERE id_commande=1";
$rep2 = mysqli_query($db, $req2);
while ($row2 = mysqli_fetch_array($rep2)) {
    $pdf->SetY($position_detail);
    $pdf->SetX(8);
    $pdf->MultiCell(158,8,utf8_decode($row2['libelle']),1,'L');
    $pdf->SetY($position_detail);
    $pdf->SetX(166);
    $pdf->MultiCell(10,8,$row2['qte'],1,'C');
    $pdf->SetY($position_detail);
    $pdf->SetX(176);
    $pdf->MultiCell(24,8,$row2['prix_ht'],1,'R');
    $position_detail += 8;
}

Comme vous le voyez, on appelle les détails de la commande en utilisant while. Comme cela, le script remontera toutes les lignes en rapport avec notre commande. Pour les chiffres, nous avons indiqué les mêmes que l'entête afin de caler les détails sur l'entête. Le 1 et le C, L ou R (centre, left ou right) correspondent à l'affichage du filet et à la position de l'info dans la colonne.

La petite nuance concerne la dernière ligne. Puisque nous sommes dans un while, il faut préciser que chaque nouvelle ligne est positionnée à 8mm en dessous de la précédente.

Il faut penser à donner un nom à votre document PDF lorsque vous souhaitez le télécharger et fermer le document pdf.php :

// Nom du fichier
$nom = 'Facture-'.$row['id'].'.pdf';

// Création du PDF
$pdf->Output($nom,'I');?>

Nous obtenons un superbe tableau en seulement quelques lignes de code : voir le PDF.

Pour appeler le fichier, un simple lien suffit :

<a href='lien-du-fichier.pdf'>Fichier PDF</a>

Voilà c'est fini

Ce tutoriel est à présent terminé. Je vous laisse réfléchir pour afficher d'autres informations comme le total de la facture, une ligne avec un RIB par exemple en cas de paiement par virement ou encore les informations obligatoires à faire apparaître sur une facture (taux de pénalité, indemnité forfaitaire, etc.). Il est tout à fait possible de créer des documents très intéressantes dès que l'on fait travailler ses neurones.

Modèle de document PDF

Une fois que vous maîtriserez ce code, il suffit de 15/20 minutes maxi pour monter le PDF d'une facture. Par contre, pour d'autres documents, faites couler une cafetière, préparez un paquet de gâteaux et armez vous de patience.

Pour la petite info, il m'est arrivé de bosser 5/6 jours sur un même document. Notamment lorsque vous avez une trame en background et qu'il faut placer des données dans des cases comme le code postal par exemple. Il faut décomposer la donnée pour placer chaque chiffre dans les 5 cases prévues à cet effet. Je ne vous dis pas la prise de tête parfois. :)

Catégorie Tutoriels - Écrit par le 02/12/2014 - Article lu 32 554 fois - 22 commentaires

22 réflexions sur ce billet

Écrit par Adrien
Le 10/12/2014 à 02h39

Sinon il existe des librairies HTML to PDF (html2pdf, dompdf). Tellement plus pratique.

Écrit par unequicheeninfo
Le 23/04/2015 à 03h19

Merci beaucoup :D

Écrit par boris yao
Le 02/09/2015 à 18h49

Merci beaucoup ! Votre tutoriel ma vraiment sauvé. Dieu vous bénisse.

Écrit par Duduche75
Le 06/12/2015 à 23h10

Vraiment un grand merci pour la clarté de ces explications. Bravo.

Écrit par Dudu75
Le 01/02/2016 à 00h36

Merci.
Petite question : comment imprimer la bonne hauteur du tableau par rapport au besoin de lignes de la facture ?

Écrit par Manequin
Le 21/05/2018 à 20h40

Salut et merci beaucoup pour ce bon cours. Mais j'ai encore un soucis, comment appeler le fichier pdf ?

Écrit par Hervé
Le 22/05/2018 à 10h37

@Manequin

J'ai ajouté l'explication dans l'article. Merci de me l'avoir signalé. ;)

Écrit par genesis
Le 05/09/2018 à 08h16

Merci beaucoup, c'est clair et détaillé.

Bravo pour ces explications.

Écrit par awizonon
Le 17/03/2019 à 00h16

Bonjour,

Merci pour ton travail. J'ai un soucis. Quand je suis dans le dossier fpdf le pdf s'affiche mais depuis un autre repertoire ça ne marche pas. Quelqu'un aurait une idée ?

Merci

Écrit par fred
Le 18/03/2019 à 15h39

J'ai un tableau dont je connais le nombre de colonnes. Je n'ai pas utilisé de while mais quand j'ai fini d'entrer mes informations, je n'arrive pas à clôturer. Les lignes verticales perdurent jusqu'à la fin de la page et je n'ai pas la ligne verticale qui clôture le tableau.

Écrit par Hervé
Le 19/03/2019 à 10h54

Awizonon

Si tu changes le nom du répertoire, il faut t'assurer de le changer aussi à l'intérieur des fichiers du dossier FPDF.

Commences par faire cette vérification. ;)

Écrit par Fred
Le 19/03/2019 à 10h56

Fred

As-tu regardé dans les logs pour vérifier s'il y avait une erreur ?

Écrit par Safi
Le 13/05/2019 à 01h06

Génial, tout fonctionne, merci infiniment !

Écrit par misterlight
Le 21/05/2019 à 16h14

Je tiens à vous remercier pour ce tutoriel car il va beaucoup m'aider.

Écrit par Moundzele Ray
Le 19/08/2020 à 08h59

Bonjour !

Quelle magnifique tutoriel et une explication sublime. Grâce à vous j'ai très bien compris cette bibliothèque fpdf.

Écrit par Jonathan KALONGA
Le 20/01/2021 à 10h20

Bonjour, j'ai parfaitement sû faire ce tableau, mais la, j'aimerai générer un document PDF non complexe, sans tableau.

Écrit par Hervé
Le 20/01/2021 à 12h23

Jonathan

Pour des PDF plutôt simples, il existe des tutoriels sur le site http://www.fpdf.org/

Écrit par Gildas
Le 04/03/2022 à 17h37

Bonjour Hervé,

Bon j'arrive 8 ans après la bataille, mais votre tuto me sauve la vie !

j'ai une question tout de même, tout votre code fonctionne chez moi j'ai même pu adapter sans soucis à partir de ce que vous avez mis, mais je reste bloqué sur un point les "é" de Désignation et Qté m'apraissent comme ça : "é" une idée d'où ca peut provenir svp ?

Écrit par Hervé
Le 04/03/2022 à 17h45

Bonjour Gildas

Effectivement, 8 ans ça fait un bail. Et quand je vois le code, ça a bien évolué. :-)

Aurais-tu un charset (utf-8 ou autre) qui traînerait quelque part dans le fichier ou sur les identifiants de connexion à la BDD ?

Je ne vois que ça.

Écrit par Gildas
Le 04/03/2022 à 17h50

merci de ton retour rapide,

effectivement dans ma connexion à, la bdd array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8') , (ma connexion ce fait via PDO) .

mais même en l'enlevant ca ne fonctionne pas , et mise à part les utf8_decode, j'ai pas d'autres utf_8

Écrit par Hervé
Le 04/03/2022 à 17h58

Gildas

Tu n'appelles pas de fichier externe via un include ou require autre que la librairie FPDF ?

J'ai déjà eu le cas, à part chercher ce qui cloche, je ne vois pas.

Tu peux jeter un coup d'œil ici dans la rubrique FAQ (sur la gauche). Le point 3 en parle : http://www.fpdf.org/

Écrit par Gildas
Le 04/03/2022 à 18h00

Nop j'ai que le require('fpdf.php) ;

Mais pas grave je les aient mis en majuscule ca sera très bien ,

Merci pour ton aide

Écrire un commentaire

Pseudo

E-mail (non publié)

Votre commentaire

Recevoir une notification par e-mail lorsqu'une réponse est postée

Veuillez recopier le code de sécurité : vk2hhq9j4b

Haut de page