Aller au contenu
AFUP AFUP Day 2025 Baromètre Planète PHP PUFA
 

Une extension PHP rouillée

Description

Écrire une extension PHP en 2022, quand on ne maîtrise pas forcément le C peut-être un parcours du combattant. Quand on vient du langage PHP, les concepts de gestion de mémoire et les bugs associés (use after free par exemple) sont lointains et peuvent nous conduire à des failles de sécurité importantes. En plus de cela, nous devons aussi absorber l'utilisation de l'API de Zend Engine. J'ai découvert Rust, il y a peu de temps : un langage qui garantit fiabilité, performance, productivité et surtout permettant d'ouvrir une passerelle vers le C. Voyons voir si l'expérience serait plus heureuse avec ce langage.

On commencera par faire un tour de l'état de l'art des extensions PHP et pourquoi Rust. On utilisera aussi la crate Rust ext-php-rs et voir comment wrapper des API Rust pour ainsi les proposer côté utilisateur PHP. On terminera sur comment automatiser la distribution de notre extension et enfin, conclure sur la valeur ajoutée.

Conférence donnée lors du Forum PHP 2022, ayant eu lieu les 13 et 14 octobre 2022.

Informations complémentaires

Vidéo

Le speaker

Pierre TONDEREAU

Ingénieur logiciel

Verbatim

_ Merci à tous. Ça fait plaisir. Il y a du monde. Qui a déjà fait du Rust dans la salle ? Il y en a beaucoup. Ça compte. Je vais vous présenter ma petite expérience que j'ai faite de manière personnelle où je me suis lancé dans l'aventure de créer une extension PHP avec Rust.

L'histoire commence avec Rust. Je l'ai découvert il y a un an. Le temps passe vite. Pour rappel, je vois qu'il y a pas mal de mains qui se sont levées, ça a été créé en 2015. C'était un langage qui était porté par l'entreprise Mozilla. Elle a émergé d'un projet de refacto de leur navigateur et de leur moteur de rendu HTML. Le but du jeu, c'était d'amener la performance au rendez-vous. Leur navigateur était toujours C++. Tout en évitant l'aspect sécurité. La gestion de la mémoire. Le langage est né. Il a évolué depuis. Spoiler : Je n'ai pas réécrit totalement la VM de PHP en Rust. Mais dans une édition du forum de PHP 2017, il y avait Yvan qui était venu présenter un truc en VM. Je veux montrer comment Rust peut échanger avec d'autres langages.

Il va s'articuler autour de trois thématiques majeures. La performance. C'est toujours rapide. Presque aussi rapide que du C ou du C++. Il se rapproche beaucoup de PHP, parce qu'il n'a pas une exécution de base. Comme PHP, il s'exécute, et à la fin, plus rien n'existe. Par contre, il n'y a pas de ramasse-miettes, de Garbage Collector. Il y a tout un système d'emprunt dans la mémoire qui permet de garantir tous ces sujets dans la mémoire.

Je ne vais pas entrer trop dans le détail. Au-delà de cela, vous pouvez totalement utiliser Rust pour comprendre les principes. C'est même conseillé quand on démarre. Il y a une barrière d'entrée pour entrer dans le langage. Mais sans connaître tous ses principes, on peut s'en sortir simplement.

Il y a de la fiabilité. Il y a tout un système de typage. Je ne vais pas mettre trop d'exemples de code. Mais c'est comme si vous aviez un PHP stan ou du TypeScript. Ça ressemble énormément. Il y a tout le tooling qui vient avec et qui est extraordinaire. Je l'utilise depuis huit ans. J'utilise Composer comme la plupart des DEV ici. Pour retrouver cette même expérience de gestion package management, j'ai réussi à la retrouver avec l'outil qui s'appelle cargo. C'est développé par Rust. Il y a tout ce qui vient avec, le paquet du management. On peut écrire des commentaires de type markdown. Dans le code. Tout est généré en HTML. On peut l'exporter dans un site. Tout est généré automatiquement par le magnum que vous avez dans le code.

Avant de continuer, je vais rappeler la méthode classique pour faire des extensions PHP. Un site qui est vraiment très utile et qui m'a fait découvrir de nombreuses choses, je remercie d'ailleurs Pascal Martin. Il a vulgarisé pas mal de choses, surtout le cycle de vie. C'était très intéressant. Merci. Tu m'as fait économiser 10 minutes sur la slide. Ce site, il faut l'avoir en tête quand vous voulez naviguer sur le code PHP ou créer des extensions. C'est du C. Ça peut être compliqué. J'ai fait les frais moi-même. Le C, j'avais une mince expérience. Ça remonte à très loin. Il faut digérer pas mal de choses pour pouvoir faire. La convention de nommage est un peu bizarre. Dans le sens où vous pouvez faire une extension de PHP 5, on appelle cela un module PHP dans le site. C'est de créer des interfaces. Interagir avec des encodeurs. Sans avoir à utiliser la gestion de la mémoire en PHP avec le Zend Memory Management. C'est ce qui diffère de la zone d'extension. Ce sera le sujet. On donne toute la maîtrise de la gestion de la mémoire à l'utilisateur. On dit bien que c'est risqué. À vos risques et périls.

