Ukratko: Kada preglednik zatraži PHP stranicu, web-poslužitelj prima zahtjev i prosljeđuje ga PHP-u putem sučelja (SAPI). PHP skriptu prevodi u bytecode, izvršava ga u Zend Engineu i rezultat, najčešće HTML, vraća web-poslužitelju. Nakon toga se stanje zahtjeva čisti kako bi sljedeći počeo čist.
Što se događa kada netko otvori Vašu web-stranicu?
Za posjetitelje je to jedan klik. Na poslužitelju se u milisekundama odvija mnogo koraka. Tko poznaje taj slijed, bolje razumije zašto su ažuriranja, ponovna pokretanja i konfiguracija toliko važni i zašto ranjivost u samom PHP-u teže pogađa nego ranjivost u dodatku.
PHP priručnik navodi tri sastavnice potrebne za PHP web-stranicu: PHP interpreter (kao CGI ili modul poslužitelja), web-poslužitelj i preglednik. Interpreter je program koji čita i izvršava PHP kod. Kako je povezan s web-poslužiteljem, određuje način rada.
Kako radi PHP? Sedam koraka jednog zahtjeva
- Zahtjev: Preglednik poslužitelju šalje HTTP zahtjev, na primjer
GET /kontakt.php. - Web-poslužitelj: Apache, Nginx ili LiteSpeed primaju zahtjev. Statične datoteke poput slika isporučuju sami. Za
.phpdatoteke pozivaju PHP. - Predaja putem SAPI-ja: Sučelje poslužitelja (SAPI) predaje PHP-u podatke zahtjeva poput zaglavlja, parametara i podataka obrasca. Kod PHP-FPM-a to ide putem FastCGI protokola, kod mod_php-a izravno u Apacheovu procesu. Pojedinosti u članku SAPI objašnjen.
- Priprema zahtjeva: PHP podatke zahtjeva sprema u varijable poput
$_GET,$_POST,$_COOKIEi$_FILESte rezervira memoriju za zahtjev. - Prevođenje: Skripta se rastavlja na gradivne dijelove (tokene), iz njih nastaje apstraktno sintaktičko stablo (AST), a iz njega opcodeovi, svojevrsni strojni jezik za PHP. Ako je OPcache aktivan, ovaj se korak preskače kada se skripta već nalazi u predmemoriji.
- Izvršavanje: Virtualni stroj Zend Enginea obrađuje opcodeove, upućuje upite bazama podataka, čita datoteke i stvara izlaz.
- Odgovor i čišćenje: Izlaz putem SAPI-ja ide natrag web-poslužitelju, a odande pregledniku. Zatim PHP oslobađa memoriju zahtjeva i vraća stanje na početno.
AST postoji od PHP-a 7. Prema pripadajućem RFC-u parser je prije toga opcodeove stvarao izravno tijekom čitanja; podjela na tri faze učinila je kompilator lakšim za održavanje.
Primjer: što skripta vidi od zahtjeva
Sljedeća bezopasna skripta pokazuje koje podatke PHP dobiva iz zahtjeva i u kojem načinu rada radi:
<?php
header('Content-Type: text/plain; charset=utf-8');
echo 'Betriebsart (SAPI): ' . PHP_SAPI . "\n";
echo 'PHP-Version: ' . PHP_VERSION . "\n";
echo 'Methode: ' . ($_SERVER['REQUEST_METHOD'] ?? '-') . "\n";
echo 'Speicher in dieser Anfrage: ' . memory_get_usage() . " Bytes\n";
Na poslužitelju s PHP-FPM-om PHP_SAPI ispisuje vrijednost fpm-fcgi, a pod Apacheom s mod_php-om apache2handler. Takve probne datoteke ostavljajte u javnom direktoriju samo kratko i nikad trajno, jer podaci o verziji pomažu i napadačima pri orijentaciji.
Gdje u igru ulaze predmemorija bytecodea i JIT
Prevođenje u koraku 5 troši vrijeme. OPcache prema priručniku pohranjuje unaprijed kompilirani bytecode u zajedničku memoriju i tako PHP-u štedi učitavanje i rastavljanje skripti pri svakom zahtjevu. Od PHP-a 8.0 dodatno JIT kompilator iz opcodeova može stvoriti pravi strojni kod. Prema JIT RFC-u gotovo je samostalan dio OPcachea.
| Faza | Rezultat | Sprema li se u predmemoriju? |
|---|---|---|
| Leksička analiza | niz tokena | ne |
| Parsiranje | apstraktno sintaktičko stablo (AST) | ne |
| Kompiliranje | opcodeovi (op-nizovi po datoteci i funkciji) | da, u OPcacheu |
| JIT (neobavezno) | strojni kod | da, u memoriji OPcachea |
| Izvršavanje | izlaz stranice | ne |
Predmemorija se odnosi samo na prevedeni kod. Podaci pojedinog zahtjeva, na primjer unosi u obrascu ili vrijednosti sesije, ne dijele se putem OPcachea.
Zašto PHP2Shell napada upravo u tom slijedu
Obje PHP2Shell ranjivosti ne pogađaju jednu aplikaciju, nego sam slijed. Kod CVE-2026-109618 stanje nedostatka memorije može prekinuti PHP dok su podaci zahtjeva tek djelomično pripremljeni, dakle u koraku 4. Pri naknadnom čišćenju nevaljani se podaci tada mogu tretirati kao valjani.
Kod CVE-2026-109619 unutarnje stanje zahtjeva može ostati sačuvano nakon oslobađanja memorije. Kasniji zahtjev u istom workeru može ga iskoristiti prije nego što se vrati na početno stanje. To se odnosi na korak 7, čišćenje. Pozadina je na stranici CVE-2026-109619 i u članku o životnom ciklusu zahtjeva.
Iz toga slijedi: zaštitne mjere u kodu aplikacije, na primjer sigurnosni dodaci, djeluju tek u koraku 6. Kod mod_php-a je prema PHP timu čak pokazan exploit prije nego što se uopće izvrši kod aplikacije. Djelotvorno je samo ažuriranje PHP-a na 8.5.12, 8.4.27, 8.3.36 ili 8.2.35 i ponovno pokretanje svih PHP procesa, jer dugovječni workeri inače nastavljaju izvršavati stari kod.
Kako PHP SOS konkretno pomaže?
- Učiniti slijed vidljivim: Utvrđujemo koji su način rada, konfiguracija i predmemorija na Vašem poslužitelju stvarno aktivni.
- Ispravno ažurirati: Instaliramo PHP ažuriranje i putem vremena pokretanja provjeravamo da više ne radi nijedan stari proces.
- Osigurati slojeve: U okviru ojačavanja poslužitelja ograničavamo veličine zahtjeva, memoriju i prava ondje gdje djeluju: ispred koda aplikacije.
- Provjeriti tragove: Kod nezaštićeno dostupnih poslužitelja tražimo znakove provale.
Česta pitanja
Prevodi li se PHP kod iznova pri svakom pozivu?
Bez predmemorije da: PHP rastavlja skriptu, gradi sintaktičko stablo i iz njega stvara opcodeove. S aktivnim OPcacheom opcodeovi se nalaze u zajedničkoj memoriji i ponovno se koriste dok se datoteka ne promijeni.
Što ostaje u memoriji nakon zahtjeva?
U načelu se stanje zahtjeva na kraju čisti kako bi sljedeći zahtjev počeo čist. Dugovječne su samo stvari poput OPcachea ili trajnih veza. Upravo na tom čišćenju napada CVE-2026-109619.
Zašto se PHP mora ponovno pokrenuti nakon ažuriranja?
Kod PHP-FPM-a i mod_php-a procesi rade neprekidno i učitali su stari programski kod. Nove datoteke na disku tu ništa ne mijenjaju. Tek ponovno pokretanje učitava ispravljeni kod.
Je li web-poslužitelj bez PHP-a sigurniji?
Ima manju površinu napada jer nikakva programska logika ne reagira na zahtjeve. Za isključivo statične sadržaje to je prava opcija. Ali za web-trgovine, obrasce i prijave treba jezik na strani poslužitelja, i tada je važno njegovo održavanje.