Articles SPIP au format PDF avec support des liens

Ceci est une ARCHIVE, peut-être périmée. Vérifiez bien les compatibilités !

Gérer correctement les liens dans les PDF générés grâce à FPDF. Tous les types de liens sont supportés (liens externes, lien internes, notes).

Cette contribution est basée sur celle de Fabrice et Jérôme Fenal (2 octobre 2005) : http://www.spip-contrib.net/Articles-SPIP-au-format-PDF

Elle a pour objet de gérer correctement les liens dans les PDF générés. Tous les types de liens sont pris en charge, à savoir :

-  Lien externe : par exemple un site Web ou une adresse courriel.
Exemple : [SPIP-http://www.spip.net/]

-  Liens internes de note (note dans le texte vers le bas de page, et note de bas de page vers le texte).

-  Lien interne vers un article de votre site. Ces liens sont transformés en lien externe avec la syntaxe suivante :

http://votre nom de domaine/article.php3?id_article=identifiant de l'article

J’ai essayé d’inclure dans un article de test (en local, avec EasyPHP) tous les raccourcis typographiques SPIP possibles. Voici, à titre de démonstration, le fichier pdf correspondant :

Démo

Attention : Pour générer les liens de note, je n’ai pas trouvé d’autre solution que d’effectuer deux itérations dans le parsing de l’article. Attendez-vous donc à ce que la génération d’un PDF prenne deux fois plus de temps qu’avec les contributions précédentes.



Installation

Vous trouverez en pièce-jointe (PDFAvecLiens.zip), les fichiers nécessaires à la génération des articles au format PDF :

-  Copiez article_pdf.php3 à la racine de votre site SPIP.

-  Copiez le fichier mes _fonctions.php3 à la racine de votre site SPIP. Attention, si le fichier mes_fonctions.php3 existe déjà, recopiez le code contenu dans notre fichier mes_fonctions.php3 entre les balises ?php et ? dans votre fichier mes_fonctions.php3.

-  Copiez le répertoire pdf dans le répertoire de SPIP contenant vos squelettes ou à la racine de SPIP si vos squelettes se trouvent... à la racine de SPIP.

-  Créez un dossier nommé : _article_PDF dans le répertoire IMG et de lui attribuer les permissions à 777 (comme vous l’aviez fait lors de l’installation de SPIP pour le répertoire IMG par exemple).

-  Faites un lien dans votre squelette article.html vers article_pdf.php3. Mon lien ressemble à ceci :

<a href="article_pdf.php3?id_article=#ID_ARTICLE">
<img src="#DOSSIER_SQUELETTE/images/pdf.gif"/>
Télécharger</a>

Evidemment, dans mon répertoire de squelettes, j’ai un sous-répertoire nommé images contenant un image pdf.gif.

-  Dans article_pdf.html, mettez des valeurs correctes pour les variables $path_pdf (chemin du répertoire où seront sauvés les fichiers pdf), $class_path (emplacement des classes PHP servant à générer les pdf) et $site_logo_path (chemin vers le logo de votre site, si vous en avez un).

-  N’oubliez pas d’activer l’extension PHP php_gd2 sur votre serveur, si ce n’est déjà fait.

-  Dans le répertoire Code SPIP Demo, vous trouverez aussi le code SPIP ayant servi à générer le PDF de démo. Vous pouvez le réutiliser en local pour vos tests (attention aux numéros des images dans le texte SPIP, qui ne seront probablement pas les mêmes chez vous, par exemple : img07|left).

Explications


Parsing des liens

Le point d’entrée pour construire le PDF se trouve dans article_pdf.html. Il s’agit de Build :

$pdf-Buid($file_out) ;

Build est défini dans la classe PDF du fichier lib_pdf_global.php. On fait deux itérations par des PDF_SPIP::BuildDocument() et ce n’est qu’à la fin qu’on enregistre le document en appelant FPDF::Output().

PDF_SPIP::BuildDocument() appelle PDF_SPIP::GenerateText() qui appelle plusieurs fois PDF::WriteHTML. C’est dans cette dernière méthode que l’on détecte la présence de liens (’HREF’ est positionné à true) et que l’on fait la distinction entre les différents types de liens évoqués au début de ce document.

Les notes de bas de page nécessitent deux itérations. Pourquoi ? Parce que lorsque vous rencontrez le raccourci typographique de note (format SPIP : 2 crochets ouvrants et 2 crochets fermants), vous devez créer deux liens dans la page html générée (et donc le PDF basé sur la page) : celui dans le texte et celui en bas de page. Or, lors du parsing, vous ne connaissez pas l’emplacement de ce dernier lien de bas de page, puisque vous n’avez pas fini de parcourir le texte. On utilise deux tableaux BottomLinkIDArray et TopLinkIDArray pour sauver les identifiants de liens. A la première itération, on ajoute un lien bidon. A la seconde itération, on met un vrai lien en allant chercher son identifiant dans les tableaux.


Modèle de PDF

C’est la classe PDF_SPIP, définie dans le fichier lib_pdf_spip.php qui détermine l’aspect de la page de garde ainsi que les en-têtes et pieds de page. Mon modèle est une version légèrement modifiée du modèle d’origine :

L’entête est simplement constituée du titre.

En haut, on reprend le logo du site auquel on accole son nom et son URL. Attention : dans ce modèle, on ignore les logos de la rubrique et de l’article.

Au centre, le surtitre, le titre et le chemin des rubriques.

Plus bas, les dates de mise en ligne et parution.

En bas, le descriptif suivi d’une notice de copyright.

Le pied de page est constitué d’un copyright avec le nom du site et du numéro de la page sur le nombre total de page.

Problèmes avec Internet Explorer

Dans article_pdf.php3 ont été définis deux modes : Release et Debug.

Le mode Debug force la regénération du fichier pdf, quelque soit la date du fichier préexistant. Il affiche également le pdf directement dans le navigateur. Ce navigateur doit être Firefox. En effet, l’affichage direct semble poser problème sous IE6 (même SP2) : au lieu de lancer l’affichage du contenu du pdf, il affiche un dump du fichier !
Le mode Release, lui fonctionne sous IE (SP2) et Firefox. Il produit une boîte de dialogue demandant à l’internaute s’il souhaite lancer un lecteur de PDF externe ou sauver le pdf sur son disque. Le pdf n’est recréé que si la date de mise à jour dépasse celle du fichier pdf préexistant (ou si aucun fichier pdf n’existe, bien sûr).


Ce qu’il reste à faire

(pour les perfectionnistes...)

-  Habillage correct des images avec le texte et les placer correctement sur la page (à gauche, à droite, ou centrée)

-  Gestion étendue des tableaux : permettre l’insertion de liens (ignorés pour le moment) et d’images (placées à l’extérieur du tableau pour le moment) à l’intérieur d’une cellule de tableau.

-  Quand on insère une ancre dans le texte, créer dans le pdf un lien qui pointe directement vers cette ancre, sans passer par un lien HTTP externe.

-  Prendre en compte les citations, pour le moment ignorées.

-  Afficher une puce différente par niveau de hiérarchie en cas de puces imbriquées.

-  Afficher correctement du code informatique. Actuellement, la première ligne est ignorée.

-  Refactoring du code (par exemple, ne garder qu’une classe ou deux classes parmi les trois classes PDF, FPDF et PDF_SPIP)

Archive génération PDF avec liens

Discussion

15 discussions

  • 1

    php_gd2 kézako ?

    je sais pas où je peux paramétrer ça sur lautre.net

    le clic sur créer un pdf donne ça chez moi

    Warning : Unknown() : open_basedir restriction in effect. File(/pdf/fpdf.php) is not within the allowed path(s) : (/var/alternc/html/c/couac/ :/usr/share/pear/ :/var/alternc/tmp/ :/tmp/) in /var/alternc/html/c/couac/inc-public.php3(60) : eval()’d code on line 119

    Warning : Unknown(/pdf/fpdf.php) : failed to open stream : Operation not permitted in /var/alternc/html/c/couac/inc-public.php3(60) : eval()’d code on line 119

    Fatal error : (null)() : Failed opening required ’/pdf/fpdf.php’ (include_path=’. :/usr/share/php :/usr/share/pear’) in /var/alternc/html/c/couac/inc-public.php3(60) : eval()’d code on line 119

    • en fait, ça y est, c’est bon pour php_gd2, j’ai trouvé, par contre le reste merdoume...

      j’ai pris le correctif (supprimer_numero en minuscules), et les adresses $path_pdf , $class_path et $site_logo_path sont normalement valides mais, d’une part ça met des plombes à créer un fichier pdf qui ensuite ne s’ouvre pas...

    Répondre à ce message

  • 2

    Bonjour,

    Faut-il absolument configurer Spip avec gd2 précisément pour utiliser cette contrib ?

    Sinon, les améliorations concernant la gestion des images et des liens dans les tableaux m’intéressent beaucoup (mais je ne suis pas compétant).

    • Faut-il absolument configurer Spip avec gd2 précisément pour utiliser cette contrib ?

      Les contributeurs précédents se sont appuyés sur cette librairie pour supporter les images gif. Donc si vos documents ne contiennent que des jpg ou des png (conseillés de préférence au gif), cette contrib devrait passer en désactivant gd2.

      Mais auparavant, il faut aller dans le fichier “fpdf.php” et mettre en commentaires la ligne
      « $readgif= gd_info() ; » (l.957).

      Ensuite, il faut court-circuiter les appels relatifs au .gif. Pas si simple, ça requiert de mettre les mains dans le code...

    • Meme erreur que precedement indiqué des que l’on a une image dans l’article, qu’elle soit en .jpg, .png ou en .gif.
      j’ai tenté de faire afficher la valeur de $type pour savoir ce que le fpdf.php trouvait ... cela me donne un « blanc ».

      J’utilise aussi le filtre réduire_image, de ce fait le chemin de l’image en est d’autant rallongé.
      Pourtant qd j’affiche le code généré par ma page le nom de mon image se termine bien par une extension comme il faut.

      Du coup je bloque.

      Cordialement

      eric

    Répondre à ce message

  • 1

    Bonjour,

    Pour simplifier l’intégration de cette contribution je propose les correctifs suivants :

    	$class_path = "#DOSSIER_SQUELETTE/pdf/" ;
    	$site_logo_path = "[IMG/(#LOGO_SITE_SPIP|fichier)]";

    et d’utiliser plutôt le lien suivant :

    <a href="page.php3?fond=article_pdf&id_article=#ID_ARTICLE">
    <img src="#DOSSIER_SQUELETTE/images/pdf.gif"/>
    Télécharger</a>

    Ainsi on peut virer le fichier article_pdf.php3 de la racine et ne laisser que article_pdf et le répertoire /pdf dans notre répertoire de squelettes.

    Enfin le fichier mes_fonctions.php3 n’est pas obligatoirement à la racine du site mais il peut également prendre place dans le répertoire des squelettes.

    Cela permet de ne présenter qu’une seule modif hors répertoire des squelettes, à savoir la création du répertoire /IMG/_article_PDF .

    En espérant que cela puisse servir,

    Bien cordialement

    Bug :

    il faut corriger

    [$titre="(#TITRE|SUPPRIMER_NUMERO|pdf_first_clean)";]

    en

    [$titre="(#TITRE|supprimer_numero|pdf_first_clean)";]
    • Merci beaucoup, Bionet pour ces très remarques utiles.

      Apparemment, vous avez repris tout ou partie de la contrib pour BioSPIP (la nouvelle version), et ça me fait très plaisir ! C’était fait pour ça.

      « Spipment » vôtre,

    Répondre à ce message

  • Bonjour,

    Pour simplifier l’intégration de cette contribution je propose les correctifs suivants :

    	$class_path = "#DOSSIER_SQUELETTE/pdf/" ;
    	$site_logo_path = "[IMG/(#LOGO_SITE_SPIP|fichier)]";

    et d’utiliser plutôt le lien suivant :

    <a href="page.php3?fond=article_pdf&id_article=#ID_ARTICLE">
    <img src="#DOSSIER_SQUELETTE/images/pdf.gif"/>
    Télécharger</a>

    Ainsi on peut virer le fichier article_pdf.php3 de la racine et ne laisser que article_pdf et le répertoire /pdf dans notre répertoire de squelettes.

    Enfin le fichier mes_fonctions.php3 n’est pas obligatoirement à la racine du site mais il peut également prendre place dans le répertoire des squelettes.

    Cela permet de ne présenter qu’une seule modif hors répertoire des squelettes, à savoir la création du répertoire /IMG/_article_PDF .

    En espérant que cela puisse servir,

    Bien cordialement

    Bug :

    il faut corriger [$titre=« (#TITRE|SUPPRIMER_NUMERO|pdf_first_clean) » ;]
    en
    [$titre=« (#TITRE|supprimer_numero|pdf_first_clean) » ;]

    Répondre à ce message

  • 3

    Bonjour,

    Merci pour cette contrib !
    ça marche très bien !

    enfin ça marchait bien avec l’encodage latin-1 (iso-8859-1) mais de puis que je suis passé en utf-8 ben les accents déconnent grave !

    bref, l’arabe n’est supporté !

    apparemment c’est dû à la bibliothèque fpdf qui ne supporte pas unicode (utf-8) il faudrait lu iasocié un script (une sorte de plugin) heureusement en lgpl (tcpdf).

    si j’arive à l’intégré je vous fais signe ! (sinon faites moi signe !)

    • salut

      qui peut me dire sur les chemins :$class_path et $path_pdf ?

      exemple:j’ai mis

      $path_pdf=« IMG/_article_pdf/ » ;

      $class_path=$GLOBALS[’dossier_squelettes’].« /../../pdf/ » ;

      car j’ai mis mon squelette « cypher » dans le répertoire « squelettes »

      voilà j’espère avoir vos réponses

      car lemessage d’erreur m’est retourné :

      Warning : Unknown() : Restriction in effect. Access to this file (/pdf/fpdf.php) is not allowed in /var/www/free.fr/f/4/bouchonneau.gilles/inc-public.php3(60) : eval()’d code on line 78

      Warning : Unknown(/pdf/fpdf.php) : failed to open stream : Operation not permitted in /var/www/free.fr/f/4/bouchonneau.gilles/inc-public.php3(60) : eval()’d code on line 78

      Fatal error : (null)() : Failed opening required ’/pdf/fpdf.php’ (include_path=’/var/www/free.fr/f/4/bouchonneau.gilles/include :.’) in /var/www/free.fr/f/4/bouchonneau.gilles/inc-public.php3(60) : eval()’d code on line 78

    • Merci pour cette contrib ! ça marche très bien !

      Merci, ça prend un peu de temps de faire une contrib, et c’est toujours agréable de voir que quelqu’un la lit et l’utilise :-)

      apparemment c’est dû à la bibliothèque fpdf qui ne supporte pas unicode (utf-8) il faudrait lu iasocié un script (une sorte de plugin) heureusement en lgpl (tcpdf).

      En fait, j’avoue m’être limité au français (et je n’irai pas plus loin, car cette langue me suffit) ; c’est vrai que pour un travail « propre » un encodage occidental ne suffit pas (SPIP est internationalisé depuis un certain temps)

      si j’arive à l’intégré je vous fais signe ! (sinon faites moi signe !)

      Vous pouvez toujours faire signe aussi à l’auteur de FPDF ou poster un message sur son forum (c’est peut-être déjà fait ?). Les langues asiatiques sont supportées, tout espoir n’est pas perdu.

    • qui peut me dire sur les chemins :$class_path et $path_pdf ?

      exemple :j’ai mis

      $path_pdf=« IMG/_article_pdf/ » ;

      $class_path=$GLOBALS[’dossier_squelettes’].« /../../pdf/ » ;

      car j’ai mis mon squelette « cypher » dans le répertoire « squelettes »

      Vous avez peut-être créé un répertoire « squelettes » à la racine de SPIP, puis un sous-répertoire « cypher ». Dans ce cas , vous devez mettre :

      $path_pdf=« IMG/_article_pdf/ » ;

      $class_path=« squelettes/cypher/pdf/ » ;

      Ces deux chemins ont pour référence la racine de SPIP.

      Voilà, j’espère vous avoir aidé...

    Répondre à ce message

Ajouter un commentaire

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparaît.

Merci d’avance pour les personnes qui vous aideront !

Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.

Qui êtes-vous ?
[Se connecter]

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document

Suivre les commentaires : RSS 2.0 | Atom