pluginGino-mpdf
 All Data Structures Namespaces Files Functions Variables Pages
Libreria per la generazione dei file pdf

Plugin per la creazione di file PDF con la libreria mPDF (http://www.mpdf1.com/mpdf/). mPDF è una classe PHP che genera file PDF da codice HTML con Unicode/UTF-8 e supporto CJK. gino è stato testato con la versione 6.0.0.

INSTALLAZIONE

  1. Scaricare la libreria
  2. Scompattare il file nella directory lib e rinominare la directory senza il numero di versione, ad esempio
    # mv mpdf57 mpdf
  3. Copiare il file plugin.mpdf.php nella directory lib/plugin.
  4. Copiare il file func.mpdf.php nella directory lib.
  5. Copiare il file mpdf.css nella directory css.

In addition

Oltre a queste operazioni si dovrebbe consentire la lettura/scrittura alle seguenti directory:

  • mpdf/tmp/
  • mpdf/ttfontdata/
  • mpdf/graph_cache/

I permessi read/write alla directory mpdf/tmp/ sono necessari quando si attiva la visualizzazione della barra di progresso.
I permessi read/write alla directory mpdf/ttfontdata/ sono necessari per evitare gli errori di questo tipo:

file_put_contents(/.../lib/mpdf/ttfontdata/dejavusanscondensed.GSUBGPOStables.dat): failed to open stream: Permission denied ...

Note

Quando si aggiorna la versione della libreria mPDF occorre verificare se sono stati aggiornati nella classe mPDF i metodi che eventualmente la classe custom_mpdf sovrascrive.
Nel caso di di modifiche sostanziali modificare i metodi della classe custom_mpdf.

STRUTTURA

Il file plugin.mpdf.php comprende tre classi:

  • gino_mpdf
  • plugin_mpdf
  • custom_mpdf

Classe gino_mpdf

La classe gino_mpdf funge da interfaccia alla classe plugin_mpdf e definisce le impostazioni base del file pdf (gino_mpdf::defineBasicOptions()), l'header e il footer di default, il nome standard del file.
In pratica questa classe raggruppa i metodi di definizione dei contenuti; metodi che possono essere sovrascritti da una classe costruita appositamente per la generazione di uno specifico file pdf.

Classe plugin_mpdf

La classe plugin_mpdf costruisce il file pdf. Utilizzando il metodo plugin_mpdf::setPhpParams() è possibile impostare alcuni parametri php.

Classe custom_mpdf

La classe custom_mpdf estende mPDF per la personalizzazione degli output html.

Interfacce per la generazione del pdf

I metodi che devono essere richiamati dalle applicazioni per generare i pdf sono:

  • gino_mpdf::pdfFromPage()
  • gino_mpdf::create() dove il metodo gino_mpdf::pdfFromPage() viene utilizzato per generare il pdf della visualizzazione di una pagina web, mentre gino_mpdf::create() per generare un file con un html personalizzato.

Processo

gino_mpdf::create() istanzia plugin_mpdf e richiama plugin_mpdf::makeFile(); a sua volta plugin_mpdf::makeFile() istanzia custom_mpdf che estende mPDF.

MODI DI UTILIZZO

La libreria fornisce i metodi per generare il pdf di una pagina web oppure per generare un pdf costruito appositamente (ad esempio un report).

File pdf di una pagina web

L'esempio ipotizza la generazione del pdf del post di un blog (file class_blog.php, metodo detail()). Per stampare a video il pdf si aggiunge all'indirizzo il parametro pdf=1 (ad esempio http://localhost/gino/blog/detail/prova/?pdf=1)

$pdf = \Gino\cleanVar($request->GET, 'pdf', 'int', '');
if($pdf)
{
require_once(PLUGIN_DIR.OS.'plugin.mpdf.php');
\Gino\Plugin\plugin_mpdf::setPhpParams();
$obj_pdf = new \Gino\Plugin\gino_mpdf();
return $obj_pdf->pdfFromPage($view->render($dict), array(
'css_file' => array('app/blog/pdf.css', 'css/mpdf.css'),
'filename' => 'blog.pdf'
));
}

oppure, utilizzando la risposta Gino.Http.ResponsePdf

$pdf = \Gino\cleanVar($request->GET, 'pdf', 'int', '');
if($pdf)
{
\Gino\Loader::import('class/http', '\Gino\Http\ResponsePdf');
return new \Gino\Http\ResponsePdf($content, array(
'css_file'=>array('css/mpdf.css'),
'filename'=>'blog.pdf'
));
}

File pdf personalizzato

Creare nella classe controller il metodo pubblico che gestisce la generazione del file pdf (ricordandosi di inserirlo nel file ini). Segue un metodo di esempio:

public function pdf() {
require_once(PLUGIN_DIR.OS.'plugin.mpdf.php');
\Gino\Plugin\plugin_mpdf::setPhpParams();
$options = array(
'progressBar'=>false,
'output'=>'inline',
'img_dir'=>'app/catalog/img',
'save_dir'=>null,
'css_file'=>array(),
'css_html'=>null
);
$html = false;
$obj_pdf = new \Gino\Plugin\gino_mpdf(array('html'=>$html));
$options['content'] = \Gino\htmlToPdf("<p>html contents</p>");
$pdf = $obj_pdf->create($options);
if($html)
{
$document = new \Gino\Document($pdf);
return $document();
}
else return $pdf;
}

Nel caso si abbia bisogno di creare più file pdf oppure anche soltanto di strutturarli in un modo più complesso può essere più efficiente creare nella classe controller un wrapper per i pdf (ad esempio createGinoPdf) che richiami una classe apposita (ad esempio GinoPdf) che estende la classe gino_mpdf.
La costruzione del singolo file sarà delegata a una apposita classe che estende, come da esempio, la classe GinoPdf. In questa classe (myGinoPdf) sarà così possibile personalizzare i metodi content, footer, header, sovrascrivendoli.

ClassController::createGinoPdf() {
...
plugin_mpdf::setPhpParams([...]);
$obj = new myGinoPdf([...]);
return $obj->generate([...]);
}
class myGinoPdf extends GinoPdf {
content(), header(), footer()
}
class GinoPdf extends gino_mpdf {
setFileName()
generate() {
$pdf = $this->create([...]);
if($html)
return $pdf;
if($link_return)
$this->redirect($link_return);
return null;
}
}

HEADER/FOOTER

L'header e il footer del pdf devono essere passati come opzioni al metodo plugin_mpdf::htmlStart(); per non stampare il footer occorre impostare il parametro footer a false.
Per visualizzare un esempio di header e footer vedere i metodi gino_mpdf::defaultHeader() e gino_mpdf::defaultFooter().

OUTPUT

La libreria gestisce i seguenti output:

  • stampare a video l'html (string)
  • inviare il file inline al browser (inline)
  • salvare localmente il file (file)
  • far scaricare il file (download)
  • creare il file e inviarlo come allegato email
gino_mpdf::create(array('output'=>[value]))

Debug

Per attivare la modalità debug occorre passare l'opzione debug a gino_mpdf::create() o a gino_mpdf::pdfFromPage() che lo richiama.

gino_mpdf::create(array('debug'=>true))

Il debug viene poi gestito nella classe plugin_mpdf().

VARIE

Memoria

La libreria mPDF utilizza una quantità notevole di memoria; nel caso in cui venga visualizzato un messaggio di errore di superamento del limite di memoria come ad esempio

Fatal error: Allowed memory size of 134.217.728 bytes exhausted (tried to allocate 261904 bytes) in C:\inetpub\wwwroot\lib\MPDF\mpdf.php on line 22048

occorre approntare alcuni accorgimenti elencanti nella seguente pagina di documentazione mpdf.

L'aumento di memoria allo script php può essere gestito a livello di:

  • file php.ini
    memory_limit = 128M
  • file php
    ini_set("memory_limit","128M")
  • virtualhost
    php_admin_value memory_limit "128M"

Limpostazione massima del limite di memoria per lo script php è

ini_set("memory_limit","-1")

Windows

La memoria può esaurirsi rapidamente durante l'esecuzione di PHP 5.3.x su Windows, e questo potrebbe essere dovuto da un bug nella versione di php per Windows. Uno script che esaurisce 256 MB di memoria su Windows può invece utilizzare solo 18MB quando viene eseguito su Linux. E sembra che non accada esclusivamente quando si utilizzano tabelle.
Quindi, se si utilizza solo Windows in un ambiente di prova e Linux per la produzione, si dovrebbe considerare di impostare il limite di memoria massimo su Windows.

Errori PHP

Un qualsiasi errore generato dallo script php (anche se soltanto un warning o un notice), blocca la generazione del pdf. In questo caso occorre inibire la stampa degli errori richiamando direttamente la funzione php:

error_reporting(0);

oppure

\Gino\Plugin\plugin_mpdf::setPhpParams(array('disable_error'=>true));

Progress bar

La progress bar non è raccomandata per un utilizzo generale ma può essere di aiuto in fase di sviluppo o nella generazione di documenti lenti.
Per impostare il valore a livello globale occorre editare il valore per progressBar nel file di configurazione config.php.

Per attivare la barra di progresso nella generazione inline di un PDF occorre assegnare i permessi 777 alla directory mpdf/tmp/, in quanto la libreria salva un file temporaneo in questa directory e poi lo mostra a video attraverso il file mpdf/includes/out.php.

Personalizzazione

La pagina della progress bar può essere personalizzata attraverso la definizione dell'opzione progbar_altHTML nel metodo plugin_mpdf::makeFile(). Ad esempio

$mpdf->progbar_altHTML = '<html><body>
<div style="margin-top: 5em; text-align: center; font-family: Verdana; font-size: 12px;">
<img style="vertical-align: middle" src="img/loading.gif" /> Creating PDF file. Please wait...</div>'

Inoltre è possibile sovrascrivere direttamente il metodo che genera la pagina della progress bar, ad esempio per personalizzarne la lingua o le stringhe.
In questo caso occorre modificare il metodo custom_mpdf::StartProgressBarOutput().

GESTIONE DEI CONTENUTI

GESTIONE DELLE STRINGHE

Le stringhe di testo sono gestite dal metodo text() che richiama le funzioni presenti nel file func.mpdf.php. Le tipologie trattate sono:

Nel caso in cui i dati in arrivo dal database non vengano gestiti attraverso l'interfaccia di gestione delle stringhe text(), la funzione php htmlentities() presente nelle funzioni del file func.mpdf.php (anche pdfHtmlToEntities()) potrebbe determinare la creazione di un file pdf costituito unicamente da una pagina bianca.

La classe gino_mpdf mette a disposizione il metodo mText() per interfacciarsi a plugin_mpdf::text().

BREAKPAGE

Occorre fare attenzione al posizionamento dei breakpage, in quanto un breakpage a fine html genera una pagina vuota.

La definizione dei contenuti di un pdf a partire da un array di singoli contenuti html avviene unendo questi singoli contenuti che saranno tra loro separati. In questo caso non posizionare i breakpage a fine html in quanto i singoli contenuti html vengono sempre mostrati a partire da una nuova pagina.

PERMESSI DEL FILE PDF

L'opzione protection (array) permette di crittografare e impostare i permessi sul file pdf. Di default il documento non è crittografato e garantisce tutte le autorizzazioni all'utente (valore null di protection). Al contrario un array vuoto nega ogni autorizzazioni all'utente.
L'array può includere alcuni, tutti o nessuno dei seguenti valori che indicano i permessi concessi (

See Also
http://mpdf1.com/manual/index.php?tid=129&searchstring=setprotection):
  • copy
  • print
  • modify
  • annot-forms
  • fill-forms
  • extract
  • assemble
  • print-highres

Le password dell'utente e del proprietario vengono passate attraverso le opzioni user_password e owner_password.

GESTIONE FILE CSS

I file css possono essere caricati come opzione del metodo definePage() in due modi, come stringa o come array. Sarà poi il metodo htlmStart() a prendersi carico della corretta inclusione dei file css nel codice html dal quale verrà generato il file pdf.

1) stringa: in questo caso viene incluso nel codice html soltanto il file css indicato, ad esempio

array([...,] 'css_file'=>'app/test/css/report.css'[, ...])

Eventuali altri file dovranno essere inclusi utilizzando la chiave @import nel file css

@import url(test.css);
.void {}
.title { color: red; }

In questo caso ho riscontrato che la prima classe css dopo la direttiva @import non viene presa in considerazione, per cui è necessario inserire una classe "finta", come 'void' nell'esempio appena sopra.

2) array: in questo caso vengono inclusi nel codice html tutti i file css indicati, nell'ordine degli elementi nell'array, ad esempio

