Īsi: Zend Engine ir PHP kodols. Tā pārvērš PHP kodu opcodes, izpilda tos virtuālajā mašīnā un pārvalda mainīgos un atmiņu. Kopš PHP 4 tā ir katrā PHP instalācijā. Tā kā PHP2Shell ievainojamības atrodas šajā kodolā, nepalīdz ne spraudņi, ne CMS atjauninājumi, bet tikai atjaunināts PHP ar pārstartēšanu.
Kas ir Zend Engine?
Zend Engine ir tā PHP daļa, kas veic īsto darbu. Viss pārējais, piemēram, savienojums ar tīmekļa serveri vai paplašinājumi datubāzēm, balstās uz to. To var salīdzināt ar automašīnas dzinēju: virsbūve un aprīkojums atšķiras, dzinējs dzen visu.
Saskaņā ar PHP rokasgrāmatu nosaukums veidots no izstrādātāju Zeev Suraski un Andi Gutmans vārdiem. Dzinējs tika prezentēts 1999. gada vidū, un no PHP 4.0, kas iznāca 2000. gada maijā, tas bija PHP kodols. Kopš tā laika tas vairākkārt ir pamatīgi pārstrādāts.
| PHP versija | Dzinējs | Svarīgākās izmaiņas saskaņā ar rokasgrāmatu un RFC |
|---|---|---|
| PHP 4.0 (2000) | Zend Engine | pirmais kopīgais kodols, labāka veiktspēja |
| PHP 5.0 (2004) | Zend Engine 2.0 | jauns objektu modelis |
| PHP 7.0 (2015) | Zend Engine 3.0 | PHPNG: kompaktākas datu struktūras, AST |
| PHP 8.0 (2020) | Tālāka attīstība | JIT kompilators kā OPcache daļa |
Pamatelementi: kompilators, virtuālā mašīna, atmiņa
Dzinējs darbojas skaidri nodalītos posmos. Kopš PHP 7 saskaņā ar RFC par abstrakto sintakses koku līdz baitkodam ir trīs fāzes:
- Lekseris: sadala pirmkodu tokenos, piemēram, atslēgvārdos, mainīgo nosaukumos un virknēs.
- Parsētājs: no tokeniem izveido abstraktu sintakses koku (AST), kas attēlo programmas struktūru.
- Kompilators: no AST izveido op-masīvus, tas ir, opcodes sarakstus, pa vienam katram failam un funkcijai.
- Izpildītājs (Zend VM): izpilda opcodes. Saskaņā ar JIT RFC katram opcode ir apstrādes funkcija (handler), kas to izpilda.
- Atmiņas pārvaldība: katram pieprasījumam rezervē un atbrīvo atmiņu un seko
memory_limitrobežai.
Skripta tokenus var padarīt redzamus ar paplašinājumu Tokenizer. Tas ir nekaitīgi un pamācoši:
<?php
$code = '<?php $summe = 2 + 3; echo $summe;';
foreach (token_get_all($code) as $token) {
if (is_array($token)) {
echo token_name($token[0]), ': ', trim($token[1]), "\n";
} else {
echo 'Zeichen: ', $token, "\n";
}
}
Izvadē redzami ieraksti, piemēram, T_VARIABLE: $summe vai T_LNUMBER: 2. Tieši ar šiem elementiem parsētājs strādā tālāk.
Kā Zend Engine pārvalda mainīgos?
Katrs PHP mainīgais saskaņā ar rokasgrāmatu atrodas konteinerā, ko sauc par zval. Tajā ir tips un vērtība, kā arī pārvaldības dati, to vidū atsauču skaitītājs (refcount). Skaitītājs norāda, cik mainīgo nosaukumu norāda uz vienu un to pašu konteineru.
<?php
$a = str_repeat('x', 10);
$b = $a; // nekopē, abi norāda uz vienu un to pašu vērtību
$b .= 'y'; // tikai tagad notiek kopēšana (copy on write)
unset($a); // skaitītājs samazinās, atmiņa tiek atbrīvota, kad tas sasniedz 0
Kad skaitītājs sasniedz nulli, dzinējs atmiņu atbrīvo. Apļveida atsaucēm starp objektiem papildus ir atkritumu savācējs (garbage collector). Vairāk par to rakstā Atmiņas pārvaldība PHP.
PHPNG pārstrāde PHP 7 vajadzībām ķērās tieši pie šīs vietas. Saskaņā ar Dmitry Stogov un Zeev Suraski RFC tā bija vērsta uz kompaktākām datu struktūrām un veiklāku vērtību attēlošanu. RFC minēja veiktspējas pieaugumu no 20 līdz 110 procentiem reālās lietojumprogrammās.
OPcache un JIT: dzinēja paplašinājumi
Bez kešatmiņas dzinējs katru skriptu pārveido no jauna katrā pieprasījumā. OPcache gatavos opcodes glabā koplietojamā atmiņā. Kopš PHP 8.0 papildus ir JIT kompilators. Saskaņā ar RFC tas balstās uz DynASM, rīku no LuaJIT projekta, un mašīnkodu veido tieši no baitkoda. Virtuālā mašīna paliek nemainīga; JIT aizstāj tikai apstrādes funkciju ieejas punktus.
Operatoriem tas nozīmē: OPcache un JIT paātrina dzinēju, bet nemaina tā uzvedību kļūdu gadījumā. Ievainojamība kodolā saglabājas arī ar aktīvu kešatmiņu.
Kāpēc ievainojamības dzinējā ir īpaši smagas
Abas PHP2Shell ievainojamības atrodas PHP kodolā. CVE-2026-109618 gadījumā Out-of-Memory stāvoklis var pārtraukt dzinēju brīdī, kad pieprasījuma dati ir inicializēti tikai daļēji; sakopšanas laikā nederīgi dati tad tiek uzskatīti par derīgiem. CVE-2026-109619 gadījumā iekšējais stāvoklis pēc atmiņas atbrīvošanas saglabājas, un to var izmantot vēlāks pieprasījums tajā pašā darbprocesā (worker).
Labotās versijas 8.5.12, 8.4.27, 8.3.36 un 8.2.35 saskaņā ar PHP rokasgrāmatu maina arī atmiņas robežas uzvedību: memory_limit tur ir mīkstā robeža, jauns iestatījums memory_hard_limit_percent nosaka cieto augšējo robežu. Rokasgrāmata norāda, ka versija, kas šo iestatījumu nepazīst, ir ievainojamību skarta. Distributīvos ar backport labojumiem papildus svarīgs ir pakotnes changelog.
Dzinējs ir ielādēts katrā PHP procesā. Pēc atjauninājuma tāpēc jāpārstartē visi PHP-FPM darbprocesi, Apache procesi ar mod_php un citi PHP pakalpojumi.
Kas iekšēji notiek atmiņas trūkuma gadījumā, apraksta raksts memory_limit un Out-of-Memory. Pašas ievainojamības klasifikāciju skatiet lapā CVE-2026-109618.
Kā PHP SOS palīdz konkrēti?
- Pārbaudīt versiju un pakotnes stāvokli: Mēs noskaidrojam, kāds dzinēja stāvoklis patiešām darbojas, ieskaitot jūsu distributīva backport labojumus.
- Atjaunināt un pārstartēt: Ar PHP ielāpošanas pakalpojumu mēs ieviešam atjauninājumu un kontrolējam, ka nepaliek neviens process ar veco kodu.
- Saprātīgi iestatīt atmiņas robežas: Mēs saskaņojam
memory_limit, jauno cieto robežu un cgroup robežas ar jūsu lietojumprogrammu. - Izmeklēt neparastas parādības: Darbprocesu avārijas vai procesus ar izejas statusu 137 mēs klasificējam un pārbaudām, vai aiz tiem var būt uzbrukums.
Biežāk uzdotie jautājumi
No kurienes Zend Engine ir ieguvusi savu nosaukumu?
Nosaukums veidots no tās izstrādātāju vārdiem: Zeev Suraski un Andi Gutmans. Saskaņā ar PHP rokasgrāmatu dzinējs tika prezentēts 1999. gada vidū, un no PHP 4.0 2000. gada maijā tas bija PHP kodols.
Vai Zend Engine ir atsevišķs produkts, kas man jāinstalē?
Nē. Zend Engine ir katras PHP instalācijas nemainīga daļa. Kas atjaunina PHP, automātiski atjaunina arī dzinēju. Ar uzņēmuma Zend komerciālajiem produktiem tam nav nekāda sakara.
Kas ir opcode?
Opcode ir atsevišķa komanda PHP virtuālajai mašīnai, piemēram, saskaitīšana, funkcijas izsaukums vai piešķiršana. Kompilators katru skriptu pārveido par šādu komandu virkni, ko dzinējs pēc tam izpilda.
Kāds sakars Zend Engine ir ar memory_limit?
Dzinējs pārvalda katra pieprasījuma atmiņu un ņem vērā memory_limit robežu. Kopš drošības izlaidumiem 2026. gada 21. oktobrī saskaņā ar rokasgrāmatu šī robeža ir mīkstā robeža, ko papildina cietā robeža ar memory_hard_limit_percent.