Lyhyesti: Zend Engine on PHP:n ydin. Se kääntää PHP-koodin opcode-käskyiksi, suorittaa ne virtuaalikoneessa ja hallinnoi samalla muuttujia ja muistia. PHP 4:stä lähtien se on ollut jokaisessa PHP-asennuksessa. Koska PHP2Shell-haavoittuvuudet ovat tässä ytimessä, lisäosat tai CMS-päivitykset eivät auta, vaan ainoastaan päivitetty PHP ja uudelleenkäynnistys.
Mikä Zend Engine on?
Zend Engine on se PHP:n osa, joka tekee varsinaisen työn. Kaikki muu, esimerkiksi yhteys verkkopalvelimeen tai tietokantalaajennukset, rakentuu sen päälle. Sitä voi verrata auton moottoriin: korit ja varusteet vaihtelevat, mutta moottori pyörittää kaikkea.
PHP-käsikirjan mukaan nimi on muodostettu kehittäjien Zeev Suraskin ja Andi Gutmansin etunimistä. Moottori esiteltiin vuoden 1999 puolivälissä, ja se oli PHP:n ydin PHP 4.0:sta lähtien, joka ilmestyi toukokuussa 2000. Sen jälkeen sitä on uudistettu perusteellisesti useita kertoja.
| PHP-versio | Moottori | Tärkein muutos käsikirjan ja RFC:iden mukaan |
|---|---|---|
| PHP 4.0 (2000) | Zend Engine | ensimmäinen yhteinen ydin, parempi suorituskyky |
| PHP 5.0 (2004) | Zend Engine 2.0 | uusi olimalli |
| PHP 7.0 (2015) | Zend Engine 3.0 | PHPNG: tiiviimmät tietorakenteet, AST |
| PHP 8.0 (2020) | jatkokehitys | JIT-kääntäjä osana OPcachea |
Osat: kääntäjä, virtuaalikone, muisti
Moottori työskentelee selvästi erotettujen vaiheiden kautta. PHP 7:stä lähtien abstraktia syntaksipuuta koskevan RFC:n mukaan tavukoodiin on kolme vaihetta:
- Lexer: pilkkoo lähdekoodin tokeneiksi, esimerkiksi avainsanoiksi, muuttujien nimiksi ja merkkijonoiksi.
- Parser: rakentaa tokeneista abstraktin syntaksipuun (AST), joka kuvaa ohjelman rakenteen.
- Kääntäjä: tuottaa AST:stä op-taulukoita eli opcode-luetteloita, yhden kutakin tiedostoa ja funktiota kohden.
- Suorittaja (Zend VM): käy opcodet läpi. JIT-RFC:n mukaan jokaiseen opcodeen kuuluu käsittelijäfunktio, joka suorittaa sen.
- Muistinhallinta: varaa ja vapauttaa muistia jokaiselle pyynnölle ja valvoo samalla
memory_limit-asetuksen rajaa.
Komentosarjan tokenit voi tehdä näkyviksi Tokenizer-laajennuksella. Se on harmitonta ja opettavaista:
<?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";
}
}
Tuloste näyttää rivejä kuten T_VARIABLE: $summe tai T_LNUMBER: 2. Juuri näillä rakennuspalikoilla jäsennin jatkaa työtä.
Miten Zend Engine hallinnoi muuttujia?
Käsikirjan mukaan jokainen PHP-muuttuja on säiliössä nimeltä zval. Se sisältää tyypin ja arvon sekä hallintatietoja, muun muassa viitelaskurin (refcount). Laskuri kertoo, kuinka moni muuttujan nimi osoittaa samaan säiliöön.
<?php
$a = str_repeat('x', 10);
$b = $a; // ei kopiointia, molemmat osoittavat samaan arvoon
$b .= 'y'; // vasta nyt kopioidaan (copy on write)
unset($a); // laskuri pienenee, muisti vapautuu, kun se saavuttaa arvon 0
Kun laskuri saavuttaa nollan, moottori vapauttaa muistin. Olioiden välisiä kehäviittauksia varten on lisäksi roskienkerääjä (garbage collector). Lisää artikkelissa Muistinhallinta PHP:ssä.
PHP 7:n PHPNG-uudistus iski juuri tähän. Dmitry Stogovin ja Zeev Suraskin RFC:n mukaan tavoitteena olivat tiiviimmät tietorakenteet ja älykkäämpi arvojen esitys. RFC mainitsi 20–110 prosentin suorituskykyhyödyt todellisissa sovelluksissa.
OPcache ja JIT: moottorin laajennukset
Ilman välimuistia moottori kääntää jokaisen komentosarjan uudelleen jokaisella pyynnöllä. OPcache pitää valmiit opcodet valmiina jaetussa muistissa. PHP 8.0:sta lähtien mukana on lisäksi JIT-kääntäjä. RFC:n mukaan se perustuu DynASM:iin, LuaJIT-projektin työkaluun, ja tuottaa konekoodia suoraan tavukoodista. Virtuaalikone pysyy samana; JIT korvaa vain käsittelijöiden sisääntulopisteet.
Ylläpitäjälle tämä tarkoittaa: OPcache ja JIT nopeuttavat moottoria, mutta eivät muuta sen käyttäytymistä virhetilanteissa. Ytimen haavoittuvuus säilyy myös aktiivisella välimuistilla.
Miksi moottorin haavoittuvuudet painavat erityisen paljon
Kumpikin PHP2Shell-haavoittuvuus on PHP:n ytimessä. Haavoittuvuudessa CVE-2026-109618 Out-of-Memory-tila voi keskeyttää moottorin, kun pyyntötiedot on alustettu vasta osittain; siivouksessa virheellisiä tietoja käsitellään sitten kelvollisina. Haavoittuvuudessa CVE-2026-109619 sisäinen tila säilyy muistin vapauttamisen jälkeen, ja myöhempi pyyntö samassa worker-prosessissa voi käyttää sitä.
Korjatut versiot 8.5.12, 8.4.27, 8.3.36 ja 8.2.35 muuttavat PHP-käsikirjan mukaan myös muistirajan käyttäytymistä: memory_limit on niissä pehmeä raja, ja uusi asetus memory_hard_limit_percent määrittää kovan ylärajan. Käsikirja huomauttaa, että versio, joka ei tunne tätä asetusta, on haavoittuvuuksien piirissä. Backportteja käyttävissä jakeluissa ratkaisevaa on lisäksi paketin muutosloki.
Moottori on ladattuna jokaisessa PHP-prosessissa. Päivityksen jälkeen kaikki PHP-FPM-workerit, mod_php:tä käyttävät Apache-prosessit ja muut PHP-palvelut on siksi käynnistettävä uudelleen.
Mitä sisäisesti tapahtuu muistin loppuessa, kuvaa artikkeli memory_limit ja Out-of-Memory. Itse haavoittuvuuden arviointi on sivulla CVE-2026-109618.
Miten PHP SOS auttaa konkreettisesti?
- Version ja pakettitilan tarkistus: Selvitämme, mikä moottorin versio todella on käynnissä, jakelunne backportit mukaan lukien.
- Päivitys ja uudelleenkäynnistys: PHP-päivityspalvelun kautta asennamme päivityksen ja varmistamme, ettei yksikään prosessi jää käyntiin vanhalla koodilla.
- Muistirajojen järkevä asetus: Sovitamme
memory_limit-asetuksen, uuden kovan rajan ja cgroup-rajat sovellukseenne. - Poikkeamien selvitys: Worker-prosessien kaatumiset tai prosessit, joiden poistumistila on 137, arvioimme ja tarkistamme, voiko niiden takana olla hyökkäys.
Usein kysytyt kysymykset
Mistä Zend Engine on saanut nimensä?
Nimi muodostuu kehittäjien etunimistä: Zeev Suraski ja Andi Gutmans. Moottori esiteltiin PHP-käsikirjan mukaan vuoden 1999 puolivälissä, ja se oli PHP:n ydin PHP 4.0:sta lähtien toukokuusta 2000.
Onko Zend Engine erillinen tuote, joka minun on asennettava?
Ei. Zend Engine on kiinteä osa jokaista PHP-asennusta. Kun PHP päivitetään, myös moottori päivittyy automaattisesti. Tällä ei ole mitään tekemistä Zend-yhtiön kaupallisten tuotteiden kanssa.
Mikä on opcode?
Opcode on yksittäinen käsky PHP:n virtuaalikoneelle, esimerkiksi yhteenlasku, funktiokutsu tai sijoitus. Kääntäjä muuntaa jokaisen komentosarjan tällaisten käskyjen jonoksi, jonka moottori sitten suorittaa.
Mitä tekemistä Zend Enginellä on memory_limit-asetuksen kanssa?
Moottori hallinnoi jokaisen pyynnön muistia ja valvoo samalla memory_limit-asetuksen rajaa. Käsikirjan mukaan 21.10.2026 julkaistuista tietoturvajulkaisuista alkaen tämä raja on pehmeä raja, jota täydentää kova raja asetuksella memory_hard_limit_percent.