source: spip-zone/_plugins_/spipdf/branches/v0.2/spipdf_fonctions.php @ 88513

Last change on this file since 88513 was 88513, checked in by olivier.tetard@…, 6 years ago

spipdf_nettoyer_html() : utilisation d’expressions rationnelles un peu plus restrictives pour la recherche de documents.

Cela permet d’éviter de lever une erreur PREG_BACKTRACK_LIMIT_ERROR sur de grands articles.

File size: 13.8 KB
Line 
1<?php
2
3/**
4 * Génération d'article SPIP au format PDF
5 *
6 * @package      spiPDF
7 * @author       Yves Tannier [grafactory.net]
8 * @copyright    2010 Yves Tannier
9 * @link         http://www.spip-contrib.net/spiPDF-generer-des-contenus-sur-mesure-en-PDF
10 * @link         http://zone.spip.org/trac/spip-zone/browser/_plugins_/spipdf
11 * @link         http://www.grafactory.net/
12 * @license      GPL Gnu Public Licence
13 * @version      0.2
14 */
15 
16if (!defined('_ECRIRE_INC_VERSION')) return; 
17
18// Options pour les marges des PDF, valables seulement pour la librairie mPDF
19// définissez vos options par défaut directement dans votre mes_options.php
20if (!defined('_SPIPDF_FORMAT')){
21        define('_SPIPDF_FORMAT', 'A4');
22}
23if (!defined('_SPIPDF_MARGIN_TOP')){
24        define('_SPIPDF_MARGIN_TOP', 20);
25}
26if (!defined('_SPIPDF_MARGIN_RIGHT')){
27        define('_SPIPDF_MARGIN_RIGHT', 20);
28}
29if (!defined('_SPIPDF_MARGIN_BOTTOM')){
30        define('_SPIPDF_MARGIN_BOTTOM', 15);
31}
32if (!defined('_SPIPDF_MARGIN_LEFT')){
33        define('_SPIPDF_MARGIN_LEFT', 15);
34}
35if (!defined('_SPIPDF_MARGIN_HEADER')){
36        define('_SPIPDF_MARGIN_HEADER', 2);
37}
38if (!defined('_SPIPDF_MARGIN_FOOTER')){
39        define('_SPIPDF_MARGIN_FOOTER', 2);
40}
41
42// Charset (qui peut être défini dans un fichier d'options
43if (!defined('SPIPDF_CHARSET')){
44        define('SPIPDF_CHARSET', 'UTF-8');
45        //define('SPIPDF_CHARSET', 'ISO-8859-15');
46}
47
48// utilisé pour le constructeur de HTML2PDF
49if (SPIPDF_CHARSET=='UTF-8'){
50        define('SPIPDF_UNICODE', true);
51} else {
52        define('SPIPDF_UNICODE', false);
53}
54
55// les librairies necessaires doivent-être dans "lib". A la racine ou dans le répertoire du plugin
56if (!defined('_DIR_LIB')){
57        define('_DIR_LIB', _DIR_RACINE . 'lib/');
58}
59
60// pour les function unicode2charset
61include_spip('inc/charsets');
62
63// repris dans le plugin article_pdf => a modifier
64// http://zone.spip.org/trac/spip-zone/browser/_plugins_/article_pdf
65function spipdf_first_clean($texte){
66
67        // supprimer les remarques HTML (du Couteau Suisse ?)
68        $texte = preg_replace(',<!-- .* -->,msU', '', $texte);
69
70        $trans = array();
71        $trans["<br />\n"] = '<BR>'; // Pour éviter que le \n ne se tranforme en espace dans les <DIV class=spip_code> (TT, tag SPIP : code)
72
73        // gestion d'un encodage latin1
74        if (SPIPDF_CHARSET=='ISO-8859-15' || SPIPDF_CHARSET=='iso-8859-15'){
75                $trans['&#176;'] = '°';
76                $trans["&#339;"] = 'oe';
77                $trans["&#8211;"] = '-';
78                $trans["&#8216;"] = '\'';
79                $trans["&#8217;"] = '\'';
80                $trans["&#8220;"] = '"';
81                $trans["&#8221;"] = '"';
82                $trans["&#8230;"] = '...';
83                $trans["&#8364;"] = 'Euros';
84                $trans["&ucirc;"] = "û";
85                $trans['->'] = '-»';
86                $trans['<-'] = '«-';
87                $trans['&mdash;'] = '-';
88                $trans['&deg;'] = '°';
89                $trans['œ'] = 'oe';
90                $trans['Œ'] = 'OE';
91                $trans['…'] = '...';
92                $trans['&euro;'] = 'Euros';
93                $trans['€'] = 'Euros';
94                $trans['&copy;'] = '©';
95        }
96        // pas d'insécable
97        $trans['&nbsp;'] = ' ';
98
99        // certains titles font paniquer l'analyse
100        // TODO : a peaufiner car ils sont necessaires pour les signets
101        // <bookmark title="Compatibilité" level="0" ></bookmark>
102        // http://wiki.spipu.net/doku.php?id=html2pdf:fr:v4:bookmark
103        //$texte = preg_replace(',title=".*",msU', 'title=""', $texte);
104
105        $texte = strtr($texte, $trans);
106        if (SPIPDF_CHARSET=='UTF-8'){
107                $texte = charset2unicode($texte);
108        } else {
109                $texte = unicode2charset(charset2unicode($texte), SPIPDF_CHARSET); // Repasser tout dans le charset demandé
110        }
111
112        // Décoder les codes HTML dans le charset final
113        $texte = html_entity_decode($texte, ENT_NOQUOTES, SPIPDF_CHARSET);
114
115        return $texte;
116}
117
118
119//function spipdf_remplaceSpan($matches) { return str_replace('img', 'img style="padding:5px;" style="float:'.$matches[1].'"', $matches[2]); }
120function spipdf_remplaceSpan_wfloat($matches){
121        return str_replace('img', 'img style="padding:5px;" class="pdf_img_float_' . $matches[1] . '"', $matches[2]);
122}
123
124function spipdf_remplaceSpan($matches){
125        return str_replace('img', 'img style="padding:5px;" align="' . $matches[1] . '"', $matches[2]);
126}
127
128function spipdf_remplaceSpanCenter($matches){
129        return $matches[1];
130}
131
132//function spipdf_remplaceDt($matches) { return str_replace('img', 'img style="padding:5px;" style="float:'.$matches[1].'"', $matches[2]); }
133function spipdf_remplaceDt_wfloat($matches){
134        return str_replace('img', 'img style="padding:5px;" class="pdf_img_float_' . $matches[1] . '"', $matches[2]);
135}
136
137function spipdf_remplaceDt($matches){
138        return str_replace('img', 'img style="padding:5px;" align="' . $matches[1] . '"', $matches[2]);
139}
140
141function spipdf_remplaceIdParName($matches){
142        return str_replace('id=\'', 'name=\'', $matches[0]);
143}
144
145function spipdf_remplaceFloatPuce($matches){
146        return str_replace('style=\'', 'style=\'float:left;', $matches[0]);
147}
148
149function spipdf_remplaceDtCenter($matches){
150        return $matches[1];
151}
152
153function spipdf_remplaceCaption($matches){
154        $table = '<table style="border:none;"' . $matches[1] . '<tr><td style="text-align: center;border:none;">' . $matches[2] . '</td></tr>';
155        $table .= '<tr><td style="border:none;">';
156        $table .= '<table' . $matches[1] . $matches[3] . '</table>';
157        $table .= '</td></tr></table>';
158        return $table;
159}
160
161function spipdf_nettoyer_html($html, $params_pdf = array()){
162
163        // supprimer les spans autour des images et récupérer le placement
164        $patterns_float = '/<span class=\'spip_document_[0-9]+ spip_documents.*float:(.*);.*>(.*)<\/span>/iUms';
165        $html = preg_replace_callback($patterns_float, !empty($params_pdf['float']) ? 'spipdf_remplaceSpan' : 'spipdf_remplaceSpan_wfloat', $html);
166
167        // supprimer les spans autour des images
168        $patterns_float = '/<span class=\'spip_document_[0-9]+ spip_documents.*>(.*)<\/span>/iUms';
169        $html = preg_replace_callback($patterns_float, 'spipdf_remplaceSpanCenter', $html);
170
171        // supprimer les dl autour des images et récupérer le placement
172        $patterns_float = '/<dl class=\'spip_document_[0-9]+ spip_documents.*float:(.*);.*<dt>(.*)<\/dt>.*<\/dl>/iUms';
173        $html = preg_replace_callback($patterns_float, !empty($params_pdf['float']) ? 'spipdf_remplaceDt' : 'spipdf_remplaceDt_wfloat', $html);
174        // replacer id par name pour les notes
175        $patterns_note = '/<a[^>]*href[^>]*class=\'spip_note\'[^>]*>/iUms';
176        $html = preg_replace_callback($patterns_note, 'spipdf_remplaceIdParName', $html);
177
178        // float sur les puces graphiques
179        $patterns_puce = '/<img[^>]*class=[\'"]puce[\'"] alt=[\'"]-[\'"][^>]*>/iUms';
180        $html = preg_replace($patterns_puce, '-', $html);
181
182        // supprimer les dl autour des images centrer
183        $patterns_float = '/<dl class=\'spip_document_[0-9]+ spip_documents.*<dt>(.*)<\/dt>.*<\/dl>/iUms';
184        $html = preg_replace_callback($patterns_float, 'spipdf_remplaceDtCenter', $html);
185
186        // remplacer les captions
187        if (!empty($params_pdf['caption'])){
188                $patterns_caption = '/<table(.*)<caption>(.*)<\/caption>(.*)<\/table>/iUms';
189                $html = preg_replace_callback($patterns_caption, 'spipdf_remplaceCaption', $html);
190        }
191
192        // tableaux centré
193        $html = preg_replace('/<table/iUms', '<table align="center"', $html);
194 
195  // balise cadre
196  $patterns_cadre = '/<textarea[^>]*class=[\'"]spip_cadre[\'"] [^>]*>(.*)<\/textarea>/iUms';
197        $html = preg_replace($patterns_cadre, '<div class="spip_cadre">$2</div>', $html);
198
199        // gestion des caractères spéciaux et de charset
200        $html = spipdf_first_clean($html);
201
202        return $html;
203
204}
205
206// traiter la balise page
207function traite_balise_page($html){
208
209        // on teste la balise page
210        if (preg_match('/<page(.*)>/iUms', $html, $matches)){
211                // on crée un tableau avec (beurk) Global pour accèder aux valeurs de pages
212                if (!empty($matches[1])){
213                        $balise_page = $matches[1];
214                        $pattern = '/(.*)="(.*)"/iUms';
215            getBalise($matches);
216                        $balise_page = preg_replace_callback($pattern, 'getBalise', $balise_page);
217
218                        // supprimer <page> et </page>
219                        $html = preg_replace('/<\/?page(.*)>/iUms', '', $html);
220
221                        return $html;
222                }
223
224        } else {
225                return $html;
226        }
227
228}
229
230//On sort cette fonction de la fonction traite_balise_page
231function getBalise($matches){
232        $matches[2] = str_replace('mm', '', $matches[2]);
233        $GLOBALS['valeurs_page'][trim($matches[1])] = trim($matches[2]);
234}
235
236
237// traitement principal. avec ce pipeline, le PDF est mis en cache et recalculé "normalement"
238function spipdf_html2pdf($html){
239
240        // les librairies possibles
241        $possible_librairies = array(
242                'mpdf' => array( // gére le float d'image mais pas les captions de tableau
243                        'float' => true,
244                        'caption' => true,
245                        'traite_balise_page' => true
246                ),
247                'html2pdf' => array( // ne gére pas le float d'image et les captions
248                        'float' => false,
249                        'caption' => true
250                ),
251                'dompdf' => array( // domPDF beta 0.6 EXPERIMENTAL
252                        'float' => false,
253                        'caption' => true,
254                        'traite_balise_page' => true
255                ),
256        );
257
258        // choix de la classe de génération via la balise <page lib>
259        if (preg_match('/\<page*.lib_pdf=["|\'](.*)["|\']/iUms', $html, $match_librairie)
260                && !empty($match_librairie[1])
261                && array_key_exists(strtolower($match_librairie[1]), $possible_librairies)
262        ){
263                $librairie_pdf = strtolower($match_librairie[1]);
264        } else {
265                $librairie_pdf = 'mpdf';
266        }
267
268        // tester si la librairie est dans /lib à la racine du spip ou dans le répertoire du plugin
269        if (is_dir(_DIR_LIB . $librairie_pdf)){
270                $dir_librairie_pdf = _DIR_LIB . $librairie_pdf . '/';
271        } elseif (is_dir(dirname(__FILE__) . '/lib/' . $librairie_pdf)) {
272                $dir_librairie_pdf = dirname(__FILE__) . '/lib/' . $librairie_pdf . '/';
273        } else {
274                die('Impossible de trouver la librairie de génération de PDF ' . $librairie_pdf . '. vérifiez que vous l\'avez bien téléchargée et installée dans /lib');
275        }
276
277        // nettoyer le HTML et gérer les placements d'image en fonction de la librairie utilisée
278        $html = spipdf_nettoyer_html($html, $possible_librairies[$librairie_pdf]);
279
280        // Debug = voir le html sans génération de PDF
281        if (isset($_GET['debug_spipdf'])){
282                echo $html;
283                exit;
284        }
285
286        // du A4 par defaut
287        $format_page = _SPIPDF_FORMAT;
288
289        // traiter la balise page pour les librairies qui ne la comprennent pas
290        if (!empty($possible_librairies[$librairie_pdf]['traite_balise_page'])){
291
292                $html = traite_balise_page($html);
293
294                // dans balise_page, on ne récupère que quelques possibilité dont le format
295                if (!empty($GLOBALS['valeurs_page'])){
296                        if (!empty($GLOBALS['valeurs_page']['format']))
297                                $format_page = $GLOBALS['valeurs_page']['format'];
298                        if (!empty($GLOBALS['valeurs_page']['backtop']))
299                                $backtop = $GLOBALS['valeurs_page']['backtop'];
300                        else
301                                $backtop = _SPIPDF_MARGIN_TOP;
302                        if (!empty($GLOBALS['valeurs_page']['backbottom']))
303                                $backbottom = $GLOBALS['valeurs_page']['backbottom'];
304                        else
305                                $backbottom = _SPIPDF_MARGIN_BOTTOM;
306                        if (!empty($GLOBALS['valeurs_page']['backleft']))
307                                $backleft = $GLOBALS['valeurs_page']['backleft'];
308                        else
309                                $backleft = _SPIPDF_MARGIN_LEFT;
310                        if (!empty($GLOBALS['valeurs_page']['backright']))
311                                $backright = $GLOBALS['valeurs_page']['backright'];
312                        else
313                                $backright = _SPIPDF_MARGIN_RIGHT;
314                        if (!empty($GLOBALS['valeurs_page']['margin_header']))
315                                $margin_header = $GLOBALS['valeurs_page']['margin_header'];
316                        else
317                                $margin_header = _SPIPDF_MARGIN_HEADER;
318                        if (!empty($GLOBALS['valeurs_page']['margin_footer']))
319                                $margin_footer = $GLOBALS['valeurs_page']['margin_footer'];
320                        else
321                                $margin_footer = _SPIPDF_MARGIN_FOOTER;
322                }
323        }
324
325        if ($librairie_pdf=='mpdf'){ // la librairie mPDF
326
327                // si il y a des options dans la balise page
328                // http://mpdf1.com/manual/index.php?tid=307
329
330                // le chemin relatif vers mPDF
331                define('_MPDF_PATH', $dir_librairie_pdf);
332                include_once(_MPDF_PATH . 'mpdf.php');
333
334                // la classe mPDF
335                $mpdf = new mPDF(SPIPDF_CHARSET, $format_page, 0, "", $backleft, $backright, $backtop, $backbottom, $margin_header, $margin_footer);
336                $mpdf->WriteHTML($html);
337
338                $html = $mpdf->Output('', 'S'); // envoyer le code binaire du PDF dans le flux
339                $echap_special_pdf_chars = true;
340
341        } elseif ($librairie_pdf=='dompdf') { // la librairie dompdf beta 0.6 // EXPERIMENTAL
342
343                // le chemin relatif vers mPDF
344                require_once(_DIR_LIB . 'dompdf/dompdf_config.inc.php');
345
346                $dompdf = new DOMPDF();
347                $dompdf->load_html($html, SPIPDF_CHARSET);
348                $dompdf->set_paper($format_page);
349                $dompdf->render();
350
351                $html = $dompdf->output(); // envoyer le code binaire du PDF dans le flux
352                $echap_special_pdf_chars = true;
353
354        } else { // la librairie HTML2PDF par défaut
355
356                // appel de la classe HTML2pdf
357                require_once($dir_librairie_pdf . 'html2pdf.class.php');
358                try {
359                        // les paramétres d'orientation et de format son écrasé par ceux défini dans la balise <page> du squelette
360                        $html2pdf = new HTML2PDF('P', $format_page, $flux['args']['contexte']['lang'], SPIPDF_UNICODE, SPIPDF_CHARSET);
361
362                        // mode debug de HTML2PDF
363                        if (defined('SPIPDF_DEBUG_HTML2PDF')){
364                                $html2pdf->setModeDebug();
365                        }
366                        // police différente selon unicode ou latin
367                        if (SPIPDF_UNICODE){
368                                $police_caractere = 'FreeSans';
369                        } else {
370                                $police_caractere = 'Arial';
371                        }
372                        $html2pdf->setDefaultFont($police_caractere);
373                        $html2pdf->writeHTML($html);
374
375                        $html = $html2pdf->Output('', true); // envoyer le code binaire du PDF dans le flux
376                        $echap_special_pdf_chars = true;
377                } catch (HTML2PDF_exception $e) {
378                        echo $e;
379                }
380
381        }
382
383        // On échappe les suites de caractères <? pour éviter des erreurs d'évaluation PHP (seront remis en place avec affichage_final)
384        // l'erreur d'évaluation est liée à la directive short_open_tag=On dans la configuration de PHP
385        if (!empty($echap_special_pdf_chars)
386                AND strpos($html, "<" . "?")!==false
387        ){
388                $html = str_replace("<" . "?", "<\2\2?", $html);
389        }
390
391        return $html;
392
393}
394
395/**
396 * On rétablit les <? du code PDF si necessaire
397 * on n'agit que sur les pages non html
398 *
399 * @param string $texte
400 * @return string
401 */
402function spipdf_affichage_final($texte){
403        if ($GLOBALS['html']==false
404                AND strpos($texte, "<\2\2?")!==false
405        ){
406                $texte = str_replace("<\2\2?", "<" . "?", $texte);
407        }
408        return $texte;
409}
410
411/**
412 * Ne pas permettre d'aller chercher un fond en sous-repertoire dans spipdf.html
413 * @param $fond
414 * @return mixed
415 */
416function spipdf_securise_fond($fond){
417        $fond = str_replace("/","_",$fond);
418        $fond = str_replace("\\","_",$fond);
419
420        return $fond;
421}
422?>
Note: See TracBrowser for help on using the repository browser.