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);
}
|