Generation de fichiers pdf en php

Dimanche, 02 Janvier 2011 10:19
Évaluez cet article
(19 votes)

La classe fpdf permet de générer des fichiers pdf en php4 ou php5 sans nécessiter d'extension ou de fichier particuliers. Il n'y a aucune restriction quant a l'utilisation de cette classe que ce soit dans vos projets commerciaux ou non.

Le site du projet est particulièrement bien fourni avec une documentation en français claire et de nombreux scripts utiles: www.fpdf.org

J'ai pour ma part picoré un peu de tous ces scripts pour créer une classe afin de générer une facture. Les fonctionnalités que j'utilise sont la création d'un tableau avec MultiCells permettant les retour à la ligne pour chaque ligne de la table, vérification du débordement de page. Tester le code ici

Voici la classe pdf étendue de la classe fpdf, elle n'est pas parfaite mais permet de générer des factures sans problèmes. Je suis ouvert à toutes propositions pour améliorer le code ou ajouter des fonctionnalités utiles.

Classe pdf

// Inclusion des librairies
include "include/fpdf.class.php";
define("TVA",0.196);

/**
* Classe PDF hérite de fpdf, permet de générer des fichiers PDF
*/


class pdf extends fpdf{

/**
* Constructeur
*/


function pdf(){
parent::fpdf();
$this->SetCreator("Damien BARRERE, www.crac-design.com");
}

//En-tête de la facture
function hautDePage(){
$position=0;

//Logo
$this->Image($_SERVER["DOCUMENT_ROOT"].'/canaillou.jpg',10,3,200);

//Adresse
$this->SetFont('Arial','B',12);
$this->SetTextColor(0,0,200);
$this->SetXY(10,30);
$this->Cell(50,6,"www.Crac-Design.com",0,2,'',false);
$this->SetFont('Arial','',12);
$this->SetTextColor(0,0,0);
$this->MultiCell(50,5,"Adresse de l'entreprise\nCP VILLE\nTel: 05.00.00.00.00\nFax: 05.00.00.00.01",0,'L',false);

//Informations Facture
$this->SetXY(60,30);
$this->SetFillColor(200,200,200);
$this->SetFont('Arial','B',15);
$this->Cell(140,6,"FACTURE",1,2,'C',true);
$this->SetFont('Arial','',12);
$this->SetXY(60,38);
$this->MultiCell(130,5,"Facture n° : Votre numéro de facture\nDate de commande : ".date("m.d.y")."\nMode de paiement : Carte Bancaire",'','L',false);
$this->SetTitle("Facture n° : Votre numéro de facture");


//Adresse de Facturation
$this->SetXY(10,60);
$this->SetFillColor(200,200,200);
$this->SetFont('Arial','B',12);
$this->Cell(90,6,"Adresse de facturation",1,2,'C',true);
$this->SetFont('Arial','',12);
$this->MultiCell(90,5,"Client NOM Prénom\nAdresse 1\nAdresse 2\nCode Postal Ville",'LRB','L',false);
$position=$this->getY();

//Adresse de livraison
$this->SetXY(110,60);
$this->SetFillColor(200,200,200);
$this->SetFont('Arial','B',12);
$this->Cell(90,6,"Adresse de livraison",1,2,'C',true);
$this->SetFont('Arial','',12);

$this->MultiCell(90,5,"Livraison à l'adresse de facturation",'LRB','L',false);

if($this->getY()>$position){
$position=$this->getY();
}
$this->SetXY(10,$position+5);
}

//Préparation de la génération de la table
function tableArticles(){
$position=0;
$prixTotal=0;

//Création des données qui seront contenues la table
$datas = array();
for($ij=0;$ij<50;$ij++){
$datas[] = array("ABCD","Désignation de l'article $ij","10".chr(128),"2","20".chr(128));
$prixTotalHorsTaxes+=20;
}

//Tableau contenant les titres des colonnes
$header=array('Réf','Désignation','Prix Unitaire HT','Qté','Prix Total HT');
//Tableau contenant la largeur des colonnes
$w=array(20,102,25,20,23);
//Tableau contenant le centrage des colonnes
$al=array('C','L','C','C','C');

//Génération de la table à proprement dite
$this->table($header,$w,$al,$datas);

//On se positionne en dessous de la table pour écrire le total
$this->SetY($this->GetY()+5);

$this->setX(108);
$this->Cell(74,6,"Total Hors Taxes",1,0,'L');
$this->Cell(19,6,$prixTotalHorsTaxes.chr(128),1,2,'C');

$this->setX(108);
$this->Cell(74,6,"TVA à ".(TVA*100)." %",1,0,'L');
$totalTVA = $prixTotalHorsTaxes*(TVA).chr(128);
$this->Cell(19,6,$totalTVA,1,2,'C');

$this->setX(108);
$this->Cell(74,6,"Total TTC",1,0,'L');
$this->Cell(19,6,$prixTotalHorsTaxes+$totalTVA.chr(128),1,2,'C');

}

//Pied de page
function Footer(){
//Positionnement à 1,5 cm du bas
$this->SetY(-15);
//Police Arial italique 8
$this->SetFont('Arial','I',8);
//Numéro de page
$this->Cell(0,4,'Page '.$this->PageNo().'/{nb}',0,2,'C');
$this->MultiCell(0,4,"www.Crac-Design.com\n",0,'C',false);
}


//Impression de l'entête du tableau
function printTableHeader($header,$w){
//Couleurs, épaisseur du trait et police grasse
$this->SetFillColor(200,200,200);
$this->SetTextColor(0);
$this->SetDrawColor(0,0,0);
$this->SetFont('Arial','B',9);
for($i=0;$i<count($header);$i++)
$this->Cell($w[$i],7,$header[$i],1,0,'C',1);
$this->Ln();
//Restauration des couleurs et de la police pour les données du tableau
$this->SetFillColor(245,245,245);
$this->SetTextColor(0);
$this->SetFont('Arial');

}

//Génération du tableau
// table(données de l'entête tableau, largeur des colonnes, alignement des colonnes, données)
function table($header,$w,$al,$datas){
//Impression de l'entête tableau
$this->SetLineWidth(.3);
$this->printTableHeader($header,$w);

$posStartX=$this->getX();
$posBeforeX=$posStartX;

$posBeforeY=$this->getY();
$posAfterY=$posBeforeY;
$posStartY=$posBeforeY;

//On parcours le tableau des données
foreach($datas as $row){
$posBeforeX=$posStartX;
$posBeforeY=$posAfterY;

//On vérifie qu'il n'y a pas débordement de page.
$nb=0;
for($i=0;$i<count($header);$i++){
$nb=max($nb,$this->NbLines($w[$i],$row[$i]));
}
$h=6*$nb;

//Effectue un saut de page si il y a débordement
$resultat = $this->CheckPageBreak($h,$w,$header,$posStartX,$posStartY,$posAfterY);
if($resultat>0){
$posAfterY=$resultat;
$posBeforeY=$resultat;
$posStartY=$resultat;
}

//Impression de la ligne
for($i=0;$i<count($header);$i++){
$this->MultiCell($w[$i],6,strip_tags($row[$i]),'',$al[$i],false);
//On enregistre la plus grande hauteur de cellule
if($posAfterY<$this->getY()){
$posAfterY=$this->getY();
}
$posBeforeX+=$w[$i];
$this->setXY($posBeforeX,$posBeforeY);
}
//Tracé de la ligne du dessous
$this->Line($posStartX,$posAfterY,$posBeforeX,$posAfterY);
$this->setXY($posStartX,$posAfterY);
}

//Tracé des colonnes
$this->PrintCols($w,$posStartX,$posStartY,$posAfterY);
}

//Tracé des colonnes
function PrintCols($w,$posStartX,$posStartY,$posAfterY){
$this->Line($posStartX,$posStartY,$posStartX,$posAfterY);
$colX=$posStartX;
//On trace la ligne pour chaque colonne
foreach($w as $row){
$colX+=$row;
$this->Line($colX,$posStartY,$colX,$posAfterY);
}
}

//Vérification du débordement de page
function CheckPageBreak($h,$w,$header,$posStartX,$posStartY,$posAfterY){
//Si la hauteur h provoque un débordement, saut de page manuel
if($this->GetY()+$h>$this->PageBreakTrigger){
//On imprime les colonnes de la page actuelle
$this->PrintCols($w,$posStartX,$posStartY,$posAfterY);
//On ajoute une page
$this->AddPage();
//On réimprime l'entête du tableau
$this->printTableHeader($header,$w);
//On renvoi la position courante sur la nouvelle page
return $this->GetY();
}
//On a pas effectué de saut on revoie 0
return 0;
}

//Calcule le nombre de lignes qu'occupe un MultiCell de largeur w
function NbLines($w,$txt){
$cw=&$this->CurrentFont['cw'];
if($w==0)
$w=$this->w-$this->rMargin-$this->x;
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
$s=str_replace("\r",'',$txt);
$nb=strlen($s);
if($nb>0 and $s[$nb-1]=="\n")
$nb--;
$sep=-1;
$i=0;
$j=0;
$l=0;
$nl=1;
while($i<$nb)
{
$c=$s[$i];
if($c=="\n")
{
$i++;
$sep=-1;
$j=$i;
$l=0;
$nl++;
continue;
}
if($c==' ')
$sep=$i;
$l+=$cw[$c];
if($l>$wmax)
{
if($sep==-1)
{
if($i==$j)
$i++;
}
else
$i=$sep+1;
$sep=-1;
$j=$i;
$l=0;
$nl++;
}
else
$i++;
}
return $nl;
}

}

