# OPcache spiegata: la cache di bytecode di PHP

> OPcache spiegata: come lavora la cache di bytecode di PHP, quali impostazioni contano, perché va svuotata dopo gli aggiornamenti e come metterla in sicurezza.

Fonte: https://phpsos.de/it/php/opcache/  
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:** OPcache è la cache di bytecode integrata di PHP. Secondo il manuale memorizza nella memoria condivisa bytecode già compilato, così PHP non deve caricare e tradurre gli script a ogni richiesta. Fa parte della dotazione di serie dalla versione PHP 5.5.0. OPcache rende PHP più veloce, ma non sostituisce un aggiornamento: dopo una patch di PHP tutti i processi PHP devono riavviarsi, non basta svuotare la cache.

## Che cosa fa esattamente OPcache?

A ogni richiesta PHP deve leggere uno script, scomporlo e tradurlo in opcode, cioè nelle istruzioni per la macchina virtuale della [Zend Engine](https://phpsos.de/it/php/zend-engine/). In un CMS con centinaia di file è molto lavoro, che si ripete di continuo.

OPcache memorizza il risultato di questa traduzione nella memoria condivisa (shared memory). Vi accedono tutti i worker di un servizio PHP-FPM o tutti i processi Apache con mod_php. Se un file non cambia, il suo bytecode viene riutilizzato direttamente.

OPcache viene caricata come estensione Zend, non come estensione normale:

```ini
; Linux (percorso a seconda del pacchetto)
zend_extension=opcache.so
; Windows
; zend_extension=php_opcache.dll
```

Secondo il manuale OPcache dovrebbe essere caricata prima di Xdebug, se entrambi sono attivi.

È importante sapere a chi appartiene la memoria condivisa. Con PHP-FPM la crea il processo master e la usano tutti i worker di tutti i pool di quel servizio. Con mod_php appartiene al processo principale di Apache. Un riavvio del servizio svuota quindi completamente la cache, un singolo nuovo worker invece no. Da riga di comando non esiste memoria condivisa tra una chiamata e l'altra, perché ogni chiamata è un processo a sé; lì OPcache è disattivata per impostazione predefinita.

Per chi decide basta una regola pratica: OPcache è quasi sempre sensata sui server di produzione, ma richiede una procedura chiara per deployment e aggiornamenti.

## Quali impostazioni di OPcache contano?

I valori seguenti provengono dalla pagina di configurazione del manuale PHP. La colonna «Modificabile» mostra dove si può impostare un parametro: `INI_SYSTEM` solo in php.ini o nella configurazione del server, `INI_ALL` ovunque.

| Direttiva | Predefinito | Modificabile | Significato |
|---|---|---|---|
| `opcache.enable` | 1 | INI_ALL | cache attiva o disattiva, a runtime si può solo disattivare |
| `opcache.enable_cli` | 0 | INI_SYSTEM | cache per la riga di comando |
| `opcache.memory_consumption` | 128 | INI_SYSTEM | dimensione della memoria condivisa in MB |
| `opcache.interned_strings_buffer` | 8 | INI_SYSTEM | memoria per le stringhe condivise in MB |
| `opcache.max_accelerated_files` | 10000 | INI_SYSTEM | numero massimo di script in cache |
| `opcache.validate_timestamps` | 1 | INI_ALL | verifica se i file sono stati modificati |
| `opcache.revalidate_freq` | 2 | INI_ALL | intervallo di verifica in secondi, 0 = a ogni richiesta |
| `opcache.restrict_api` | vuoto | INI_SYSTEM | consente le funzioni API solo da un percorso |
| `opcache.validate_permission` | 0 | INI_SYSTEM | verifica i permessi dei file rispetto all'utente corrente |
| `opcache.validate_root` | 0 | INI_SYSTEM | evita collisioni di nomi con chroot |
| `opcache.file_cache` | vuoto | INI_SYSTEM | secondo livello di cache sul disco |

Una tipica configurazione di produzione potrebbe essere questa. Verifichi prima i valori con la Sua applicazione:

```ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.restrict_api=/var/www/admin-tools
```

Chi imposta `opcache.validate_timestamps=0` guadagna un po' di prestazioni. In tal caso però OPcache non riconosce più i file modificati e ogni deployment richiede un reset della cache o un riavvio.

## Osservare la cache e svuotarla in modo mirato

OPcache include funzioni proprie, tra cui `opcache_get_status()`, `opcache_get_configuration()`, `opcache_invalidate()` e `opcache_reset()`. Una breve occhiata in sola lettura al livello di riempimento:

```php
<?php
$status = opcache_get_status(false);
if ($status === false) {
    exit("OPcache ist nicht aktiv.\n");
}
printf("Gecachte Skripte: %d\n", $status['opcache_statistics']['num_cached_scripts']);
printf("Freier Speicher: %.1f MB\n", $status['memory_usage']['free_memory'] / 1048576);
```

Sui server con più siti web non ogni applicazione dovrebbe poter svuotare o leggere la cache di tutte le altre. A questo serve `opcache.restrict_api`: solo gli script sotto il percorso indicato possono chiamare le funzioni API.

## JIT: il compilatore di codice macchina in OPcache

Da PHP 8.0 OPcache contiene un compilatore JIT che traduce gli opcode in codice macchina. Secondo la RFC sul JIT è una componente quasi autonoma di OPcache e deposita il codice generato in un'area propria della memoria condivisa. Si controlla tramite `opcache.jit` e `opcache.jit_buffer_size`. Da PHP 8.4.0 `opcache.jit` è per impostazione predefinita su `disable`. Quando il JIT conviene lo spiega l'articolo [JIT e prestazioni in PHP 8](https://phpsos.de/it/php/jit-und-performance/).

## OPcache e sicurezza: che cosa vale dopo PHP2Shell

OPcache non è uno strumento di sicurezza, ma ha conseguenze per la sicurezza. Dopo PHP2Shell tre punti sono importanti:

1. **Un reset della cache non è un aggiornamento.** `opcache_reset()` svuota solo gli script in cache. L'interprete con le vulnerabilità CVE-2026-109618 e CVE-2026-109619 resta in memoria finché tutti i processi non sono riavviati. Come si fa è spiegato in [Riavviare PHP-FPM e tutti i worker](https://phpsos.de/it/php2shell/php-fpm-neustart/).
2. **Il codice iniettato può sopravvivere nella cache.** Se un file è stato manipolato e poi sostituito, con il controllo dei timestamp disattivato la vecchia versione può continuare a essere eseguita. Dopo una bonifica occorre quindi anche un riavvio.
3. **La memoria condivisa richiede separazione.** Sui server con più clienti aiutano pool PHP-FPM propri per ogni sito, oltre a `opcache.validate_permission` e `opcache.restrict_api`. Una directory per `opcache.file_cache` deve essere scrivibile solo dall'utente PHP.

> **Consiglio:**
> Dopo ogni aggiornamento verifichi che l'ora di avvio dei processi PHP sia successiva all'aggiornamento. Una OPcache piena con un alto tasso di hit non è la prova che giri il nuovo interprete.

## Come aiuta concretamente PHP SOS?

- **Verificare la configurazione:** leggiamo la configurazione attiva di OPcache per ogni modalità di esecuzione e la confrontiamo con la Sua applicazione.
- **Mettere in sicurezza i deployment:** impostiamo una procedura fissa per reset della cache e riavvio, perché non continui a girare alcuna vecchia versione del codice.
- **Separare i clienti:** nell'ambito dell'[hardening del server](https://phpsos.de/it/leistungen/server-haertung/) impostiamo pool separati, `restrict_api` e permessi adeguati.
- **Controllare dopo gli aggiornamenti:** documentiamo con gli orari di avvio dei processi che l'interprete aggiornato è davvero attivo.


## Domande frequenti

**OPcache è attiva per impostazione predefinita?**  
OPcache viene fornita con PHP dalla versione 5.5.0 e, secondo il manuale, funziona con opcache.enable=1 come valore predefinito non appena l'estensione è caricata. Se sia caricata dipende dal Suo pacchetto o dall'hoster. Da riga di comando OPcache è invece disattivata per impostazione predefinita (opcache.enable_cli=0).

**Perché dopo un deployment vedo ancora il vecchio codice?**  
Probabilmente OPcache controlla le modifiche ai file solo a intervalli o non le controlla affatto. Con opcache.revalidate_freq attende per impostazione predefinita due secondi, con opcache.validate_timestamps=0 mai. In tal caso aiuta solo un reset della cache o un riavvio di PHP-FPM o Apache.

**Dopo un aggiornamento di PHP basta opcache_reset()?**  
No. opcache_reset() svuota solo la cache con gli script tradotti. Un aggiornamento di PHP sostituisce l'interprete stesso, che è caricato in ogni processo in esecuzione. Per questo tutti i processi PHP devono essere riavviati.

**Il JIT è attivo in PHP 8.4?**  
Secondo il manuale, da PHP 8.4.0 opcache.jit è impostato per impostazione predefinita su disable, mentre opcache.jit_buffer_size è 64M. Prima era il contrario: jit su tracing, buffer a 0. In entrambi i casi il JIT non è attivo senza una configurazione consapevole.

## Fonti

- [Manuale PHP: OPcache](https://www.php.net/manual/en/book.opcache.php)
- [Manuale PHP: configurazione di OPcache](https://www.php.net/manual/en/opcache.configuration.php)
- [Manuale PHP: installazione di OPcache](https://www.php.net/manual/en/opcache.installation.php)
- [PHP RFC: JIT](https://wiki.php.net/rfc/jit)
