Kort sagt: OPcache er PHP's indbyggede bytekode-cache. Ifølge manualen gemmer den forkompileret bytekode i den delte hukommelse, så PHP ikke skal indlæse og oversætte scripts ved hver forespørgsel. Den hører med til leverancen siden PHP 5.5.0. OPcache gør PHP hurtigere, men erstatter ikke en opdatering: Efter en PHP-patch skal alle PHP-processer genstartes, det er ikke nok at tømme cachen.
Hvad gør OPcache helt præcist?
Ved hver forespørgsel skal PHP læse et script, opdele det og oversætte det til opcodes, altså kommandoerne til den virtuelle maskine i Zend Engine. Ved et CMS med hundredvis af filer er det meget arbejde, som gentages hele tiden.
OPcache gemmer resultatet af denne oversættelse i den delte hukommelse (shared memory). Alle workere i en PHP-FPM-tjeneste eller alle Apache-processer med mod_php tilgår den. Ændres en fil ikke, genbruges dens bytekode direkte.
OPcache indlæses som Zend-udvidelse, ikke som almindelig udvidelse:
; Linux (sti afhængig af pakken)
zend_extension=opcache.so
; Windows
; zend_extension=php_opcache.dll
Ifølge manualen skal OPcache indlæses før Xdebug, hvis begge er aktive.
Det er vigtigt, hvem der ejer den delte hukommelse. Ved PHP-FPM opretter master-processen den, og alle workere i alle pools i denne tjeneste bruger den. Ved mod_php hører den til Apaches hovedproces. En genstart af tjenesten tømmer derfor cachen fuldstændigt, en enkelt ny worker gør det derimod ikke. På kommandolinjen findes der ingen delt hukommelse på tværs af kald, fordi hvert kald er en proces for sig; dér er OPcache slået fra som standard.
For beslutningstagere er en tommelfingerregel nok: OPcache giver næsten altid mening på produktionsservere, men kræver et klart forløb for deployments og opdateringer.
Hvilke OPcache-indstillinger tæller?
De følgende værdier stammer fra konfigurationssiden i PHP-manualen. Kolonnen "Kan ændres" viser, hvor en indstilling må sættes: INI_SYSTEM kun i php.ini eller serverkonfigurationen, INI_ALL overalt.
| Direktiv | Standard | Kan ændres | Betydning |
|---|---|---|---|
opcache.enable |
1 | INI_ALL | cache til eller fra, kan under kørsel kun slås fra |
opcache.enable_cli |
0 | INI_SYSTEM | cache til kommandolinjen |
opcache.memory_consumption |
128 | INI_SYSTEM | størrelsen på den delte hukommelse i MB |
opcache.interned_strings_buffer |
8 | INI_SYSTEM | hukommelse til fælles tegnstrenge i MB |
opcache.max_accelerated_files |
10000 | INI_SYSTEM | maksimalt antal cachede scripts |
opcache.validate_timestamps |
1 | INI_ALL | kontrollerer, om filer er ændret |
opcache.revalidate_freq |
2 | INI_ALL | kontrolinterval i sekunder, 0 = ved hver forespørgsel |
opcache.restrict_api |
tom | INI_SYSTEM | tillader API-funktioner kun fra en sti |
opcache.validate_permission |
0 | INI_SYSTEM | kontrollerer filrettigheder mod den aktuelle bruger |
opcache.validate_root |
0 | INI_SYSTEM | forhindrer navnekollisioner ved chroot |
opcache.file_cache |
tom | INI_SYSTEM | andet cache-niveau på disken |
En typisk produktionskonfiguration kunne se sådan ud. Kontrollér værdierne på forhånd med jeres applikation:
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
Den, der sætter opcache.validate_timestamps=0, vinder lidt ydelse. Så opdager OPcache dog slet ikke længere ændrede filer, og hvert deployment kræver et reset af cachen eller en genstart.
Observere cachen og tømme den målrettet
OPcache har egne funktioner med, blandt andet opcache_get_status(), opcache_get_configuration(), opcache_invalidate() og opcache_reset(). Et kort, læsende blik på fyldningsgraden:
<?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);
På servere med flere websites bør ikke hver applikation kunne tømme eller aflæse alle andres cache. Det er formålet med opcache.restrict_api: Kun scripts under den angivne sti må kalde API-funktionerne.
JIT: maskinkode-compileren i OPcache
Siden PHP 8.0 indeholder OPcache en JIT-compiler, der oversætter opcodes til maskinkode. Ifølge JIT-RFC'en er den en næsten selvstændig del af OPcache og lægger den genererede kode i et eget område af den delte hukommelse. Den styres via opcache.jit og opcache.jit_buffer_size. Siden PHP 8.4.0 står opcache.jit som standard på disable. Hvornår JIT kan betale sig, forklarer indlægget JIT og ydelse i PHP 8.
OPcache og sikkerhed: hvad der gælder efter PHP2Shell
OPcache er ikke et sikkerhedsværktøj, men har konsekvenser for sikkerheden. Tre punkter er vigtige efter PHP2Shell:
- Et cache-reset er ikke en opdatering.
opcache_reset()tømmer kun cachede scripts. Fortolkeren med sårbarhederne CVE-2026-109618 og CVE-2026-109619 bliver i hukommelsen, indtil alle processer er genstartet. Hvordan det gøres, står under Genstart PHP-FPM og alle workere. - Indsmuglet kode kan leve videre i cachen. Er en fil blevet manipuleret og senere erstattet, kan den gamle udgave ved slået-fra tidsstempelkontrol fortsat blive udført. Efter en oprydning hører derfor en genstart med.
- Delt hukommelse kræver adskillelse. På servere med flere kunder hjælper egne PHP-FPM-pools pr. website samt
opcache.validate_permissionogopcache.restrict_api. En mappe tilopcache.file_cachemå kun være skrivbar for PHP-brugeren.
Kontrollér efter hver opdatering, om starttidspunktet for PHP-processerne ligger efter opdateringen. En fuld OPcache med høj hitrate er ikke noget bevis for, at den nye fortolker kører.
Hvordan hjælper PHP SOS konkret?
- Kontrollere konfigurationen: Vi aflæser den aktive OPcache-konfiguration pr. driftsform og afstemmer den med jeres applikation.
- Sikre deployments: Vi indfører et fast forløb for cache-reset og genstart, så ingen gammel kodeversion kører videre.
- Adskille lejere: Som led i serverhærdningen sætter vi adskilte pools,
restrict_apiog passende rettigheder. - Kontrollere efter opdateringer: Vi dokumenterer via processernes starttidspunkter, at den opdaterede fortolker virkelig er aktiv.
Ofte stillede spørgsmål
Er OPcache aktiv som standard?
OPcache leveres med PHP siden PHP 5.5.0 og køres ifølge manualen med opcache.enable=1 som standard, så snart udvidelsen er indlæst. Om den er indlæst, afhænger af jeres pakke eller hostingudbyder. På kommandolinjen er OPcache derimod slået fra som standard (opcache.enable_cli=0).
Hvorfor ser jeg efter et deployment stadig den gamle kode?
Sandsynligvis kontrollerer OPcache filændringer kun med mellemrum eller slet ikke. Med opcache.revalidate_freq venter den som standard to sekunder, med opcache.validate_timestamps=0 aldrig. Så hjælper kun et reset af cachen eller en genstart af PHP-FPM hhv. Apache.
Er opcache_reset() nok efter en PHP-opdatering?
Nej. opcache_reset() tømmer kun cachen med oversatte scripts. En PHP-opdatering erstatter selve fortolkeren, og den er indlæst i hver kørende proces. Derfor skal alle PHP-processer genstartes.
Er JIT slået til i PHP 8.4?
Ifølge manualen er opcache.jit siden PHP 8.4.0 sat til disable som standard, mens opcache.jit_buffer_size er 64M. Tidligere var det omvendt: jit på tracing, buffer på 0. I begge tilfælde er JIT ikke aktiv uden bevidst konfiguration.