//Instanciation de la classe
$pdf = new pdf;
$pdf->AliasNbPages();
$pdf->Open();
$pdf->AddPage();
$pdf->hautDePage();
$pdf->tableArticles();
$pdf->Output();

?>

TODO:

  • Changer la couleur de fond d'une ligne sur deux

Dernière modification le Lundi, 03 Janvier 2011 15:09

commentaires  

 
0 #8 SmartiesKiller 16-03-2010 18:30
exelent,reste plus qu'a produire un ptit module pour ameliorer nos factures sous prestashop :D
je te laisse le faire car c'est hors de mes competences lool :D
Cordialement..
Citer
 
 
+1 #7 Damien BARRERE 15-10-2009 14:15
Bonjour,
Je vous invite vivement à lire la documentation des fonctions que vous utilisez (ici par exemple http://php.net/manual/fr/index.php).
Ici vous n'utilisez pas la bonne fonction pour lire une ligne dans votre base de donnée.

Prenez le temps de bien comprendre ce que retourne chaque fonction et sous quelle forme.

Vous pouvez utiliser la fonction print_r($variab le) afin de déboguer votre code, surtout pour les tableaux ;-) .
Citer
 
 
0 #6 Trabelsi Maher 15-10-2009 11:25
Encore une explication peu mieu
Par exmeple je veux afficher la désignation PAX20 le résultat de la reqète m'affiche correctement la désignation mais dans le PDF le désignation PAX20 est afficher chaque caractére dans une colonne:
L'affichage de la ligne est comme suit
Pour la colonne Réf: le PDF affiche P
Pour la colonne Désignation: le PDF affiche A
Pour la colonne Qté: le PDF affiche X
Pour la colonne Prix: le PDF affiche 2
Pour la colonne Montant:le PDF affiche 0