Je découvre cela avec stupéfaction. Je me dis : Par quel bout je vais le manger ? Je découvre Rust au même moment. Je me dis : Il doit y avoir un système pour pouvoir dialoguer avec le C. Avec PHP, il y a FFI. Pourquoi est-ce que Rust n'aurait pas la même chose ? Il y a du FFI. Il y a quand même des gens qui ont dû faire des bugs dans le coin. Exposer cela. Je suis arrivé vite à une bibliothèque que j'ai trouvée dans mes recherches. Ça s'appelle ext-php-rs. Le nommage n'est pas fou.

J'ai rejoint les mainteneurs il n'y a pas longtemps. Dans le but de la faire évoluer le plus rapidement possible. C'est le but de cette conférence. Faire le plus de retours possible de gens qui auraient des besoins production. Pour ceux qui font du Rust sur leur temps libre ou de manière professionnelle, n'hésitez pas à vous en emparer. Invitez-le à fond. Nous n'attendons que des retours.

L'objectif de cette bibliothèque, elle a un but très clair. Coder en C, ça peut être rébarbatif. Rust, ça l'est un peu moins. Il y a du sucre syntaxique. Il y a plus d'attraction au niveau sur ces sujets. C'est mieux expliqué. Il y a une grosse documentation. Tout est fait pour être plus accessible que le C à mon sens. Le pari: La librairie C existe. Où de grands FFI. On va aller tout extraire la touche du C. Il n'y a pas tout dans le système. Quand je vais vous montrer du code... le but du jeu, ce sera de créer tout cela simplement, sans fioriture, avoir l'expérience pour créer vos extensions. Il y a le support de Linux, MD64 et RM, il y a Mac OS qui est supporté en MD64 et architecturial pour tous les possesseurs de M1. Mais pour Windows, c'est plus utile. Ce n'est pas stabilisé. Je ne l'ai pas dit tout à l'heure. Rust a un système de channel pour tout ce qui est accessibilité des nouvelles versions. Je ne sais pas si vous l'avez déjà vu, mais ça fonctionne comme Firefox. Les bulles continues du navigateur, ils ont continué la même chose avec Rust. C'est émergé sur le Master. Il y a tout le channel stable où il y a une stabilisation complète des API avec un système de rétrocompatibilité. Vous n'allez pas tout casser si vous passez d'une version à l'autre.

Le support de Windows passe par... ** malheureusement. Ce qui est proposé dans Rust, dans les API, on ne pourra pas l'utiliser dans Windows.

Qu'est-ce que ça donne vos codes ? Voilà. Les deux premières lignes, on s'en fout. C'est du code spécifique Windows. Ce qu'il faut comprendre, c'est PHP_function. Comme ce que vous faites avec le langage PHP depuis la version huit. On peut marquer des classes. Derrière, c'est ce qu'on appelle des macros. Chez Rust... côté utilisateur final qui va développer, vous allez pouvoir déclarer une fonction. Il y a le PHP Module. Je n'en ai pas beaucoup parlé. Mais ça a été évoqué dans certaines conférences. Je pense que c'est celle de Pascal Martin. Quand vous développez une extension PHP, vous devez dire à PHP : Toutes les classes que je vais utiliser, toutes les variables, les constantes, les fonctions, au runtime, il faut le compiler côté Rust pour dire : comptabilise tout cela. Dans le cycle de vie de PHP, quand ça démarre et quand ça s'arrête, la mémoire de Rust, comment je dis : Tu peux arrêter d'exécuter. Ça sert à cela. Ça va bouger. Il y a une PR qui est en cours pour supprimer pour que ce soit le plus simple possible.

C'est rendu possible par rapport au FFI. Pareil. C'est indigeste à comprendre au début. Mais ça fait du sens de comprendre comment ça s'empile. Il y a le lien pour comprendre comment utiliser le FFI avec Rust. Ce sont des mots-clés, mais de la syntaxe spécifique Rust. C'est bien documenté.

C'est le schéma très simplifié. De comment ça s'interface avec PHP. L'histoire commence là. Rust, le code source de PHP. Les en-têtes. On va pouvoir lui dire : cherche-moi toutes les en-têtes et génère du code Rust qui va permettre de l'exécuter. La bibliothèque va faire une abstraction de tout cela. Pour que ce soit simple à utiliser. Derrière, Rust va exposer avec le FFI du C. Le moteur PHP, il pourra comprendre : C'est une véritable extension. Ça marche pour moi. C'est la partie la plus complexe du document.

