Actuele situatie: PHP2Shell. Twee kritieke PHP-kwetsbaarheden (CVSS 9.2) maken schadelijke code zonder inloggen mogelijk. Patches sinds 21-10-2026.Wat u nu moet doen →

De Zend Engine: het hart van PHP

De Zend Engine vertaalt PHP-code naar opcodes en voert die uit. Wie de bouwstenen kent, begrijpt waarom lekken in de kern zoals PHP2Shell alleen met een PHP-update verholpen worden.

Stand 5 min. leestijdPHP-kennis

Kort gezegd: De Zend Engine is de kern van PHP. Ze vertaalt PHP-code naar opcodes, voert die uit in een virtuele machine en beheert daarbij variabelen en geheugen. Sinds PHP 4 zit ze in elke PHP-installatie. Omdat de PHP2Shell-lekken in deze kern zitten, helpen geen plug-ins of CMS-updates, maar alleen een bijgewerkte PHP met herstart.

Wat is de Zend Engine?

De Zend Engine is het onderdeel van PHP dat het eigenlijke werk doet. Al het andere, zoals de koppeling met de webserver of extensies voor databases, bouwt erop voort. Je kunt haar vergelijken met de motor van een auto: carrosserie en uitrusting verschillen, de motor drijft alles aan.

Volgens de PHP-handleiding is de naam gevormd uit de voornamen van de ontwikkelaars Zeev Suraski en Andi Gutmans. De engine werd medio 1999 gepresenteerd en was vanaf PHP 4.0, verschenen in mei 2000, de kern van PHP. Sindsdien is ze meermaals fundamenteel herzien.

PHP-versie Engine Belangrijkste wijziging volgens handleiding en RFC's
PHP 4.0 (2000) Zend Engine eerste gezamenlijke kern, betere prestaties
PHP 5.0 (2004) Zend Engine 2.0 nieuw objectmodel
PHP 7.0 (2015) Zend Engine 3.0 PHPNG: compactere datastructuren, AST
PHP 8.0 (2020) doorontwikkeling JIT-compiler als onderdeel van OPcache

De bouwstenen: compiler, virtuele machine, geheugen

De engine werkt in duidelijk gescheiden fasen. Sinds PHP 7 zijn het volgens de RFC over de abstracte syntaxisboom drie fasen tot de bytecode:

  1. Lexer: ontleedt de broncode in tokens, bijvoorbeeld sleutelwoorden, variabelenamen en tekenreeksen.
  2. Parser: bouwt uit de tokens een abstracte syntaxisboom (AST), die de structuur van het programma weergeeft.
  3. Compiler: maakt uit de AST op-arrays, dus lijsten van opcodes, één per bestand en functie.
  4. Executor (Zend VM): werkt de opcodes af. Volgens de JIT-RFC hoort bij elke opcode een handlerfunctie die hem uitvoert.
  5. Geheugenbeheer: reserveert en geeft geheugen vrij voor elk verzoek en bewaakt daarbij de grens uit memory_limit.

De tokens van een script kunnen met de extensie Tokenizer zichtbaar worden gemaakt. Dat is onschuldig en leerzaam:

<?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";
    }
}

De uitvoer toont vermeldingen als T_VARIABLE: $summe of T_LNUMBER: 2. Met precies deze bouwstenen werkt de parser verder.

Hoe beheert de Zend Engine variabelen?

Elke PHP-variabele ligt volgens de handleiding in een container met de naam zval. Die bevat type en waarde en beheergegevens, waaronder een referentieteller (refcount). De teller geeft aan hoeveel variabelenamen naar dezelfde container wijzen.

<?php
$a = str_repeat('x', 10);
$b = $a;        // niet kopiëren, beide wijzen naar dezelfde waarde
$b .= 'y';      // pas nu wordt gekopieerd (copy on write)
unset($a);      // teller daalt, geheugen komt vrij als hij 0 bereikt

Bereikt de teller nul, dan geeft de engine het geheugen vrij. Voor kringverwijzingen tussen objecten bestaat bovendien een garbage collector. Meer daarover in het artikel Geheugenbeheer in PHP.

De herziening PHPNG voor PHP 7 zette precies hier in. Volgens de RFC van Dmitry Stogov en Zeev Suraski ging het om compactere datastructuren en een slimmere weergave van waarden. De RFC noemde prestatiewinsten van 20 tot 110 procent in echte toepassingen.