Si le résultat de la requête est de valeur numérique il m’affiche un message d’erreur ou si le résultat de la requête est un mot supérieur à 5 caractère il m’affiche rien.

Merci pour votre écoute
Citer
 
 
0 #5 Trabelsi Maher 15-10-2009 10:34
Merci beaucoup c’est bon ça marche mais il reste un problème d’affichage de la ligne par exemple la résultat de la requête est PAX 20(La désignation de l’article)
Le PDF m’affiche comme suit:
Réf Désignation Prix Qte Montant
P A X 2 0
Si le résultat de la requête est de valeur numérique il m’affiche un message d’erreur ou si le résultat de la requête est un mot supérieur à 5 caractère il m’affiche rien.
voiçi le code source:
Class facture
{
function tabarticlefactu r($con,$id,$typ efact)
{
$retour=array();
$requete1= odbc_exec( $con, "select * from FACTURE");
while(odbc_fetc h_row($requete1))
{
$retour[]=odbc_result( $requete1, 6 );
}
return $retour;
}
}
class pdf extends fpdf
{
function tableArticles()
{
$bas=new basedonnee();
$facture=new facture();
$datas=array();
$datas=$facture->tabarticlefactu re($bas >connexion,$_GET ['id'],$_GET['typefact']);
//reste du code
}
//reste des autre fonctions(foote r()...)
}
Citer
 
 
0 #4 Damien BARRERE 14-10-2009 17:24
C'est tout à fait normal,
Vous sortez de votre boucle de lecture des données dès la première itération grâce au "return".
Il faut passer par un tableau pour stocker tous les résultats de votre table et renvoyer le tableau:
function tabarticlefactu r($con,$id,$typ efact){
$requete1= odbc_exec( $con, "select * from FACTURE");
$retour=array();
while(odbc_fetc h_row($requete1))
{
$retour[] = odbc_result( $requete1, 6 );
}
return $retour;
}