Ça a mené à plein de choses. Il y a des exemples dans la bibliothèque que j'ai signée dans readme. Il y a plein de cas d'utilisations qui peuvent en découler. Mais il y a aussi d'autres exemples plus simples : Comment on s'interface avec la librairie opus. C'est une petite librairie qui est utilisée et qui permet de faire du streaming ou de l'encodage à des fins de stockage. Je vous laisse aller voir dans le readme. Je n'aurais pas le temps de vous le montrer. Comment ça se passe, comment ça s'interface.

J'ai été plus loin. Je suis resté sur ma faim. J'ai été faire une implémentation personnelle. Je montrerai du code plus tard. J'ai fait une implémentation de l'algorithme. C'est un algorithme qui est décrit dans la documentation de reddis qui permet de faire du log, distribuer sans faire de la documentation sur plusieurs serveurs reddis. On veut obtenir un blog pour une ressource particulière. On déclare la liste des serveurs éligibles. Quand ça va locker, ça va déclencher sur reddis et les serveurs. Il va toujours répondre. Peu importe que le serveur soit up ou down.

Comment ça se matérialise. Il y a le code source en ligne. Je vous laisserai avec le QR code aller faire un tour. J'ai eu deux problématiques. La distribution de l'extension. Vous voyez, c'est qu'il faut importer. Pour chaque OS, chaque architecture, il faut le compiler. Et chaque version de PHP. Ce que je conseille, quand vous êtes dans cette situation et que vous n'êtes pas forcément Open Source dès le début, c'est de faire ce qui vous intéresse. Vous avez un serveur Linux, compilez seulement pour Linux début. Et vous ajustez au fur et à mesure.

Il y a du sucre syntaxique pour activer différentes fonctionnalités dans le code Rust. Pas besoin de faire des cafouillages en PHP pour savoir : je suis sous MD... c'est le problème de Rust, pas PHP. Il y a un truc que j'aurais aimé montrer. Ce sont les tests end to end. Est-ce que les classes que j'écris fonctionnent ? Est-ce que ça redonne quelque chose ? Du tooling, ça permet de faire cela facilement. Il y a PHP Unit. Pourquoi est-ce que je ne l'utiliserais pas ? Je prends les classes que j'ai créées côté Rust, je les utilise, je vérifie si ça marche bien.

Il y a un truc, je vais passer rapidement dessus. Quand vous faites une extension qui ne marche pas aux yeux de PHP, les IDE ne vont pas comprendre ce que vous faites. Il y a ce qu'on appelle les stubs. Des classes vides qui exposent des prototypes de fonctions. Ou des attributs, des fonctions. C'est généré automatiquement par la bibliothèque. Il y a un outil en ligne de commande qui est incluse en ligne des bibliothèques. C'est en alpha. Il n'y a pas tous les cas couverts. Mais dans le lien que j'ai mis, j'ai fait un fork de vieux tool en PHP. Il utilise à outrance réflexion pour générer le code. Si ça fait le boulot très bien pour l'instant. J'aimerais que les gens me fassent des retours sur la bibliothèque principalement pour qu'on couvre le plus de cas possible. C'est exhaustif. Aujourd'hui, ça existe, ça fonctionne.

Dernière information. Pourquoi utiliser Rust ? Je vais reprendre les arguments que j'ai listés tout au long de la conférence. La performance, ça ne m'intéressait pas. C'était plutôt la sécurité. Je ne sais pas si vous avez vu ces dernières années dans le navigateur Google Chrome qui est C++ le nombre de failles de sécurités qui sont liées à de la gestion de la mémoire ? C'est affolant et ça coûte très cher. Microsoft, je n'ai pas mis les liens, mais c'est facilement rechargeable sur Internet. Microsoft, le pôle sécurité, en 2019, il avait fait un article comme quoi la performance pour eux, ce n'était plus leur priorité. C'était vraiment axé sur la sécurité et la gestion de la mémoire. En termes de budget entre la performance ultrarapide et des oublis de sécurité, ce qui compte le plus cher, ce sont les oublis de sécurité. Le Rust, ce qui est cool, quand vous interfacez avec industrie, vous pouvez le wrapper pour que ce soit safe. Vous n'êtes pas à l'abri d'un petit bug. Rust ça permet de garantir une sécurité en wrappant les méthodes.

Voilà. C'était ma première conférence. J'espère que ça vous a plu. J'étais très condensé. Je suis désolé si vous n'avez pas vu assez de codes. Mais vous pouvez faire du feed-back sur Open Feedback. Je vous remercie beaucoup.

(applaudissements)