OPcache en JIT: uitbreidingen van de engine

Zonder cache vertaalt de engine elk script bij elk verzoek opnieuw. De OPcache houdt de kant-en-klare opcodes in het gedeelde geheugen klaar. Sinds PHP 8.0 is er bovendien een JIT-compiler. Volgens de RFC is die gebaseerd op DynASM, een hulpmiddel uit het LuaJIT-project, en maakt hij machinecode rechtstreeks uit de bytecode. De virtuele machine blijft daarbij ongewijzigd; de JIT vervangt alleen de instappunten van de handlers.

Voor beheerders betekent dat: OPcache en JIT versnellen de engine, maar veranderen niets aan haar gedrag bij fouten. Een lek in de kern blijft ook met een actieve cache bestaan.

Waarom lekken in de engine bijzonder zwaar wegen

De twee PHP2Shell-lekken zitten in de kern van PHP. Bij CVE-2026-109618 kan een out-of-memory-toestand de engine onderbreken terwijl verzoekgegevens pas gedeeltelijk zijn geïnitialiseerd; bij het opruimen worden ongeldige gegevens dan als geldig behandeld. Bij CVE-2026-109619 blijft de interne toestand na het vrijgeven van het geheugen bestaan en kan die door een later verzoek in dezelfde worker worden gebruikt.

De verholpen versies 8.5.12, 8.4.27, 8.3.36 en 8.2.35 wijzigen volgens de PHP-handleiding ook het gedrag van de geheugengrens: memory_limit is daar een zachte grens, een nieuwe instelling memory_hard_limit_percent legt een harde bovengrens vast. De handleiding wijst erop dat een versie die deze instelling niet kent, door de lekken is getroffen. Bij distributies met backports telt bovendien de changelog van het pakket.

Belangrijk

De engine is in elk PHP-proces geladen. Na de update moeten daarom alle PHP-FPM-workers, Apache-processen met mod_php en overige PHP-diensten opnieuw worden gestart.

Wat er van binnen gebeurt bij een geheugentekort, beschrijft het artikel memory_limit en out-of-memory. De duiding van het lek zelf staat onder CVE-2026-109618.

Hoe helpt PHP SOS concreet?

  • Versie en pakketstand controleren: Wij stellen vast welke engine-stand daadwerkelijk draait, inclusief backports van uw distributie.
  • Bijwerken en herstarten: Via de PHP-patchservice installeren wij de update en controleren dat er geen proces met oude code overblijft.
  • Geheugengrenzen zinvol instellen: Wij stemmen memory_limit, de nieuwe harde grens en cgroup-grenzen af op uw toepassing.
  • Opvallende zaken onderzoeken: Crashes van workers of processen met exitstatus 137 beoordelen wij en we controleren of er een aanval achter kan zitten.

Veelgestelde vragen

Waar komt de naam Zend Engine vandaan?

De naam is samengesteld uit de voornamen van de ontwikkelaars: Zeev Suraski en Andi Gutmans. De engine werd volgens de PHP-handleiding medio 1999 gepresenteerd en was vanaf PHP 4.0 in mei 2000 de kern van PHP.

Is de Zend Engine een apart product dat ik moet installeren?

Nee. De Zend Engine is vast onderdeel van elke PHP-installatie. Wie PHP bijwerkt, werkt automatisch ook de engine bij. Met commerciële producten van het bedrijf Zend heeft dat niets te maken.

Wat is een opcode?

Een opcode is één enkele opdracht voor de virtuele machine van PHP, bijvoorbeeld een optelling, een functieaanroep of een toewijzing. De compiler vertaalt elk script naar een reeks van zulke opdrachten, die de engine vervolgens afwerkt.

Wat heeft de Zend Engine met memory_limit te maken?

De engine beheert het geheugen van elk verzoek en let daarbij op de grens uit memory_limit. Sinds de beveiligingsreleases van 21-10-2026 is deze grens volgens de handleiding een zachte grens, aangevuld met een harde grens via memory_hard_limit_percent.

Bronnen

Direct contact

Elk uur telt. Schrijf ons nu.

Beschrijf kort het systeem, de PHP-versie en wat u opmerkt. Wij nemen contact op, brengen de situatie in kaart en werken op afstand tot het incident is afgerond en gedocumenteerd.

Directe hulp