Générer un document Word dynamiquement, en PHP

Le sujet est explicite, simple, connu et sérieux. Vous développez un outil de gestion pour un de vos clients, et ce dernier souhaite que votre application puisse générer des documents; en développeur moderne que vous êtes, vous êtes naturellement parti du principe que les modifications doivent s’opérer directement dans l’application, et que vous pouvez donc exporter tranquillement en PDF à l’aide d’une des nombreuses librairies disponibles pour ce faire (FPDF, HTML2PDF, HTML2PS, etc.).

Or, il s’avère que votre client veut pouvoir modifier ces documents en-dehors de l’application (le bougre); dans certains cas, vous pourrez le ramener facilement à la raison (pour la facturation : « Comment, mais vous ne vous rendez pas compte !! Une facture est une pièce comptable, et vous ne pourrez plus garantir l’intégrité de votre comptabilité s’il est possible de modifier une facture en dehors de l’application… »).

Dans d’autres cas, en revanche, votre partie est perdue d’avance, et le client veut pouvoir rajouter des mots doux à l’intention des destinataires, sans pour autant que cela figure dans l’application. Du coup, vous bataillez pour une sortie txt, rtf…rien n’y fait; votre client veut du MS Word, et puis c’est tout.

Bienvenue dans le monde désenchanté de la génération dynamique de fichiers word en PHP (ben oui, en .NET, ce serait évidemment trop facile).

On n’est pas dans la mer-deuh

Avant de pleurer (cela viendra), il convient de déterminer avec un maximum de précision à quel point vous y êtes. Votre client peut vouloir plusieurs choses différentes :

  • à partir d’un modèle donné, intégrer des données de la base de données — ou d’ailleurs — un peu sur le mode de la fusion en publipostage;
  • sans modèle donné, fabriquer des documents Word « à la volée » qui soient réutilisables, avec des données de la base de données ou non.

Toujours avec la même détermination, vous devez connaître les contraintes de votre client, ce qui, à ce stade, signifie une seule chose pour vous : à quel point le document Word doit-il être compatible avec des versions plus ou moins anciennes ?

Une fausse bonne idée

PHP met à disposition, depuis longtemps déjà, une librairie de fonctions permettant de fabriquer des documents Word ou Excel : les objets COM .

Cela peut paraître tentant, et selon le désir que vous avez de vous prendre la tête à faire quelque chose de propre ou non, cela peut même se laisser tenter. Toutefois, avant d’y aller, permettez-moi de vous indiquer les contraintes majeures de ce système :

  • votre serveur doit tourner sous Windows;
  • MS Word (ou Excel) doit être installé sur votre serveur (croyez-le ou non, mais la génération du document Word par ce biais se fait directement…dans Word — vive les API);
  • bonjour la syntaxe à se colletiner pour générer un document, disons, à peu près propre (je suis à peu près gentil, en l’espèce).

Si c’est cette voie que vous choisissez, allez voir un peu sur PHPClasses les classes existant qui vous simplifient (un peu) la tâche (ou sur google, ou ce que vous voulez, ce n’est plus, à ce stade, mon problème).

Pour ma part, autant se contraindre pour une fonctionnalité d’export sur une application web est un hérésie.

Du coup, qu’est-ce qu’on fait ?

Je vais être clair, simple, précis et concis comme à mon habitude (sauf pour « concis ») : votre choix va dépendre directement du niveau de rétrocompatibilité que vous souhaitez pouvoir gérer; dans ce cadre, il y a trois grandes étapes dans la vie de MS Word :

  • avant MS Word 2003;
  • de MS Word 2003 à 2007;
  • depuis MS Word 2007.

Pour être compatible avec une version antérieure à 2003, vous pouvez utiliser la fausse bonne idée de tantôt, ou décider de changer de client (ce n’est pas toujours déshonorant). En effet, sur ces versions là, le code qui compose un fichier .doc est autant illisible que complètement propriétaire, et seules les API Microsoft vous permettent d’y pouvoir quelque chose.

Depuis la version 2003, les documents Word ont la possiblilté d’être tout simplement sauvés dans un format XML (appelé indifféremment WordProcessingML ou WordML); il existe désormais des sites entiers vous expliquant comment ce langage est constitué. Pour information, la première fois que j’ai eu à fabriquer des documents Word, ce n’était pas le cas, et la seule solution qui s’offrait à moi consistait à ouvrir un nouveau fichier Word, y faire quelque chose (du texte, une image, un tableau, un alignement, etc.), l’enregistrer au format XML et enfin lire le fichier XML brut pour comprendre ce qu’il s’y passait.

