TUTORIELS 
Document PDF "à la volée" avec un script CGI-Perl
Avec l'outil HTMLDOC, sous licence GPL, il est possible de renvoyer les données en sorties d'un script CGI en Perl non plus en HTML, mais sous forme d'un document PDF.  (2 juillet 2001)
 

Le format PDF est aujourd'hui largement répandu pour diffuser sur le web des documents prêts pour l'impression. Nous allons montrer ici comment produire des documents PDF "à la volée" à l'aide d'un script CGI en Perl. Le principe est simple: les données en sortie du script Perl, habituellement renvoyées sous forme de code HTML, seront "traduites" au format PDF par un outil spécifique, HTMLDOC, utilitaire sous licence GPL et fonctionnant sous Linux, Solaris ou Windows. Notre script Perl ne sera ni plus ni moins qu'une interface pilotant HTMLDOC. Développé par Easy Software Products, HTMLDOC s'installe très facilement sur toutes les plates-formes citées. Bien entendu, pour tester notre script Perl, il faut disposer en outre du lecteur Acrobat Reader.

La méthode, ses avantages et ses inconvénients
Il s'agit bien de convertir des données sous forme de code HTML en un document PDF: le script Perl pourra produire ses données HTML lui-même, où les récupérer via une variable CGI correspondant à un champ de formulaire. Ensuite HTMLDOC sera lancé via un appel système (sur le serveur), coûteux en temps de traitement. Par ailleurs, HTMLDOC n'est pas parfait: il ne supporte pas encore les feuilles de styles et trouve ses limites dans le traitement de pages web complexes. Néanmoins, la méthode permet de récupérer le code HTML déjà produit par un script Perl pour le convertir ensuite, or la majorité des scripts Perl fournissent en sortie du code HTML. Le travail de développement sera donc restreint d'autant. Par ailleurs, malgré les défauts de notre méthode, celle-ci n'est pas nouvelle et déjà utilisée ou ayant fait l'objet d'articles sur Internet.

Le code
L'exemple suivant fonctionne sous Unix et nécessite le module CGI.pm. Ce dernier module permet de récupérer facilement des données de formulaire en construisant un "objet CGI" dont les attributs $nom_objet->param("nom_champ") contiennent les valeurs des champs. On fera donc appel à notre exemple avec une requête transmettant le code HTML à convertir.

my $objet_cgi=new CGI;
my $code_html=$objet_cgi->param("source");

La deuxième étape consiste à traiter un ensemble de caractères "gênants". Ainsi, un "@" dans le code HTML devra être converti en "\@" pour être transmis, plus loin, à la fonction Unix echo. L'opération de substitution fait intervenir une expression régulière (voir l'article correspondant) du type:

~s/\@/\\\@/g

Ici, on regroupe les caractères à traiter et leurs (méta-)caractères de substitution dans un tableau associatif nommé tab_car (ainsi $tab_car{"\$"} contiendra "\\\$"), puis les "clés" de ce tableau (sachant que nom_tableau{clé} = valeur dans un tableau associatif) dans une chaîne appelée liste_car.

my %tab_car=( '","´", "\$","\\\$", "\@","\\\@", "\!","\\\!", "\n","", "\r","");
my $liste_car=join("",keys %tab_car);


Il ne reste plus qu'à substituer les éléments de la chaîne (les clés) par les valeurs correspondantes. Ce qui se réalise en employant une seule expression régulière:

$code_html =~s/([$liste_car])/$tab_car{$1}/g;

... ou presque, car le caractère "\" ne peut être substitué en "\\" mais en "\\\\" (le méta-caractère "\\" désignant le caractère "\"). Le traitement de ce caractère est donc isolé des autres traitements dans une instruction assez absconse:

$code_html =~s/\\/\\\\\\\\/g;

On effectuera logiquement cette transformation spécifique avant l'autre. On écrira donc:

$code_html =~s/\\/\\\\\\\\/g;
$code_html =~s/([$liste_car])/$tab_car{$1}/g;

La troisième étape (très importante!) consiste à indiquer au navigateur que le type MIME du document qui va lui être transmis correspond au format PDF:

print "Content-Type: application/pdf\r\n\r\n";

A noter que ce type d'indication doit être précisé au navigateur une fois par page et une seule.

Enfin, la dernière étape consiste à appeler le programme HTMLDOC. Il s'agit d'un programme externe donc on doit effectuer un appel système (ici sous Unix) par l'intermédiaire de la fonction Perl eval().

if ($code_html) {
   my $commande="`echo -e '".$code_html."' | htmldoc --webpage -t pdf - `";
   print eval($commande);
}


Et voilà! En dehors de l'opération de substitution des caractères particuliers, l'opération est très simple. L'ensemble nécessite peu de code et peut rendre de grands services.

Notre programme final sera donc:

#!/usr/bin/perl

my $objet_cgi=new CGI;
my $code_html=$objet_cgi->param("source");

my %tab_car=( '","´", "\$","\\\$", "\@","\\\@", "\!","\\\!", "\n","", "\r","");
my $liste_car=join("",keys %tab_car);

$code_html =~s/\\/\\\\\\\\/g;
$code_html =~s/([$liste_car])/$tab_car{$1}/g;

print "Content-Type: application/pdf\r\n\r\n";

if ($code_html) {
   my $commande="`echo -e '".$code_html."' | htmldoc --webpage -t pdf - `";
   print eval($commande);
}

 
[ Jérôme MorlonJDNet
 
Accueil | Haut de page