# La Zend Engine: il cuore di PHP

> La Zend Engine spiegata: compilatore, opcode, macchina virtuale, zval e gestione della memoria nel nucleo di PHP, le sue versioni e il peso per le patch.

Fonte: https://phpsos.de/it/php/zend-engine/  
Stato: 25/10/2026  
Fornitore: PHP SOS, Assistenza di emergenza PHP e sicurezza dei server. Assistenza immediata su WhatsApp: https://wa.me/491736494914?text=Buongiorno%20PHP%20SOS%2C%20abbiamo%20bisogno%20di%20aiuto%20con%20il%20nostro%20server%20PHP.%20Azienda%3A%20%E2%80%A6%20Sito%20web%3A%20%E2%80%A6

**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:

1. **Lexer:** scompone il codice sorgente in token, ad esempio parole chiave, nomi di variabile e stringhe.
2. **Parser:** costruisce dai token un albero sintattico astratto (AST) che rappresenta la struttura del programma.
3. **Compilatore:** genera dall'AST gli op array, cioè elenchi di opcode, uno per file e funzione.
4. **Executor (Zend VM):** elabora gli opcode. Secondo la RFC sul JIT, a ogni opcode corrisponde una funzione handler che lo esegue.
5. **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
<?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
<?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](https://phpsos.de/it/php/speicherverwaltung/).

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](https://phpsos.de/it/php/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.

> **Importante:**
> 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](https://phpsos.de/it/php/out-of-memory/). La classificazione della vulnerabilità vera e propria è in [CVE-2026-109618](https://phpsos.de/it/php2shell/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](https://phpsos.de/it/leistungen/php-patch-service/) 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.

## Fonti

- [Manuale PHP: storia di PHP](https://www.php.net/manual/en/history.php.php)
- [PHP RFC: PHPNG](https://wiki.php.net/rfc/phpng)
- [PHP RFC: JIT](https://wiki.php.net/rfc/jit)
- [Manuale PHP: conteggio dei riferimenti](https://www.php.net/manual/en/features.gc.refcounting-basics.php)
- [Manuale PHP: impostazioni del core (memory_limit)](https://www.php.net/manual/en/ini.core.php)