Ceci devrait imprimer plus d'une ligne dans votre facture.
Citer
 
 
0 #3 Trabelsi Maher 14-10-2009 09:49
Merci pour votre aide. Je pense que code source est beaucoup plus bref voici une meilleure vision de code :
Class facture
{
function tabarticlefactu r($con,$id,$typ efact)
{
$requete1= odbc_exec( $con, "select * from FACTURE");
while(odbc_fetc h_row($requete1))
{
return odbc_result( $requete1, 6 );
}

}

}
include("fpdf.php");
include("facture.php");
include("basededonne.php");
class pdf extends fpdf
{

function tableArticles()
{
$bas=new basedonnee();
$facture=new facture();
$datas=array();
$datas[]=$facture->tabarticlefactu re($bas >connexion,$_GET ['id'],$_GET['typefact']); // appel a cette fonction pour afficher le résultat de la requette

//reste du code
}
}

$pdf = new pdf;
$pdf->AliasNbPages();
$pdf->Open();
$pdf->AddPage();
$pdf->tableArticles() ;
$pdf->Output();

la table datas affiche dans le PDF que la premiére ligne de resultat de la requette.
Merci.
Citer
 
 
0 #2 Damien BARRERE 13-10-2009 15:33
Bonjour,
Je pense que votre problème vient du fait que vous n'assignez aucune valeur à la variable $datas.

Changez la ligne modifiez la ligne suivante dans la fonction tableArticles() :

$datas=$facture->tabarticlefactu re($bas->connexion,$_GET ['id'],$_GET['typefact']);
Citer
 
 
0 #1 Trabelsi Maher 13-10-2009 12:35
Je veut adapté votre code source pour réaliser ma propre facture en utilsant une BD. Ma probléme est d'afficher le résultat de la requette dans la methode tablesarticles
voiçi une bref description du code
class facture
{

tabarticlefactu re($bas->connexion,$_GET ['id'],$_GET['typefact']);
{
// cette fonction contient ma requette

}
}


include("facture.php"); // classe contient les différents methodes pour manipuler une facture
include("basededonnee.php"); // classe de connexion


class pdf extends fpdf
{

function tableArticles()
{
$bas=new basedonnee();
$facture=new facture();

$facture->tabarticlefactu re($bas->connexion,$_GET ['id'],$_GET['typefact']); // appel a cette fonction pour afficher le résultat de la requette
}
}

$pdf = new pdf;
$pdf->AliasNbPages();
$pdf->Open();
$pdf->AddPage();
$pdf->tableArticles() ;
$pdf->Output();

Le PDF est afficher mais le résultat ne s'affiche pas.
Merçi pour votre écoute
Citer
 

Ajouter un Commentaire


touche

Vitrine, e-commerce, blog...

Nous proposons des solutions fiables et adaptées à vos besoins et à votre budget. Nous vous suivons et conseillons durant toutes les étapes de votre projet.
N'hésitez pas à nous contacter.
Création de sites Internet
html

Logiciel sur mesure

Nous vous proposons la création de logiciels sur mesure. Un logiciel adapté à votre activité n'est pas forcément plus cher qu'un progiciel existant qui ne répondra pas complètement à vos attentes.
Création de logiciels
touche

Solutions informatiques

Nous vous proposons la création de logiciels sur mesure. Un logiciel adapté à votre activité n'est pas forcément plus cher qu'un progiciel existant qui ne répondra pas complètement à vos attentes.
Solutions informatiques