# Le cycle de vie d'une requête : démarrage, exécution, arrêt

> Le cycle de vie d'une requête PHP expliqué : MINIT, RINIT, RSHUTDOWN, MSHUTDOWN, réutilisation des workers et pourquoi CVE-2026-109619 s'attaque à ce point précis.

Source : https://phpsos.de/fr/php/request-lebenszyklus/  
État : 25/10/2026  
Fournisseur : PHP SOS, Assistance d'urgence PHP et sécurité des serveurs. Aide immédiate par WhatsApp : https://wa.me/491736494914?text=Bonjour%20PHP%20SOS%2C%20nous%20avons%20besoin%20d%27aide%20avec%20notre%20serveur%20PHP.%20Entreprise%20%3A%20%E2%80%A6%20Site%20web%20%3A%20%E2%80%A6

**En bref :** le cycle de vie d'une requête PHP comporte deux niveaux. Une fois par processus, PHP charge ses extensions (phase MINIT) et les décharge à la fin (MSHUTDOWN). Pour chaque requête prise isolément, il existe une phase de démarrage et de nettoyage propre (RINIT et RSHUTDOWN). En exploitation web, un worker traite de nombreuses requêtes l'une après l'autre ; PHP doit donc réinitialiser de façon fiable tout l'état de la requête entre deux requêtes. C'est précisément à cette frontière que se situait CVE-2026-109619, la seconde faille PHP2Shell.

## Deux niveaux : le processus et la requête

Pour les non-techniciens, une image aide : un worker PHP est comme un guichet dans une administration. Le guichet est installé une fois le matin, avec formulaires, tampons et ordinateur. Ensuite, de nombreux visiteurs se succèdent. Après chaque visiteur, le bureau doit être vide, pour que le suivant ne voie pas les documents d'un autre.

PHP fonctionne de la même manière. Au démarrage d'un processus, il charge les extensions et les réglages qui sont les mêmes pour toutes les requêtes. Chaque requête reçoit ensuite sa propre mémoire, ses propres variables et ses propres données de requête comme `$_GET`, `$_POST` ou `$_FILES`. À la fin de la requête, PHP libère cette mémoire. Le PHP Internals Book le résume brièvement : PHP oublie la mémoire de la requête à la fin de chaque requête.

## Les phases du cycle de vie d'une requête PHP en un coup d'œil

Les noms viennent de l'intérieur de PHP ; chaque extension peut s'accrocher à ces phases.

| Phase | Quand elle s'exécute | Fréquence | Tâche typique |
|---|---|---|---|
| MINIT (Module Init) | au démarrage du processus | une fois par processus | enregistrer les extensions, créer les entrées ini, données durables |
| GINIT | à la création des globales | par processus, avec les threads par thread | préparer les variables globales d'une extension |
| RINIT (Request Init) | au début de chaque requête | par requête | préparer la mémoire et l'état de la requête |
| Exécution | entre les deux | par requête | votre code PHP s'exécute |
| RSHUTDOWN | à la fin de chaque requête | par requête | libérer les ressources de la requête |
| PRSHUTDOWN | après RSHUTDOWN | par requête, rarement utilisée | derniers travaux de nettoyage |
| MSHUTDOWN | à l'arrêt du processus | une fois par processus | libérer les données durables |

Une phrase importante du PHP Internals Book pour les développeurs d'extensions : les globales ne sont pas vidées automatiquement après chaque requête. Ce qui doit être neuf à chaque requête doit être réinitialisé dans RINIT. Cette règle montre pourquoi la frontière entre deux requêtes est un point critique pour la sécurité.

À la fin d'une requête, l'ordre est lui aussi fixé : d'abord s'exécutent les fonctions de shutdown que vous avez enregistrées avec `register_shutdown_function()`, puis les destructeurs, puis le tampon de sortie est vidé. Ce n'est qu'ensuite que vient RSHUTDOWN.

## Pourquoi les workers sont réutilisés