Pour vous donner une idée, l’écriture automatique de Word à l’époque ressemble beaucoup au code HTML qui était généré par les premières versions de Dreamweaver, et qui pouvait parfois donner des choses comme :

 

<b></b><b></b><b>mon texte<b> </b><b>en</b><b> </b>gras<b></b></b>

Et histoire d’améliorer la lisibilité, Word ne connaissait tout simplement par le retour chariot (ou retour à la ligne pour les profanes qui, s’ils sont normalement constitués, ne sont pas en train de lire cet article mais en train de regarder la vidéo d’un chat complètement ivre sur YouTube).

Juste une petite précision : en fait, Word connaissait très bien le retour chariot, mais uniquement lorsqu’il s’agissait d’intégrer une image dans un document Word; en effet, la méthode propre, mise au point par Microsoft pour intégrer une image dans un fichier Word consistait…à encoder intégralement l’image dans le fichier .doc, et lorsque je dis « encoder », je veux dire « écrire l’intégralité du contenu du fichier image en Base64 directement dans le fichier .doc » (sic).

Ce qui est drôle, en l’espèce, c’est que, selon la méthode utilisée, si vous dupliquez une image dans un fichier Word, dans un cas il encodera complètement deux fois la même image, et dans un autre cas il ne l’encodera qu’une fois et y fera simplement référence pour la seconde insertion; je vous laisse trouver par vous-même ce qu’il faut faire pour choisir le cas qui, au final, fait une différence de poids (au sens du nombre d’octets).

Enfin, depuis la version 2007, Microsoft s’est rangée du côté de la mouvance générale grace à l’utilisation d’OpenXML, qui rationnalise enfin correctement ce qui constitue un document texte :

  • une feuille de style (et une mise en page);
  • un contenu brut;
  • des images, tableaux excel et autres insertions;
  • des méta-données.

Le tout, dans une boîte nommée .docx qui, à l’instar des archives Java .JAR, n’est strictement rien d’autre qu’un conteneur ZIP (dézippez un fichier docx et vous verrez à quel point c’est relativement plus propre, maintenant).

S’il te plaît, Bruce, enfonce une porte ouverte

Avec plaisir…Bien évidemment, les versions OpenXML ne sont pas compatibles avec les versions antérieures à la version 2007, et les versions WordML ne sont pas compatibles avec les versions antérieures à la version 2003.

J’ajoute que, si OpenXML est tout à fait compatible avec les grands autres logiciels de traitement de texte que sont celui d’OpenOffice-dont-le-nom-m’échappe-et-je-n’ai-même-pas-envie-de-perdre-10-secondes-à-le-retrouver, ou encore Pages (celui d’iWork, développé par Apple®), ce n’est absolument pas le cas de WordML (en tout cas pour Pages), alors que la vieille version propriétaire, elle, est plutôt compatible avec tout le monde.

Du coup, le choix du langage sur lequel vous allez vous appuyer dépend un peu de ce que le client est prêt à accepter comme contrainte :

  • vous connaissez déjà les contraintes de la première version;
  • pour WordML, cela signifie que le client doit pouvoir lire le fichier généré et le convertir (à l’enregistrement) dans un format plus « standard »;
  • pour OpenXML, cela signifie que le client doit veiller à ne pas destiner les fichiers résultant à des tiers qui ne disposeraient pas d’une version suffisamment récente de MS Word.

J’ajoute, concernant ce choix, que ce qui va également vous motiver :

  • option 1 : pas très chère;
  • option 2 : un peu chère;
  • option 3 : bien plus chère.

Ceci étant, les options 2 et 3 sont plutôt réutilisables (surtout la 3).

Avec tout ça, on n’a même pas encore commencé

Je suis d’accord; mais le sujet est suffisamment vaste et complexe pour qu’on le divise en parties distinctes et intelligibles indépendamment les unes des autres. C’est pourquoi cet article s’arrête ici; le prochain article de ce dossier concernera le cas relativement simple du document Word que l’on génère à partir de modèles, sur un mode assez classique de fusion de données extérieures à l’intérieur d’un document existant, comme pour le publipostage.

 

 

Étape suivante : Générer un document Word à partir d’un modèle

