In breve: la Zend Engine è il nucleo di PHP. Traduce il codice PHP in opcode, li esegue in una macchina virtuale e gestisce nel frattempo variabili e memoria. Da PHP 4 è presente in ogni installazione di PHP. Poiché le vulnerabilità di PHP2Shell si trovano in questo nucleo, non servono plugin né aggiornamenti del CMS: serve solo un PHP aggiornato con riavvio.
Che cos'è la Zend Engine?
La Zend Engine è la parte di PHP che svolge il lavoro vero e proprio. Tutto il resto, come il collegamento al server web o le estensioni per i database, si appoggia su di essa. La si può paragonare al motore di un'auto: carrozzeria e dotazioni differiscono, il motore fa muovere tutto.
Secondo il manuale PHP il nome è formato dai nomi di battesimo degli sviluppatori Zeev Suraski e Andi Gutmans. La engine fu presentata a metà del 1999 e dal rilascio di PHP 4.0, nel maggio 2000, è il nucleo di PHP. Da allora è stata più volte rivista in modo sostanziale.
| Versione di PHP | Engine | Modifica principale secondo manuale e RFC |
|---|---|---|
| PHP 4.0 (2000) | Zend Engine | primo nucleo comune, prestazioni migliori |
| PHP 5.0 (2004) | Zend Engine 2.0 | nuovo modello a oggetti |
| PHP 7.0 (2015) | Zend Engine 3.0 | PHPNG: strutture dati più compatte, AST |
| PHP 8.0 (2020) | evoluzione | compilatore JIT come parte di OPcache |
I componenti: compilatore, macchina virtuale, memoria
La engine lavora in stadi nettamente separati. Da PHP 7, secondo la RFC sull'albero sintattico astratto, le fasi fino al bytecode sono tre:
- Lexer: scompone il codice sorgente in token, ad esempio parole chiave, nomi di variabile e stringhe.
- Parser: costruisce dai token un albero sintattico astratto (AST) che rappresenta la struttura del programma.
- Compilatore: genera dall'AST gli op array, cioè elenchi di opcode, uno per file e funzione.
- Executor (Zend VM): elabora gli opcode. Secondo la RFC sul JIT, a ogni opcode corrisponde una funzione handler che lo esegue.
- Gestione della memoria: riserva e libera memoria per ogni richiesta e sorveglia il limite di
memory_limit.
I token di uno script si possono rendere visibili con l'estensione Tokenizer. È innocuo e istruttivo:
<?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";
}
}
L'output mostra voci come T_VARIABLE: $summe o T_LNUMBER: 2. Proprio con questi elementi il parser prosegue il lavoro.
Come gestisce le variabili la Zend Engine?
Secondo il manuale ogni variabile PHP risiede in un contenitore chiamato zval. Contiene tipo e valore e informazioni di gestione, tra cui un contatore di riferimenti (refcount). Il contatore indica quanti nomi di variabile puntano allo stesso contenitore.
<?php
$a = str_repeat('x', 10);
$b = $a; // nessuna copia, entrambe puntano allo stesso valore
$b .= 'y'; // solo ora si copia (copy on write)
unset($a); // il contatore scende, la memoria si libera quando arriva a 0
Quando il contatore arriva a zero, la engine libera la memoria. Per i riferimenti circolari tra oggetti esiste inoltre un garbage collector. Maggiori dettagli nell'articolo Gestione della memoria in PHP.
La revisione PHPNG per PHP 7 puntava proprio qui. Secondo la RFC di Dmitry Stogov e Zeev Suraski si trattava di strutture dati più compatte e di una rappresentazione più intelligente dei valori. La RFC indicava guadagni di prestazioni dal 20 al 110 per cento in applicazioni reali.
OPcache e JIT: estensioni della engine
Senza cache la engine traduce di nuovo ogni script a ogni richiesta. OPcache tiene gli opcode già pronti nella memoria condivisa. Da PHP 8.0 esiste inoltre un compilatore JIT. Secondo la RFC si basa su DynASM, uno strumento del progetto LuaJIT, e genera codice macchina direttamente dal bytecode. La macchina virtuale resta invariata; il JIT sostituisce soltanto i punti di ingresso degli handler.
Per chi gestisce i sistemi significa: OPcache e JIT accelerano la engine, ma non cambiano il suo comportamento in caso di errori. Una vulnerabilità nel nucleo resta anche con la cache attiva.
Perché le vulnerabilità nella engine pesano in modo particolare
Le due vulnerabilità di PHP2Shell si trovano nel nucleo di PHP. Con CVE-2026-109618 una condizione di memoria esaurita (out-of-memory) può interrompere la engine mentre i dati della richiesta sono inizializzati solo in parte; nella pulizia i dati non validi vengono poi trattati come validi. Con CVE-2026-109619 lo stato interno rimane dopo la liberazione della memoria e può essere usato da una richiesta successiva nello stesso worker.
Le versioni corrette 8.5.12, 8.4.27, 8.3.36 e 8.2.35 modificano, secondo il manuale PHP, anche il comportamento del limite di memoria: lì memory_limit è un limite morbido, mentre una nuova impostazione memory_hard_limit_percent fissa un tetto rigido. Il manuale avverte che una versione che non conosce questa impostazione è interessata dalle vulnerabilità. Per le distribuzioni con backport conta inoltre il changelog del pacchetto.
La engine è caricata in ogni processo PHP. Dopo l'aggiornamento vanno quindi riavviati tutti i worker PHP-FPM, i processi Apache con mod_php e gli altri servizi PHP.
Che cosa accade all'interno in caso di carenza di memoria lo descrive l'articolo memory_limit e out-of-memory. La classificazione della vulnerabilità vera e propria è in CVE-2026-109618.
Come aiuta concretamente PHP SOS?
- Verificare versione e stato dei pacchetti: accertiamo quale stato della engine giri davvero, inclusi i backport della Sua distribuzione.
- Aggiornare e riavviare: tramite il servizio di patch PHP installiamo l'aggiornamento e controlliamo che non resti alcun processo con il vecchio codice.
- Impostare in modo sensato i limiti di memoria: adattiamo
memory_limit, il nuovo limite rigido e i limiti dei cgroup alla Sua applicazione. - Esaminare le anomalie: classifichiamo i crash dei worker o i processi con stato di uscita 137 e verifichiamo se dietro possa esserci un attacco.
Domande frequenti
Da dove viene il nome Zend Engine?
Il nome è formato dai nomi di battesimo dei suoi sviluppatori: Zeev Suraski e Andi Gutmans. Secondo il manuale PHP la engine fu presentata a metà del 1999 e dal rilascio di PHP 4.0, nel maggio 2000, è il nucleo di PHP.
La Zend Engine è un prodotto a parte che devo installare?
No. La Zend Engine è parte integrante di ogni installazione di PHP. Chi aggiorna PHP aggiorna automaticamente anche la engine. Non ha nulla a che fare con i prodotti commerciali dell'azienda Zend.
Che cos'è un opcode?
Un opcode è una singola istruzione per la macchina virtuale di PHP, ad esempio una somma, una chiamata di funzione o un'assegnazione. Il compilatore traduce ogni script in una sequenza di tali istruzioni, che la engine poi elabora.
Che cosa c'entra la Zend Engine con memory_limit?
La engine gestisce la memoria di ogni richiesta e tiene d'occhio il limite di memory_limit. Dalle release di sicurezza del 21/10/2026 questo limite è, secondo il manuale, un limite morbido, integrato da un limite rigido tramite memory_hard_limit_percent.