Il formato PDF è lo standard de facto per la distribuzione di documenti multipiattaforma. Deve la sua diffusione alle specifiche libere e a disposizione di tutti, al fatto che i file mantengono lo stesso aspetto sui vari schermi su cui vengono mostrati e su ogni stampante, e al fatto che i documenti risultano abbastanza compatti.
In questo articolo vedremo come creare dei documenti PDF con dati provenienti da form o da un database, in altre parole come realizzare PDF dinamici con PHP.
Le soluzioni in PHP per i PDF
Per creare questo tipo di file con PHP, la community degli sviluppatori ha sviluppato diverse soluzioni: alcune si affidano a programmi esterni, altre si interfacciano a librerie, altre ancora sono scritte direttamente in PHP. Iniziamo con una panoramica su 3 di queste soluzioni:
- PDFlib;
- R&OS: Pdf class;
- FPDF
per poi sceglierne una e approfondirne il funzionamento.
PDFlib
La libreria PDFlib è un'estensione dell'interprete PHP che si interfaccia ad API scritte in ANSI C. Il fatto di essere scritta in C e di essere un modulo dell'interprete, la rende la libreria più veloce in circolazione. Inoltre è l'unica ad avere la possibilità di modificare un documento creato precedentemente.
L'utilizzo di questa libreria è in gran parte facilitato dalla presenza di un'intera sezione del manuale PHP . Essere un'estensione dell'interprete però implica la necessità di ricompilare il php stesso. Questo unito alla licenza commerciale fa sì che questa libreria non sia molto diffusa sui server.
R&OS
Questa libreria è invece composta da due classi scritte in linguaggio php. Questo rende la libreria più lenta della PDFlib ma al tempo stesso più facile da personalizzare per il comune sviluppatore php e più facile da installare (infatti basta copiare le due classi e richiamarle dai propri script).
Sul sito della R&OS è presente un'ampia documentazione in formato PDF (tra l'altro realizzato proprio con questa libreria) che rende bene l'idea delle potenzialità di questa estensione.
FPDF
Anche la FPDF è una libreria scritta in PHP. Non è completa come la R&OS, ma il suo punto di forza è nella semplicità del suo codice e nella vasta comunità che ha messo a disposizione alcune soluzioni pronte molto utili. Anche questa libreria dispone di un'ampia documentazione in forma di manuale e di tutorial.
Tabella riassuntiva dei PDF - PHP tool
PDFlib | FPDF | R&OS | |
---|---|---|---|
Versione Pdf | 1.4 | 1.3 | 1.3 |
Apertura file esterni | Sì (+PDI) | No | No |
Salvataggio su disco | Sì | Sì | Sì |
Licenza | Commerciale | Open Source | Open Source |
Documentazione | Inglese | Italiano, Inglese | Inglese |
Pdf protetti | Sì | No | No |
Inserimento immagini | Sì | Sì | Sì |
Creazione PDF dinamici con FPDF
Partiamo subito con un approccio pratico alla creazione di documenti PDF dinamici con PHP. Utilizzeremo la libreria FPDF, per cui iniziamo visitando il sito della libreria per scaricare il file zip contenente il codice.
Scaricato e decompresso l'archivio ci troveremo una serie di cartelle e di file, alcuni dei quali servono come documentazione. Caricate sul vostro spazio web la cartella "font" e il file fpdf.php
. A questo punto l'installazione è completata, non ci resta che iniziare ad usare questa estensione.
L'utilizzo di questa estensione richiede una disceta conoscenza della programmazione ad oggetti. È possibile usare la classe in due modi:
- Maniera diretta (chiamare direttamente le funzioni della classe fpdf.php)
- Estensione della classe (chiamare le funzioni di una classe che estenda le funzioni della prima)
Il secondo procedimento è quello che offre un risultato migliore in termini di resa grafica poiché è possibile controllare meglio le varie aree del documento.
Per prima cosa è necessario definire FPDF_FONTPATH
, costante che indica il percorso della cartella dei font. Poi possiamo includere la classe stessa.
// dichiarare il percorso dei font
define('FPDF_FONTPATH','./font/');
//questo file e la cartella font si trovano nella stessa directory
require('fpdf.php');
A questo punto possiamo creare un'istanza della classe. Questo oggetto rappresenta il nostro documento, vediamo come dichiaralo, inizializzarlo e aggiungere una pagina:
// crea l'istanza del documento
$p = new fpdf();
// inizializza il documento
$p->Open();
// aggiunge una pagina
$p->AddPage();
Inserire il testo in un PDF con PHP
Per aggiungere il testo possiamo sfruttare con quattro funzioni diverse, ne analizziamo subito le differenze:
Cell() e MultiCell()
Con queste funzioni possiamo aggiungere il testo a celle, creano cioè una casella di testo di dimensioni impostate dal primo e dal secondo parametro passato (larghezza e altezza). Il testo possiamo inserirlo nel terzo parametro.
MultiCell() differisce da Cell() per il solo fatto che permette l’immissione di testo su più righe (divise tra loro dal carattere n
).
Ecco un esempio:
$p->MultiCell(0, 5, 'Testo con ' . "n" . 'MultiCell()', 0, 'center');
Gli ultimi due parametri sono opzionali e rappresentano rispettivamente la presenza del bordo e l'allineamento del testo.
Write()
Questa è la funzione più semplice per l’aggiunta di testo e richiede come parametri solo l'altezza del testo e il testo stesso.
$p->Write(5, 'Testo con Write()');
Text()
Questa è la funzione più precisa in quanto permette di specificare con precisione le coordinate di partenza x
e y
del testo. Ciò rende però la funzione più difficile da gestire e quindi di solito, come suggerito anche dal manuale, conviene utilizzare le funzioni più User-Friendly.
$p->Text(5, 10, 'Testo con Text()');
Il primo rendering del PDF creato con PHP
Proviamo ad inserire all'interno della nostra pagina alcune prove di stampa del testo:
// Impostare le caratteristiche del carattere
$p->SetTextColor(0);
$p->SetFont('Arial', '', 9);
// Le funzioni per scrivere il testo
$p->MultiCell(0, 5, 'Testo con ' . "n" . 'MultiCell()', 0, 'center');
$p->Cell(0, 5, 'Testo con Cell()');
$p->Write(5, 'Testo con Write()');
$p->Text(5, 10, 'Testo con Text()');
Per finire bisogna rendere la pagina in output:
// Senza parametri rende il file al browser
$p->output();
Ed ecco creato il nostro primo documento in PDF con PHP.
FPDF, impostare font e colori dei caratteri
Conoscere le funzionalità di formattazione di base di FPDF ci abilita a creare moltissime tipologie di documenti, vediamo quali sono e quali i possibili utilizzi della libreria per risolvere praticamente tutte le necessità grafiche di paginazione.
SetFontSize e SetFont
La formattazione del carattere è un aspetto cruciale nella creazione dei documenti, per questo FPDF ci mette a disposizione due funzioni:
SetFontSize($size)
, che serve ad impostare la dimensione del carattere;SetFont($famiglia, $stile, $dimensione)
, che permette di modificare anche famiglia (Arial, Time o un carattere particolare importato con AddFont) e stile del carattere (grassetto, italico, sottolineato).
Prima di utilizzare un carattere basta "dichiararlo" con questa funzione. Dopo di che tutto il testo inserito verrà reso con la stessa formattazione.
Ad esempio per impostare un carattere 12, Arial, grassetto, basta utilizzare il seguente codice:
$p->SetFont('Arial', 'B', 12);
Al posto dei parametri della funzione potete passare stringhe vuote per eliminare la formattazione precedente.
Ricollegandoci all'esempio precedente, se vogliamo lasciare lo stesso carattere ma renderlo normale, basterà richiamare la stessa funzione in questo modo:
$p->SetFont('Arial');
SetTextColor
Ovviamente la libreria ci permette di intervenire anche sul colore del testo con la funzione:
SetTextColor($rosso, $verde, $blu)
Ad esempio per impostare il colore del testo a grigio potete usare il seguente codice
$p->SetTextColor(120, 120, 120);
Nota: I parametri dei colori da passare sono valori decimali interi compresi tra 0 e 255.
Dimensioni della pagina
Creando un documento Pdf risulta utile anche specificare con precisione le dimensioni della pagina e l’area in cui debba essere inserito il contenuto.
La dimensione vera e propria della pagina (cioè del foglio su cui potrà essere stampato il documento) può essere specificata soltanto con la creazione dell'istanza della classe; attraverso il costruttore infatti si può specificare l'orientamento del foglio (orizzontale o verticale), l'unità di misura utilizzata (di default mm) e la dimensioni del foglio. Quest'ultimo parametro deve essere una stringa che rappresenti uno dei formati più diffusi (ad esempio 'A4' o 'Legal').
Per ogni pagina è invece possibile scegliere l'orientamento specificando ‘P’ per la pagina in verticale e ‘L’ per quella in orizzontale alla funzione AddPage()
.
Per specificare i margini è possibile usare le funzioni SetTopMargin(), SetLeftMargin(), SetRightMargin() o SetMargins() che modifica tutti e tre i margini con un’unica chiamata.
// Imposta il margine sinistro a 50, quello alto a 20 e quello basso a 10
$p->SetMargins(50, 20, 10);
Inserire immagini e grafici nei PDF con FPDF
Inserire forme, grafici e immagini è una delle attività fondamentali nella creazione di un documento PDF, vediamo quali sono le funzioni messe a disposizione da FPDF.
Image
L'inserimento delle immagini possiamo gestirlo semplicemente grazie alla Image()
.
Purtroppo (o per fortuna se guardiamo dal punto di vista della gestione grafica) dobbiamo specificare le coordinate dell'angolo in alto a sinistra dell'immagine. Ecco un esempio:
$p->Image('php.gif', 7, 40);
In questo caso abbiamo inserito l'immagine "php.gif" a partire dal punto (7, 40) con dimensioni originali.
Le immagini vanno prese dal filesystem e il percorso deve essere passato come primo parametro alla funzione.
Il quarto e il quinto parametro infine rappresentano le dimensioni (larghezza e altezza) dell'immagine da mostrare; se passate come parametro 0, la libreria prenderà la dimensione direttamente dal file scelto.
Nota: le coordinate partono dall'angolo in alto a sinistra della pagina (0, 0).
Forme geometriche, Line e Rect
La libreria FPDF dispone anche di due gruppi di funzioni per creare immagini geometriche: linee e rettangoli. Per creare una linea possiamo utilizzare la funzione Line() che prende 4 argomenti: le coordinate x e y del punto di partenza e quelle del punto di arrivo della linea:
// Linea obliqua da destra-alto a sinistra-basso
$p->Line(5, 60, 85, 21);
Di default una linea ha spessore di 0.2 mm
, ma potete specificare la dimensione che preferite con la funzione SetLineWidth() che accetta come parametro lo spessore della linea da disegnare.
La creazione dei rettangoli è altrettanto semplice, la funzione Rect() accetta infatti 4 parametri (coordinate dell'angolo in alto a sinistra e dimensioni del rettangolo) più uno facoltativo per indicare se il rettangolo debba essere riempito ('F'), solo bordato ('D') oppure entrambi ('DF').
// quadrato di lato 20 riempito
$p->Line(5, 5, 25, 25, 'F');
Ovviamente è possibile scegliere i colori del bordo o della parte interna dei rettangoli rispettivamente con le funzioni SetDrawColor() e SetFillColor(). Entrambe si comportano come la funzione SetTextColor()
accettando 3 parametri decimali.
I metadati PDF
Il formato PDF permette di specificare oltre ai dati da inserire in un documento anche informazioni che descrivano il documento stesso (l'equivalente dei metatag nell'HTML). Dato che alcuni software di catalogazione (e forse anche alcuni motori di ricerca) le utilizzano per archiviare i dati, può essere utile aggiungerli al documento PDF creato.
Metodo | Descrizione |
---|---|
Settitle | Imposta il titolo del documento (l'equivalente del tag <title> ) |
SetSubject | Imposta il soggetto (una descrizione) del documento (l'equivalente di <meta name="description"> ) |
SetKeywords | Imposta una serie di keywords per il documento (l'equivalente di <meta name"keywords"> ) |
SetCreator | definisce il programma che ha creato il documento |
SetAuthor | definisce l'autore del documento |
In genere quando si crea un file PDF (soprattutto se abbastanza corposo), la composizione avviene in maniera modulare: si crea cioè un file php che si occupa di includere la classe principale, inizializzarla e richiamare in ordine le varie parti del documento.
Una di queste parti modulari dovrebbe essere quella relativa ai metadati. Dei metodi per la gestione della strutture dei documenti Pdf parlerò nel prossimo articolo, per il momento chiudo la parentesi con un breve esempio:
<?php // index.php
define('FPDF_FONTPATH','./font/');
require('fpdf.php');
$p = new fpdf();
$p->open();
include('metadati.php'); //importo il file con le impostazioni dei metadati
$Pdf->Output();
?>
<?php // metadati.php
$p->Settitle('Documento di prova');
$p->SetSubject('Questo documento rappresenta solamente una prova e serve solo a mostrare l'uso dei metadati');
$p->SetKeywords('metadati prova test meta dati');
$p->SetCreator('FPDF 1.5');
$p->SetAuthor('Andrea Cristaudo');
?>
Estensione della classe (personalizzazione del documento)
Come già accennato all'inizio dell'articolo, possiamo utilizzare la libreria FPDF si può utilizzare in due maniere: chiamando direttamente i metodi della classe base oppure estendere direttamente la classe per creare dei metodi personalizzati.
Questo secondo metodo di funzionamento è solo leggermente più complicato del primo, ma presenta il vantaggio di poter personalizzare al massimo il documento. È possibile infatti personalizzare header e footer di ogni pagina inserendo ad esempio un logo, dei titoli oppure la numerazione delle pagine.
Header e Footer con PHP
Per modificare header e footer di un documento Pdf basta estendere la classe fpdf sovrascrivendo i metodi omologhi. Ad esempio, se volessimo inserire in fondo ad ogni pagina del documento un' informazione sul copyright, dovremmo utilizzare un codice simile:
<?php
define('FPDF_FONTPATH','./font/');
require('fpdf.php');
class Pdf extends fpdf {
var $copyright = 'Questo documento appartiene a NomeAzienda. Solo per uso interno';
function header(){
$this->SetTextColor(120, 120, 120); // testo in grigio
$this->SetFont('Arial', '', 8); //imposto un carattere più piccolo
$this->MultiCell(0, 5, $this->copyright, 0, 'C'); // Scrivo il testo al centro
$this->SetTextColor(0, 0, 0); // colore originale
$this->SetFont('Arial', '', 12); //imposto il carattere originale
}
}
$p = new Pdf();
$p->open();
$p->AddPage();
$p->AddPage();
$p->Output();
?>
In maniera molto simile si può sorascrivere la classe per aggiungere la numerazione alle pagine.
<?
class Pdf extends fpdf{
var $pgNum = 0;
function footer(){
$this->SetTextColor(120, 120, 120); // testo in grigio
$this->SetFont('Arial', '', 8); //imposto un carattere più piccolo
$this->MultiCell(0, 5, 'Pagina' . ++$this->pgNum, 0, 'C'); // Scrivo il testo al centro
$this->SetTextColor(0, 0, 0); // colore originale
$this->SetFont('Arial', '', 12); //imposto il carattere originale
}
}
?>
Effettuando poi un controllo sul numero della pagina è poi possibile allineare il testo o il numero di pagina più a destra o più a sinistra simulando la struttura di un libro.
<?php
define('FPDF_FONTPATH','./font/');
require('fpdf.php');
class Pdf extends fpdf {
var $copyright = 'Questo documento appartiene a NomeAzienda. Solo per uso interno';
function header(){
$this->SetTextColor(120, 120, 120); // testo in grigio
$this->SetFont('Arial', '', 8); //imposto un carattere più piccolo
$this->MultiCell(0, 5, $this->copyright, 0, 'C'); // Scrivo il testo al centro
$this->SetTextColor(0, 0, 0); // colore originale
$this->SetFont('Arial', '', 12); //imposto il carattere originale
}
}
$p = new Pdf();
$p->open();
$p->AddPage();
$p->AddPage();
$p->Output();
?>
In maniera molto simile si può sorascrivere la classe per aggiungere la numerazione alle pagine.
<?php
class Pdf extends fpdf {
var $pgNum = 0;
function footer() {
$this->SetTextColor(120, 120, 120); // testo in grigio
$this->SetFont('Arial', '', 8); //imposto un carattere più piccolo
$this->MultiCell(0, 5, 'Pagina' . ++$this->pgNum, 0, 'C'); // Scrivo il testo al centro
$this->SetTextColor(0, 0, 0); // colore originale
$this->SetFont('Arial', '', 12); //imposto il carattere originale
}
}
?>
Facendo poi un controllo sul numero della pagina è poi possibile allineare il testo o il numero di pagina più a destra o più a sinistra simulando la struttura di un libro.
Impostazione modulare dei file PDF
Per una composizione modulare del PDF, risulta molto utile suddividere i file necessari alla creazione di un documento complesso (articolato in più pagine e con una formattazione massiccia). In questo modo so possono creare documenti PDF di oltre 100 pagine avendo comunque un controllo generale sul codice e potendo intervenire con facilità apportando modifiche alle singole sezioni.
Questa procedura è dunque molto comoda per i file creati in maniera "stand-alone" come ad esempio documentazione o presentazioni, ma può essere anche uno spunto di riflessione per quanto riguarda i documenti dinamici che necessitano comunque di una maggior velocità di creazione.
La mia strutturazione del PDF è stata questa: Estensione della classe; pagina loader; dimensioni di pagina e inizializzazione; metadati; una pagina per argomento
Il funzionamento della pagina loader è molto semplice: questa pagina inlcude tutte quelle necessarie al documento. In questo modo, se dovremo inserire in futuro un nuovo "argomento" tra due già presenti, dovremo soltanto creare il file con il codice necessario e aggiungere un include()
nella pagina loader nel punto desiderato.
Il file di inizializzazione semplicemente crea un oggetto dalla classe estesa indicando la dimensione delle pagine e la disposizione (orizzontale o verticale) e imposta i margini.
"Classi" di caratteri
Un altro utilizzo molto comodo dell'estensione della classe è la gestione della formattazione delle varie parti del testo, come avviene con i CSS in HTML.
Capita infatti che il documento PDF contenga una divisione strutturale del testo in cui si presentano titoli, sottotitoli o ornamenti particolari (ad esempio un'immagine per identificare un elemento di una lista) che vanno ripetuti nel documento.
A questo punto risulta utile estendere la classe fpdf e aggiungere un metodo per la gestione di queste strutture:
<?
class Pdf extends fpdf{
function H1($text){
$this->SetTextColor(0, 0, 0);
$this->SetFont('Arial', 'B', 30);
$this->Cell(0, 10, $text, 0, 0, 'C');
$this->Ln(10);
}
function H2($text){
$this->SetTextColor(0, 0, 0);
$this->SetFont('Arial', '', 18);
$this->Cell(0, 10, $text, 0, 0, 'C');
$this->Ln(10);
}
}
?>
Seguendo questo esempio è possibile gestire molto comodamente i testi strutturati. Ad esempio sarebbe possibile creare facilmente una documentazione in Pdf per i nostri script rendendola allo stesso tempo gradevole visivamente, leggera e portabile.
Uno script proposto da Pascal Morin potrebbe tornarci utile per gestire una formattazione molto simile ad una pagina html dove abbiamo necessità di creare testi in cui singole parole all'interno di discorsi debbano essere messe in risalto con colore o con il grassetto.