array([...,] 'css_file'=>array('app/dvr/css/report.css', 'app/dvr/css/test.css')[, ...])

CSS/STILI

Posizionamento

Gli elementi DIV possono essere posizionati staticamente nella pagina, a condizione che abbiamo come parent direttamente il BODY, ovvero che non siano all'interno di una SECTION o di un altro DIV.

Nel caso di

position:absolute;

il blocco prende come riferimento la pagina senza tenere in considerazione i margini, mentre nel caso

position:relative;

il blocco prende come riferimento i margini della pagina.
Seguono due esempi: nel primo caso il blocco viene posizionato al vivo in basso nella pagina, mentre nel secondo caso il blocco viene posizionato a una distanza di 30mm dal basso e dentro i margini della pagina.

.myfixed1 {
position: absolute;
overflow: visible;
left: 0;
bottom: 0;
border: 1px solid #880000;
background-color: #FFEEDD;
background-gradient: linear #dec7cd #fff0f2 0 1 0 0.5;
padding: 1.5em;
margin: 0;
font-family:sans;
}
.myfixed2 {
position: fixed;
overflow: auto;
left: 120mm;
right: 0;
bottom: 0mm;
height: 30mm;
border: 1px solid #880000;
background-color: #FFEEDD;
background-gradient: linear #dec7cd #fff0f2 0 1 0 0.5;
padding: 0.5em;
margin: 0;
font-family:sans;
}

