# Životný cyklus požiadavky: štart, vykonanie, shutdown

> Životný cyklus požiadavky PHP vysvetlený: MINIT, RINIT, RSHUTDOWN, MSHUTDOWN, opätovné použitie workerov a prečo CVE-2026-109619 útočí práve tu.

Zdroj: https://phpsos.de/sk/php/request-lebenszyklus/  
Stav: 25.10.2026  
Poskytovateľ: PHP SOS, Núdzová pomoc pri PHP a bezpečnosť serverov. Okamžitá pomoc cez WhatsApp: https://wa.me/491736494914?text=Dobr%C3%BD%20de%C5%88%2C%20PHP%20SOS%2C%20potrebujeme%20pomoc%20s%20na%C5%A1%C3%ADm%20serverom%20s%20PHP.%20Spolo%C4%8Dnos%C5%A5%3A%20%E2%80%A6%20Web%3A%20%E2%80%A6

**Stručne:** Životný cyklus požiadavky PHP má dve úrovne. Raz na proces PHP načíta svoje rozšírenia (fáza MINIT) a na konci ich opäť odbúra (MSHUTDOWN). Pre každú jednotlivú požiadavku existuje vlastná štartovacia a upratovacia fáza (RINIT a RSHUTDOWN). Vo webovej prevádzke worker vybavuje mnoho požiadaviek po sebe, preto musí PHP medzi dvoma požiadavkami spoľahlivo vynulovať všetok stav požiadavky. Práve na tejto hranici ležala CVE-2026-109619, druhá zraniteľnosť PHP2Shell.

## Dve úrovne: proces a požiadavka

Pre netechnikov pomáha prirovnanie: worker PHP je ako okienko na úrade. Okienko sa ráno raz zariadi, s formulármi, pečiatkami a počítačom. Potom prichádza po sebe mnoho návštevníkov. Po každom návštevníkovi musí byť stôl prázdny, aby ďalší nevidel cudzie podklady.

PHP funguje rovnako. Pri štarte procesu načíta rozšírenia a nastavenia, ktoré sú pre všetky požiadavky rovnaké. Každá požiadavka potom dostane vlastnú pamäť, vlastné premenné a vlastné údaje požiadavky, ako `$_GET`, `$_POST` alebo `$_FILES`. Na konci požiadavky PHP túto pamäť uvoľní. PHP Internals Book to zhŕňa stručne: PHP na konci každej požiadavky zabudne pamäť požiadavky.

## Fázy životného cyklu požiadavky PHP v prehľade

Názvy pochádzajú z vnútra PHP; každé rozšírenie sa môže do týchto fáz zapojiť.

| Fáza | Kedy beží | Ako často | Typická úloha |
|---|---|---|---|
| MINIT (Module Init) | pri štarte procesu | raz na proces | registrovať rozšírenia, vytvoriť záznamy ini, trvalé údaje |
| GINIT | pri vytváraní globálnych premenných | na proces, pri vláknach na vlákno | pripraviť globálne premenné rozšírenia |
| RINIT (Request Init) | na začiatku každej požiadavky | na požiadavku | pripraviť pamäť a stav požiadavky |
| Vykonanie | medzitým | na požiadavku | beží váš kód PHP |
| RSHUTDOWN | na konci každej požiadavky | na požiadavku | uvoľniť zdroje požiadavky |
| PRSHUTDOWN | po RSHUTDOWN | na požiadavku, zriedka používané | posledné upratovacie práce |
| MSHUTDOWN | pri ukončení procesu | raz na proces | uvoľniť trvalé údaje |

Dôležitá veta z PHP Internals Book pre vývojárov rozšírení: globálne premenné sa po každej požiadavke automaticky nevyprázdňujú. Čo musí byť pri každej požiadavke čerstvé, patrí vynulovať v RINIT. Toto pravidlo ukazuje, prečo je hranica medzi dvoma požiadavkami bezpečnostne kritickým miestom.

Na konci požiadavky je poradie tiež pevne dané: najprv bežia funkcie shutdown, ktoré ste zaregistrovali pomocou `register_shutdown_function()`, potom destruktory, potom sa vyprázdni výstupný buffer. Až potom nasleduje RSHUTDOWN.

## Prečo sa workery používajú opakovane