En ligne de commande, un processus traite exactement une requête, puis se termine. En exploitation web, ce serait trop lent. PHP-FPM, Apache avec mod_php, LiteSpeed et FrankenPHP gardent donc en réserve des workers qui servent de nombreuses requêtes d'affilée. MINIT s'exécute alors une fois, RINIT et RSHUTDOWN des milliers de fois. La manière dont FPM pilote ses workers est expliquée dans [PHP-FPM expliqué](https://phpsos.de/fr/php/php-fpm-erklaert/).

Dans PHP-FPM, `pm.max_requests` détermine après combien de requêtes un worker redémarre. La valeur par défaut est `0`, c'est-à-dire illimité. Le manuel cite ce réglage comme remède contre les fuites de mémoire dans des bibliothèques tierces :

```ini
; Pool FPM : redémarrer le worker après 500 requêtes (contre les fuites de mémoire)
pm = dynamic
pm.max_children = 20
pm.max_requests = 500
```

Le mode worker de FrankenPHP va plus loin : toute l'application y démarre une fois et reste en mémoire. L'état de l'application survit alors aussi au niveau de PHP. L'exemple montre la différence :

```php
<?php
function anfrageZaehler(): int
{
    static $zaehler = 0;   // en exploitation FPM classique, de nouveau 0 à chaque requête
    return ++$zaehler;     // en mode worker, la valeur continue de compter d'une requête à l'autre
}
echo anfrageZaehler();
```

En exploitation classique, l'appel affiche toujours 1, car PHP rejette la mémoire de la requête. En mode worker, la valeur augmente tant que le worker vit. La documentation de FrankenPHP conseille donc de réinitialiser volontairement l'état propre à la requête entre les requêtes.

## Où CVE-2026-109619 intervient

CVE-2026-109619 ne concerne pas le code de votre application, mais PHP lui-même. Selon php.net, un état interne appartenant à la requête pouvait survivre à la libération de sa mémoire. Une requête ultérieure dans le même worker pouvait l'utiliser avant que l'initialisation ne le réinitialise. Dans l'image : un papier est resté sur le bureau du guichet alors qu'il aurait déjà dû être rangé. Nous ne publions volontairement pas de détails d'exploitation ; la description figure sous [CVE-2026-109619](https://phpsos.de/fr/php2shell/cve-2026-109619/).

Les mesures transitoires de php.net pour cette faille portent sur des voies confirmées ; elles ne constituent pas une protection complète :

1. `session.upload_progress.enabled=0` dans php.ini, le pool FPM ou la configuration du serveur, puis redémarrer tous les workers ; pas via `ini_set()` ou `.user.ini`.
2. Sur PHP 8.5, en plus `fatal_error_backtraces=0` et redémarrage.
3. Supprimer par requête les réglages invalides ou obsolètes qui produisent des messages avant l'initialisation. Masquer simplement les messages n'aide pas, selon php.net.
4. Corriger dans l'application les erreurs fatales et dépassements de délai déclenchables de l'extérieur, y compris dans les callbacks, le traitement des uploads et des imports.

Le véritable remède est la mise à jour vers PHP 8.5.12, 8.4.27, 8.3.36 ou 8.2.35. Comme le défaut se trouve dans le worker en cours d'exécution, elle n'agit qu'après un redémarrage de tous les processus ; les étapes figurent sous [Redémarrer PHP-FPM et tous les workers](https://phpsos.de/fr/php2shell/php-fpm-neustart/).

> **Astuce:**
> Après le redémarrage, vérifiez avec `ps -eo pid,lstart,cmd | grep php` que tous les processus PHP ont été démarrés après le moment de la mise à jour.

## Ce que le cycle de vie signifie pour l'exploitation et le développement

Du modèle découlent des règles claires. Pour les administrateurs : une mise à jour n'est efficace que lorsqu'aucun processus avec l'ancien code ne tourne plus. Chaque mode d'exploitation avec des workers de longue durée nécessite un redémarrage documenté. Pour les développeurs : le code qui s'exécute dans les modes worker ne doit laisser aucun état propre à la requête dans des variables statiques ou des singletons, par exemple des données d'utilisateur ou des droits. Pour les deux : conserver les logs à partir du 20 octobre 2026, afin de pouvoir juger plus tard si quelque chose s'est produit avant le correctif.

## Comment PHP SOS aide-t-il concrètement ?

Avec le [service de correctifs PHP](https://phpsos.de/fr/leistungen/php-patch-service/), nous mettons le modèle en pratique :

- **Déterminer le mode d'exploitation :** nous établissons si PHP-FPM, mod_php, LiteSpeed, FrankenPHP ou php-cgi tourne et comment les workers sont gérés.
- **Mise à jour et redémarrage :** nous installons la version corrigée et redémarrons chaque worker de façon contrôlée.
- **Contrôle des processus :** nous prouvons, à l'aide des heures de démarrage et des versions, qu'il ne reste aucun ancien processus.
- **Vérifier les modes worker :** pour les applications de longue durée, nous examinons si l'état propre à la requête est correctement réinitialisé.


## Questions fréquentes

**PHP démarre-t-il un nouveau processus pour chaque requête ?**  
En ligne de commande, oui ; en exploitation web, en général non. PHP-FPM, Apache avec mod_php, LiteSpeed ou FrankenPHP laissent un processus traiter de nombreuses requêtes l'une après l'autre. Entre les requêtes, PHP nettoie l'état propre à la requête.

**Quelle est la différence entre MINIT et RINIT ?**  
MINIT s'exécute une fois, au démarrage du processus PHP, et met en place des structures durables. RINIT s'exécute au début de chaque requête individuelle et prépare ce dont seule cette requête a besoin.

**pm.max_requests aide-t-il contre CVE-2026-109619 ?**  
php.net ne cite pas des redémarrages plus fréquents des workers comme mesure transitoire. Le réglage limite seulement le nombre de requêtes qu'un worker traite avant de redémarrer. Contre la faille, ce qui aide, c'est la mise à jour suivie du redémarrage de tous les workers.

**Qu'est-ce que le mode worker de FrankenPHP ?**  
En mode worker, l'application démarre une fois et reste en mémoire. Cela fait gagner du temps, mais les variables statiques, les globales et les caches subsistent entre les requêtes. Selon la documentation de FrankenPHP, l'état propre à la requête doit donc être réinitialisé volontairement.

## Sources

- [php.net : avis de sécurité du 21 octobre 2026](https://www.php.net/)
- [Manuel PHP : configuration de FPM](https://www.php.net/manual/en/install.fpm.configuration.php)
- [PHP Internals Book : cycle de vie de PHP](https://www.phpinternalsbook.com/)
