Pe scurt: OPcache este cache-ul de bytecode integrat al PHP. Potrivit manualului, el stochează bytecode precompilat în memoria comună, astfel încât PHP să nu mai trebuiască să încarce și să traducă scripturile la fiecare cerere. Face parte din pachetul livrat din PHP 5.5.0. OPcache face PHP mai rapid, dar nu înlocuiește o actualizare: după un patch PHP trebuie repornite toate procesele PHP, nu doar golit cache-ul.
Ce face exact OPcache?
La fiecare cerere, PHP trebuie să citească un script, să-l descompună și să-l traducă în opcodes, adică în instrucțiunile pentru mașina virtuală a Zend Engine. La un CMS cu sute de fișiere, aceasta este multă muncă, repetată continuu.
OPcache stochează rezultatul acestei traduceri în memoria comună (shared memory). Toți workerii unui serviciu PHP-FPM sau toate procesele Apache cu mod_php o accesează. Dacă un fișier nu se schimbă, bytecode-ul lui este reutilizat direct.
OPcache se încarcă ca extensie Zend, nu ca o extensie obișnuită:
; Linux (calea diferă în funcție de pachet)
zend_extension=opcache.so
; Windows
; zend_extension=php_opcache.dll
Potrivit manualului, OPcache trebuie încărcat înaintea Xdebug dacă ambele sunt active.
Important este cui îi aparține memoria comună. La PHP-FPM, o creează procesul master, iar toți workerii tuturor pool-urilor acelui serviciu o folosesc. La mod_php, ea aparține procesului principal Apache. O repornire a serviciului golește de aceea complet cache-ul, un singur worker nou, în schimb, nu. Pentru linia de comandă nu există memorie comună între apeluri, pentru că fiecare apel este un proces separat; acolo OPcache este implicit oprit.
Pentru factorii de decizie este suficientă o regulă practică: OPcache este aproape întotdeauna util pe serverele de producție, dar cere un proces clar pentru deployment-uri și actualizări.
Ce setări OPcache contează?
Valorile următoare provin din pagina de configurare a manualului PHP. Coloana „Modificabil” arată unde poate fi setată o opțiune: INI_SYSTEM doar în php.ini sau în configurația serverului, INI_ALL oriunde.
| Directivă | Implicit | Modificabil | Semnificație |
|---|---|---|---|
opcache.enable |
1 | INI_ALL | cache pornit sau oprit, în timpul execuției poate fi doar oprit |
opcache.enable_cli |
0 | INI_SYSTEM | cache pentru linia de comandă |
opcache.memory_consumption |
128 | INI_SYSTEM | dimensiunea memoriei comune în MB |
opcache.interned_strings_buffer |
8 | INI_SYSTEM | memorie pentru șirurile de caractere comune, în MB |
opcache.max_accelerated_files |
10000 | INI_SYSTEM | numărul maxim de scripturi din cache |
opcache.validate_timestamps |
1 | INI_ALL | verifică dacă fișierele au fost modificate |
opcache.revalidate_freq |
2 | INI_ALL | intervalul de verificare în secunde, 0 = la fiecare cerere |
opcache.restrict_api |
gol | INI_SYSTEM | permite funcțiile API doar dintr-o cale anume |
opcache.validate_permission |
0 | INI_SYSTEM | verifică drepturile fișierelor față de utilizatorul curent |
opcache.validate_root |
0 | INI_SYSTEM | previne coliziunile de nume la chroot |
opcache.file_cache |
gol | INI_SYSTEM | al doilea nivel de cache, pe disc |
O configurație tipică de producție ar putea arăta așa. Verificați valorile în prealabil cu aplicația dumneavoastră:
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
Cine setează opcache.validate_timestamps=0 câștigă ceva performanță. În acest caz, OPcache nu mai recunoaște deloc fișierele modificate, iar fiecare deployment cere o resetare a cache-ului sau o repornire.
Observarea cache-ului și golirea lui țintită
OPcache vine cu propriile funcții, printre care opcache_get_status(), opcache_get_configuration(), opcache_invalidate() și opcache_reset(). O privire scurtă, doar de citire, asupra gradului de umplere:
<?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);
Pe serverele cu mai multe site-uri, nu orice aplicație ar trebui să poată goli sau citi cache-ul tuturor celorlalte. Pentru aceasta este gândit opcache.restrict_api: doar scripturile aflate sub calea indicată pot apela funcțiile API.
JIT: compilatorul de cod-mașină din OPcache
Din PHP 8.0, OPcache conține un compilator JIT care traduce opcodes în cod-mașină. Potrivit RFC-ului JIT, acesta este o parte aproape independentă a OPcache și depune codul generat într-o zonă proprie a memoriei comune. Este controlat prin opcache.jit și opcache.jit_buffer_size. Din PHP 8.4.0, opcache.jit este implicit pe disable. Când merită JIT explică articolul JIT și performanță în PHP 8.
OPcache și securitatea: ce se aplică după PHP2Shell
OPcache nu este un instrument de securitate, dar are consecințe pentru securitate. Trei puncte sunt importante după PHP2Shell:
- O resetare a cache-ului nu este o actualizare.
opcache_reset()golește doar scripturile din cache. Interpretorul cu vulnerabilitățile CVE-2026-109618 și CVE-2026-109619 rămâne în memorie până când toate procesele sunt repornite. Cum se face aflați la Repornirea PHP-FPM și a tuturor workerilor. - Codul injectat poate supraviețui în cache. Dacă un fișier a fost manipulat și ulterior înlocuit, la verificarea dezactivată a marcajelor de timp poate fi executată în continuare versiunea veche. După o curățare, o repornire face de aceea parte din proces.
- Memoria comună are nevoie de separare. Pe serverele cu mai mulți clienți ajută pool-uri PHP-FPM separate pentru fiecare site, precum și
opcache.validate_permissionșiopcache.restrict_api. Un director pentruopcache.file_cachetrebuie să poată fi scris doar de utilizatorul PHP.
După fiecare actualizare, verificați dacă ora de pornire a proceselor PHP este ulterioară actualizării. Un OPcache plin, cu o rată mare de succes, nu este o dovadă că rulează noul interpretor.
Cum ajută PHP SOS concret?
- Verificarea configurației: Citim configurația OPcache activă pentru fiecare mod de operare și o corelăm cu aplicația dumneavoastră.
- Securizarea deployment-urilor: Stabilim un proces fix pentru resetarea cache-ului și repornire, astfel încât să nu continue să ruleze o versiune veche a codului.
- Separarea clienților: În cadrul întăririi serverului setăm pool-uri separate,
restrict_apiși drepturi potrivite. - Controlul după actualizări: Dovedim prin orele de pornire ale proceselor că interpretorul actualizat este cu adevărat activ.
Întrebări frecvente
Este OPcache activ implicit?
OPcache este livrat cu PHP din versiunea 5.5.0 și, potrivit manualului, funcționează implicit cu opcache.enable=1 de îndată ce extensia este încărcată. Dacă este încărcată depinde de pachetul dumneavoastră sau de furnizorul de hosting. În linia de comandă, în schimb, OPcache este implicit oprit (opcache.enable_cli=0).
De ce văd încă codul vechi după un deployment?
Probabil OPcache verifică modificările fișierelor doar la intervale sau deloc. Cu opcache.revalidate_freq așteaptă implicit două secunde, cu opcache.validate_timestamps=0 niciodată. Atunci ajută doar o resetare a cache-ului sau o repornire a PHP-FPM, respectiv a Apache.
Este suficient opcache_reset() după o actualizare PHP?
Nu. opcache_reset() golește doar cache-ul cu scripturi traduse. O actualizare PHP înlocuiește interpretorul însuși, iar acesta este încărcat în fiecare proces care rulează. Pentru aceasta trebuie repornite toate procesele PHP.
Este JIT activat în PHP 8.4?
Potrivit manualului, opcache.jit este setat implicit pe disable începând cu PHP 8.4.0, în timp ce opcache.jit_buffer_size este 64M. Înainte era invers: jit pe tracing, bufferul pe 0. În ambele cazuri, JIT nu este activ fără o configurare deliberată.