V príkazovom riadku vybaví proces presne jednu požiadavku a skončí. Vo webovej prevádzke by to bolo príliš pomalé. PHP-FPM, Apache s mod_php, LiteSpeed a FrankenPHP preto držia workery, ktoré obsluhujú mnoho požiadaviek za sebou. MINIT potom beží raz, RINIT a RSHUTDOWN tisíckrát. Ako FPM riadi svojich workerov, vysvetľuje [PHP-FPM vysvetlené](https://phpsos.de/sk/php/php-fpm-erklaert/).

V PHP-FPM určuje `pm.max_requests`, po koľkých požiadavkách sa worker reštartuje. Štandard je `0`, teda neobmedzene. Príručka toto nastavenie uvádza ako prostriedok proti únikom pamäte v knižniciach tretích strán:

```ini
; Pool FPM: reštartovať worker po 500 požiadavkách (proti únikom pamäte)
pm = dynamic
pm.max_children = 20
pm.max_requests = 500
```

Ešte ďalej ide režim workera vo FrankenPHP: tam sa celá aplikácia spustí raz a zostáva v pamäti. Stav aplikácie potom prežíva aj na úrovni PHP. Príklad ukazuje rozdiel:

```php
<?php
function anfrageZaehler(): int
{
    static $zaehler = 0;   // v klasickej prevádzke FPM je pri každej požiadavke opäť 0
    return ++$zaehler;     // v režime workera hodnota naďalej rastie naprieč požiadavkami
}
echo anfrageZaehler();
```

V klasickej prevádzke vypíše volanie vždy 1, pretože PHP zahodí pamäť požiadavky. V režime workera hodnota rastie, kým worker žije. Dokumentácia FrankenPHP preto radí stav viazaný na požiadavku medzi požiadavkami vedome vynulovať.

## Kde útočí CVE-2026-109619

CVE-2026-109619 sa netýka vášho aplikačného kódu, ale samotného PHP. Podľa php.net mohol interný stav patriaci k požiadavke prežiť uvoľnenie svojej pamäte. Neskoršia požiadavka v tom istom workeri ho mohla použiť skôr, než ho inicializácia vynulovala. V obraze: na stole okienka zostal ležať lístok, ktorý mal byť už odložený. Podrobnosti o zneužití zámerne nezverejňujeme; zaradenie je uvedené v [CVE-2026-109619](https://phpsos.de/sk/php2shell/cve-2026-109619/).

Prechodné opatrenia php.net k tejto zraniteľnosti sa opierajú o potvrdené cesty, nie sú úplnou ochranou:

1. `session.upload_progress.enabled=0` v php.ini, poole FPM alebo konfigurácii servera, potom reštartovať všetky workery; nie cez `ini_set()` ani `.user.ini`.
2. Na PHP 8.5 navyše `fatal_error_backtraces=0` a reštart.
3. Odstrániť neplatné alebo zastarané nastavenia pre každú požiadavku, ktoré pred inicializáciou vytvárajú hlásenia. Hlásenia iba skryť podľa php.net nepomáha.
4. Opraviť v aplikácii fatálne chyby a prekročenia času, ktoré sa dajú vyvolať zvonku, aj v callbackoch, pri spracovaní nahrávaní a importov.

Skutočným riešením je aktualizácia na PHP 8.5.12, 8.4.27, 8.3.36 alebo 8.2.35. Pretože chyba sídli v bežiacom workeri, účinkuje až po reštarte všetkých procesov; kroky sú uvedené v [Reštart PHP-FPM a všetkých workerov](https://phpsos.de/sk/php2shell/php-fpm-neustart/).

> **Tip:**
> Po reštarte skontrolujte pomocou `ps -eo pid,lstart,cmd | grep php`, či sa všetky procesy PHP spustili po čase aktualizácie.

## Čo životný cyklus znamená pre prevádzku a vývoj

Z modelu sa dajú odvodiť jasné pravidlá. Pre administrátorov: aktualizácia je účinná, až keď už nebeží žiadny proces so starým kódom. Každý spôsob prevádzky s dlhožijúcimi workermi potrebuje zdokumentovaný reštart. Pre vývojárov: kód, ktorý beží v režimoch workera, nesmie nechávať stav viazaný na požiadavku v statických premenných alebo singletonoch, napríklad údaje používateľa alebo oprávnenia. Pre oboch platí: uchovajte logy od 20. 10. 2026, aby sa neskôr dalo posúdiť, či sa pred záplatou niečo stalo.

## Ako PHP SOS konkrétne pomáha?

Pomocou [služby záplatovania PHP](https://phpsos.de/sk/leistungen/php-patch-service/) model uplatňujeme v praxi:

- **Určenie spôsobu prevádzky:** Zisťujeme, či beží PHP-FPM, mod_php, LiteSpeed, FrankenPHP alebo php-cgi a ako sa workery spravujú.
- **Aktualizácia a reštart:** Nasadzujeme opravenú verziu a kontrolovane reštartujeme každý worker.
- **Kontrola procesov:** Pomocou časov štartu a verzií dokladujeme, že nezostal žiadny starý proces.
- **Kontrola režimov workera:** Pri dlhožijúcich aplikáciách sa pozeráme, či sa stav viazaný na požiadavku čisto nuluje.


## Časté otázky

**Spúšťa PHP pre každú požiadavku nový proces?**  
V príkazovom riadku áno, vo webovej prevádzke väčšinou nie. PHP-FPM, Apache s mod_php, LiteSpeed alebo FrankenPHP nechávajú jeden proces vybavovať mnoho požiadaviek po sebe. Medzi požiadavkami PHP upratuje stav požiadavky.

**Aký je rozdiel medzi MINIT a RINIT?**  
MINIT beží raz, keď sa proces PHP spustí, a vytvára trvalé štruktúry. RINIT beží na začiatku každej jednotlivej požiadavky a pripravuje to, čo potrebuje len táto požiadavka.

**Pomáha pm.max_requests proti CVE-2026-109619?**  
php.net častejšie reštarty workerov ako prechodné opatrenie neuvádza. Nastavenie obmedzuje iba to, koľko požiadaviek worker vybaví pred reštartom. Proti zraniteľnosti pomáha aktualizácia s následným reštartom všetkých workerov.

**Čo je režim workera vo FrankenPHP?**  
V režime workera sa aplikácia spustí raz a zostáva v pamäti. Ušetrí to čas, ale statické premenné, globálne premenné a cache sa medzi požiadavkami zachovávajú. Podľa dokumentácie FrankenPHP sa preto stav viazaný na požiadavku musí vedome vynulovať.

## Zdroje

- [php.net: Bezpečnostné oznámenie z 21. 10. 2026](https://www.php.net/)
- [Príručka PHP: Konfigurácia FPM](https://www.php.net/manual/en/install.fpm.configuration.php)
- [PHP Internals Book: Životný cyklus PHP](https://www.phpinternalsbook.com/)