Rotazione del testo

Sull'intera riga di una tabella (tag tr) oppure su singole celle (tag td).

<tr text-rotate="45">
oppure
<tr style="text-rotate: 45">

Tabelle

Block-level tags (DIV, P etc) are ignored inside tables, including any CSS styles - inline CSS or stylesheet classes, id etc.
To set text characteristics within a table/cell, either define the CSS for the table/cell, or use in-line tags e.g. .

Ripetizione di header e/o footer di una tabella al cambio di pagina

Se una tabella è splittata su più pagine, la prima riga di una tabella sarà ripetuta in testa alla nuova pagina se:

<table repeat_header="1"> o
<thead> o <tfoot> sono definiti

####Inserimento di un bordo all'inizio e alla fine di una tabella

.table_style {
topntail: 0.02cm solid #666;
}

####Esempi di celle di tabella

<td colspan="2" valign="top" align="center">text_label:<br />text_value</td>
<td width="50%" valign="top" rowspan="2">text_label:<br />text_value</td>

Cambiare le dimensioni della pagina nel documento

L'esempio seguente stampa una pagina A4 (landscape).

Come css

.headerPagedStart { page: smallsquare; }
.headerPagedEnd { page: standard; }
@page smallsquare {
sheet-size: A4-L; // width height <length>{2} | Letter | Legal | Executive | A4 | A4-L | A3 | A3-L etc. Any of the standard sheet sizes can be used with the suffix '-L' for landscape
size: 15cm 20cm; // width height <length>{1,2} | auto | portrait | landscape NB 'em' and 'ex' % are not allowed
margin: 5%;
margin-header: 5mm;
margin-footer: 5mm;
}
@page standard {
sheet-size: A4; margin: 15mm; margin-header: 5mm; margin-footer: 5mm;
}

Nel codice html

<h2 class="headerPagedStart">Paged Media using CSS</h2>
<h4>Changing page (sheet) sizes within the document</h4> <p>This should print on an A4 (landscape) sheet</p> <p>Nulla felis erat, imperdiet eu, ..........</p>
<div class="headerPagedEnd"></div>