Aktuel situation: PHP2Shell. To kritiske PHP-sårbarheder (CVSS 9,2) tillader skadelig kode uden login. Rettelser siden 21.10.2026.Hvad der skal gøres nu →

Request-livscyklussen: startup, udførelse, shutdown

Hvordan PHP starter processer, behandler forespørgsler og rydder op imellem. Med faserne MINIT til MSHUTDOWN og sammenhængen med CVE-2026-109619.

Status 5 min. læsetidPHP-viden

Kort sagt: PHP request lifecycle har to niveauer. Én gang pr. proces indlæser PHP sine udvidelser (fasen MINIT) og nedbryder dem igen til sidst (MSHUTDOWN). For hver enkelt forespørgsel er der en egen start- og oprydningsfase (RINIT og RSHUTDOWN). I webdrift behandler en worker mange forespørgsler efter hinanden, og derfor skal PHP mellem to forespørgsler pålideligt nulstille al forespørgselstilstand. Netop ved denne grænse lå CVE-2026-109619, den anden PHP2Shell-sårbarhed.

To niveauer: processen og forespørgslen

For ikke-teknikere hjælper et billede: En PHP-worker er som en skranke i en myndighed. Skranken indrettes én gang om morgenen, med formularer, stempler og computer. Derefter kommer mange besøgende efter hinanden. Efter hver besøgende skal bordet være tomt, så den næste ikke ser fremmede papirer.

PHP arbejder på samme måde. Ved start af en proces indlæser det udvidelser og indstillinger, der er ens for alle forespørgsler. Hver forespørgsel får så sin egen hukommelse, sine egne variabler og egne forespørgselsdata som $_GET, $_POST eller $_FILES. Ved forespørgslens afslutning frigiver PHP denne hukommelse. PHP Internals Book opsummerer det kort: PHP glemmer forespørgselshukommelsen ved afslutningen af hver forespørgsel.

Faserne i PHP request lifecycle i overblik

Navnene stammer fra PHP's indre; hver udvidelse kan hægte sig ind i disse faser.

Fase Hvornår den kører Hvor ofte Typisk opgave
MINIT (Module Init) ved processens start én gang pr. proces registrere udvidelser, oprette ini-poster, varige data
GINIT ved oprettelsen af globals pr. proces, ved tråde pr. tråd forberede en udvidelses globale variabler
RINIT (Request Init) i begyndelsen af hver forespørgsel pr. forespørgsel forberede forespørgselshukommelse og forespørgselstilstand
Udførelse imellem pr. forespørgsel jeres PHP-kode kører
RSHUTDOWN ved afslutningen af hver forespørgsel pr. forespørgsel frigive forespørgselsressourcer
PRSHUTDOWN efter RSHUTDOWN pr. forespørgsel, sjældent brugt sidste oprydningsarbejder
MSHUTDOWN når processen afsluttes én gang pr. proces frigive varige data

En vigtig sætning fra PHP Internals Book til udvidelsesudviklere: Globals tømmes ikke automatisk efter hver forespørgsel. Hvad der skal være frisk pr. forespørgsel, hører til at nulstille i RINIT. Denne regel viser, hvorfor grænsen mellem to forespørgsler er et sikkerhedskritisk sted.

Ved afslutningen af en forespørgsel er rækkefølgen også fastlagt: Først kører shutdown-funktioner, som I har registreret med register_shutdown_function(), derefter destruktorer, og så tømmes outputbufferen. Først derefter følger RSHUTDOWN.

Hvorfor workers genbruges

På kommandolinjen behandler en proces præcis én forespørgsel og slutter. I webdrift ville det være for langsomt. PHP-FPM, Apache med mod_php, LiteSpeed og FrankenPHP holder derfor workers klar, som betjener mange forespørgsler efter hinanden. MINIT kører så én gang, RINIT og RSHUTDOWN tusindvis af gange. Hvordan FPM styrer sine workers, forklarer PHP-FPM forklaret.

I PHP-FPM fastlægger pm.max_requests, efter hvor mange forespørgsler en worker genstarter. Standarden er 0, altså ubegrænset. Manualen nævner indstillingen som middel mod hukommelseslækager i tredjepartsbiblioteker:

; FPM-pool: genstart workers efter 500 forespørgsler (mod hukommelseslækager)
pm = dynamic
pm.max_children = 20
pm.max_requests = 500

Endnu længere går FrankenPHP's worker-tilstand: Dér starter hele applikationen én gang og bliver i hukommelsen. Applikationstilstand overlever så også på PHP-niveau. Eksemplet viser forskellen:

<?php
function anfrageZaehler(): int
{
    static $zaehler = 0;   // i klassisk FPM-drift igen 0 pr. forespørgsel
    return ++$zaehler;     // i worker-tilstand tæller værdien videre på tværs af forespørgsler
}
echo anfrageZaehler();

