Situazione attuale: PHP2Shell. Due vulnerabilità critiche di PHP (CVSS 9,2) consentono codice dannoso senza autenticazione. Patch dal 21/10/2026.Che cosa fare ora →

OPcache spiegata: la cache di bytecode di PHP

OPcache tiene il codice PHP già tradotto nella memoria condivisa. Risparmia tempo di calcolo, ma richiede cura in deployment, riavvii e sui server con più clienti.

Stato 5 min di letturaConoscere PHP

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. 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:

; 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:

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
$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.

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.
  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 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

Contatto immediato

Ogni ora conta. Ci scriva adesso.

Descriva brevemente sistema, versione di PHP e quanto osservato. Ci faremo sentire, chiariremo la situazione e lavoreremo da remoto fino alla chiusura e alla documentazione dell'incidente.

Aiuto immediato