12 réponses à to “Générer un document Word dynamiquement, en PHP”

  • GreG:

    OpenDocument. Voilà, tu as perdu ta seconde, mais pas à chercher.

  • GreG:

    Encore que je suis pas sûr d’avoir compris si c’était le nom de format ou le nom du logiciel que tu cherchais. Sinon c’est Writer.

  • Un jour, il faudra que je comprenne pourquoi, lorsque je cherche un nom à donner à ma société, tout ce qui peut me venir à l’esprit est déjà déposé, quel qu’en soit le sens, et que les traitements de textes aient réussi à protéger des noms aussi évidents que : Word, Pages et Writer.

    Tout ceci m’agace. Mais merci pour l’info, monsieur GreG.

  • GreG:

    Tu m’as poussé à aller voir la base marque de l’INPI, Microsoft est bien titulaire en France d’une marque « Microsoft Word » et d’une marque « Word », mais je ne sais pas pourquoi j’ai des doutes sur la solidité de la seconde pour t’empêcher d’éditer un traitement de texte nommé « Bruce’s Word » ou au moins « Bruce Words and Letters ». Mais bon je suis pas très calé en propriété intellectuelle.

  • Noémie:

    Bonjour,

    Votre article est très intéressant, à quand la suite?

  • Merci de votre intérêt; le dossier en question va être long de près d’une dizaine d’articles au final. Un nouvel article vient d’être publié, sur la génération dynamique de documents Word depuis un modèle existant.

  • elsa:

    Bonjour, j’ai un document word que je dois modifier a l aide de mon application web.

    Mon application devra avoir un menu avec plusieurs onglets. Chaque onglet me donnera un resultat.

    Dans un des onglets par exemple, on doit remplir un tableau.
    Le but dans ce cas est d ajouter ce tableau a mon document word.

    Comment le faire?

    Merci bcp.

  • C’est un problème qui peut être résolu assez simplement, mais sous certaines conditions; si les colonnes de ce tableau sont connues (ou au moins le nombre de colonnes), le plus simple est de créer un fichier word (vide, donc) et de créer un tableau avec le même nombre de colonnes, et trois lignes; dans la première ligne, renseignez les noms des colonnes (ou des noms de colonnes); dans les deux lignes suivantes, remplissez les cellules en les suffixant par le numéro de ligne et le numéro de colonne : élément_1_1, élément_1_2…puis élément_2_1, élément_2_2…

    Enregistrez le fichier au format XML et ouvrez le dans un bel éditeur XML; le jeu consiste à isoler la première ligne des éléments (donc la seconde ligne du tableau); cette ligne devient votre variable, dans laquelle chaque valeur de cellule est une variable.

    Si vous avez besoin de compléments, indiquez-le moi par réponse de commentaire et je vous enverrai un exemple directement par email.

  • Akira:

    Bonjour Bruce,

    J’ai une petite question, tu as écris ceci:
    « Pour vous donner une idée, l’écriture automatique de Word à l’époque ressemble beaucoup au code HTML qui était généré par les premières versions de Dreamweaver ».

    Or quand je génère un document XML World (version 2007). J’ai droit à un beau texte non indenté. Je voudrai savoir si cela vient de mon éditeur (NotePad++), j’ai un gros doute. Je pense que ça vient à la base car le document fut sauvegarder sous la version 2003 de word.

    Cordialement,
    Akira

  • Ca fait longtemps que je n’ai pas testé, donc je ne sais pas quelle version de Word sort quel résultat. Maintenant, de mémoire, Word sort toujours un fichier XML sans indentation ni quasiment aucun retour à la ligne — moche !

    Mais surtout, ce que je voulais dire par rapport à dreamweaver, c’est la chose suivante :
    dans les premières versions de dreamweaver, si tu sélectionnais un texte, que tu le mettais en gras, puis plus en gras, puis à nouveau en gras, deux ou trois fois, tu pouvais rapidement te retrouver avec un résultat du genre :

    Mon texte

    Ce qui fonctionnait, mais était illisible.
    Et encore, les tags sont simples et clairs…imagine le même résultat sous WordML…

  • Bonjour, merci pour cet article avec de l’humour en prime !

  • rubinse:

    Bonjour tous le monde,

    Je rencontre un probleme lors de la génération du word, il y a une quantité d’espace entre chaque ligne, avez vous une idée? 15 jours que je cherches et pas de solution

    Merci pour votre réponse

    Fabrice