I klassisk drift udskriver kaldet altid 1, fordi PHP kasserer forespørgselshukommelsen. I worker-tilstand vokser værdien, så længe workeren lever. FrankenPHP-dokumentationen anbefaler derfor bevidst at nulstille forespørgselsrelateret tilstand mellem forespørgsler.

Hvor CVE-2026-109619 sætter ind

CVE-2026-109619 angår ikke jeres applikationskode, men PHP selv. Ifølge php.net kunne intern tilstand, der hørte til forespørgslen, overleve frigivelsen af sin hukommelse. En senere forespørgsel i den samme worker kunne bruge den, før initialiseringen nulstillede den. I billedet: På skrankebordet blev en seddel liggende, som egentlig allerede var ryddet væk. Udnyttelsesdetaljer offentliggør vi bevidst ikke; vurderingen står under CVE-2026-109619.

php.nets midlertidige foranstaltninger til denne sårbarhed sætter ind ved bekræftede veje, de er ingen fuldstændig beskyttelse:

  1. session.upload_progress.enabled=0 i php.ini, FPM-pool eller serverkonfiguration, derefter genstart alle workers; ikke via ini_set() eller .user.ini.
  2. På PHP 8.5 desuden fatal_error_backtraces=0 og genstart.
  3. Fjern ugyldige eller forældede indstillinger pr. forespørgsel, som frembringer meddelelser før initialiseringen. Blot at skjule meddelelserne hjælper ifølge php.net ikke.
  4. Ret fatale fejl og tidsoverskridelser i applikationen, som kan udløses udefra, også i callbacks, upload- og importbehandling.

Den egentlige afhjælpning er opdateringen til PHP 8.5.12, 8.4.27, 8.3.36 eller 8.2.35. Fordi fejlen sidder i den kørende worker, virker den først efter en genstart af alle processer; trinene står under Genstart PHP-FPM og alle workers.

Tip

Kontrollér efter genstarten med ps -eo pid,lstart,cmd | grep php, om alle PHP-processer er startet efter opdateringstidspunktet.

Hvad livscyklussen betyder for drift og udvikling

Af modellen kan der udledes klare regler. For administratorer: En opdatering er først virksom, når ingen proces med gammel kode kører mere. Enhver driftsform med langlivede workers har brug for en dokumenteret genstart. For udviklere: Kode, der kører i worker-tilstande, må ikke lade forespørgselsrelateret tilstand ligge i statiske variabler eller singletons, f.eks. brugerdata eller rettigheder. For begge gælder: Opbevar logs fra 20.10.2026 for senere at kunne vurdere, om der skete noget før patchen.

Hvordan hjælper PHP SOS konkret?

Med PHP-patchservicen gennemfører vi modellen i praksis:

  • Bestemme driftsformen: Vi afgør, om PHP-FPM, mod_php, LiteSpeed, FrankenPHP eller php-cgi kører, og hvordan workers administreres.
  • Opdatering og genstart: Vi indspiller den rettede version og genstarter hver worker kontrolleret.
  • Proceskontrol: Vi dokumenterer ud fra starttidspunkter og versioner, at ingen gammel proces er tilbage.
  • Kontrollere worker-tilstande: Ved langlivede applikationer ser vi på, om forespørgselsrelateret tilstand nulstilles korrekt.

Ofte stillede spørgsmål

Starter PHP en ny proces til hver forespørgsel?

På kommandolinjen ja, i webdrift som regel ikke. PHP-FPM, Apache med mod_php, LiteSpeed eller FrankenPHP lader en proces behandle mange forespørgsler efter hinanden. Mellem forespørgslerne rydder PHP forespørgselstilstanden op.

Hvad er forskellen på MINIT og RINIT?

MINIT kører én gang, når PHP-processen starter, og opretter varige strukturer. RINIT kører i begyndelsen af hver enkelt forespørgsel og forbereder det, som kun denne forespørgsel har brug for.

Hjælper pm.max_requests mod CVE-2026-109619?

php.net nævner hyppigere worker-genstarter som midlertidig foranstaltning ikke. Indstillingen begrænser kun, hvor mange forespørgsler en worker behandler, før den genstarter. Mod sårbarheden hjælper opdateringen med efterfølgende genstart af alle workers.

Hvad er FrankenPHP's worker-tilstand?

I worker-tilstand starter applikationen én gang og bliver i hukommelsen. Det sparer tid, men statiske variabler, globals og caches bevares mellem forespørgsler. Ifølge FrankenPHP-dokumentationen skal forespørgselsrelateret tilstand derfor nulstilles bevidst.

Kilder

Akut kontakt

Hver time tæller. Skriv til os nu.

Beskriv kort system, PHP-version og observation. Vi vender tilbage, afklarer situationen og arbejder på afstand, indtil hændelsen er afsluttet og dokumenteret.

Akut hjælp