# OPcache objašnjen: PHP-ova predmemorija bytecodea

> OPcache objašnjen: kako radi PHP-ova predmemorija bytecodea, koje postavke vrijede, zašto se nakon ažuriranja mora isprazniti i kako je osigurati.

Izvor: https://phpsos.de/hr/php/opcache/  
Stanje: 25.10.2026  
Pružatelj: PHP SOS, PHP hitna pomoć i sigurnost poslužitelja. Hitna pomoć putem WhatsAppa: https://wa.me/491736494914?text=Pozdrav%20PHP%20SOS%2C%20trebamo%20pomo%C4%87%20s%20na%C5%A1im%20PHP%20poslu%C5%BEiteljem.%20Tvrtka%3A%20%E2%80%A6%20Web-stranica%3A%20%E2%80%A6

**Ukratko:** OPcache je ugrađena PHP-ova predmemorija bytecodea. Prema priručniku pohranjuje unaprijed kompiliran bytecode u zajedničku memoriju, pa PHP skripte ne mora pri svakom zahtjevu iznova učitavati i prevoditi. Dio je isporuke od PHP-a 5.5.0. OPcache ubrzava PHP, ali ne zamjenjuje ažuriranje: nakon PHP zakrpe moraju se ponovno pokrenuti svi PHP procesi, a ne samo isprazniti predmemorija.

## Što točno radi OPcache?

Pri svakom zahtjevu PHP mora pročitati skriptu, rastaviti je i prevesti u opcodeove, dakle u naredbe za virtualni stroj [Zend Enginea](https://phpsos.de/hr/php/zend-engine/). Kod CMS-a sa stotinama datoteka to je puno posla koji se neprestano ponavlja.

OPcache rezultat tog prevođenja sprema u zajedničku memoriju (shared memory). Pristupaju joj svi workeri jedne PHP-FPM usluge odnosno svi Apache procesi s mod_php-om. Ako se datoteka ne promijeni, njezin se bytecode izravno ponovno koristi.

OPcache se učitava kao Zend ekstenzija, a ne kao obična ekstenzija:

```ini
; Linux (putanja ovisi o paketu)
zend_extension=opcache.so
; Windows
; zend_extension=php_opcache.dll
```

Prema priručniku OPcache treba učitati prije Xdebuga ako su oba aktivna.

Važno je kome pripada zajednička memorija. Kod PHP-FPM-a nju stvara master proces, a koriste je svi workeri svih poolova te usluge. Kod mod_php-a pripada glavnom procesu Apachea. Ponovno pokretanje usluge stoga potpuno prazni predmemoriju, a jedan novi worker ne. Za naredbeni redak ne postoji zajednička memorija među pozivima jer je svaki poziv zaseban proces; tamo je OPcache prema zadanim postavkama isključen.

Za donositelje odluka dovoljno je jedno pravilo: OPcache je na produkcijskim poslužiteljima gotovo uvijek smislen, ali traži jasan slijed za deploymente i ažuriranja.

## Koje OPcache postavke vrijede?

Sljedeće vrijednosti potječu sa stranice konfiguracije PHP priručnika. Stupac „Promjenjivo“ pokazuje gdje se postavka smije podešavati: `INI_SYSTEM` samo u php.ini ili konfiguraciji poslužitelja, `INI_ALL` posvuda.

| Direktiva | Zadano | Promjenjivo | Značenje |
|---|---|---|---|
| `opcache.enable` | 1 | INI_ALL | predmemorija uključena ili isključena, tijekom rada može se samo isključiti |
| `opcache.enable_cli` | 0 | INI_SYSTEM | predmemorija za naredbeni redak |
| `opcache.memory_consumption` | 128 | INI_SYSTEM | veličina zajedničke memorije u MB |
| `opcache.interned_strings_buffer` | 8 | INI_SYSTEM | memorija za zajedničke nizove znakova u MB |
| `opcache.max_accelerated_files` | 10000 | INI_SYSTEM | najveći broj skripti u predmemoriji |
| `opcache.validate_timestamps` | 1 | INI_ALL | provjerava jesu li se datoteke promijenile |
| `opcache.revalidate_freq` | 2 | INI_ALL | razmak provjere u sekundama, 0 = pri svakom zahtjevu |
| `opcache.restrict_api` | prazno | INI_SYSTEM | dopušta API funkcije samo iz jedne putanje |
| `opcache.validate_permission` | 0 | INI_SYSTEM | provjerava prava datoteka u odnosu na trenutnog korisnika |
| `opcache.validate_root` | 0 | INI_SYSTEM | sprječava sukobe naziva kod chroota |
| `opcache.file_cache` | prazno | INI_SYSTEM | druga razina predmemorije na disku |

Tipična produkcijska konfiguracija mogla bi izgledati ovako. Vrijednosti prije provjerite sa svojom aplikacijom:

```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
```

Tko postavi `opcache.validate_timestamps=0`, dobiva malo učinkovitosti. No tada OPcache uopće više ne prepoznaje izmijenjene datoteke i svaki deployment traži reset predmemorije ili ponovno pokretanje.

## Promatrati predmemoriju i ciljano je prazniti

OPcache donosi vlastite funkcije, među ostalim `opcache_get_status()`, `opcache_get_configuration()`, `opcache_invalidate()` i `opcache_reset()`. Kratak pogled samo za čitanje na popunjenost:

```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);
```

Na poslužiteljima s više web-stranica ne bi svaka aplikacija smjela moći prazniti ili čitati predmemoriju svih ostalih. Za to služi `opcache.restrict_api`: API funkcije smiju pozivati samo skripte ispod navedene putanje.

## JIT: kompilator strojnog koda u OPcacheu

Od PHP-a 8.0 OPcache sadrži JIT kompilator koji opcodeove prevodi u strojni kod. Prema JIT RFC-u gotovo je samostalan dio OPcachea i stvoreni kod sprema u zasebno područje zajedničke memorije. Upravlja se putem `opcache.jit` i `opcache.jit_buffer_size`. Od PHP-a 8.4.0 `opcache.jit` je prema zadanim postavkama `disable`. Kada se JIT isplati, objašnjava članak [JIT i performanse u PHP-u 8](https://phpsos.de/hr/php/jit-und-performance/).

## OPcache i sigurnost: što vrijedi nakon PHP2Shella

OPcache nije sigurnosni alat, ali ima posljedice za sigurnost. Tri su točke važne nakon PHP2Shella:

1. **Reset predmemorije nije ažuriranje.** `opcache_reset()` prazni samo skripte u predmemoriji. Interpreter s ranjivostima CVE-2026-109618 i CVE-2026-109619 ostaje u memoriji dok se svi procesi ne pokrenu iznova. Kako to ide, piše na stranici [Ponovno pokretanje PHP-FPM-a i svih workera](https://phpsos.de/hr/php2shell/php-fpm-neustart/).
2. **Ubačeni kod može živjeti u predmemoriji.** Ako je datoteka bila manipulirana, a kasnije zamijenjena, uz isključenu provjeru vremenskih oznaka stara se izvedba može i dalje izvršavati. Nakon čišćenja zato treba i ponovno pokretanje.
3. **Zajednička memorija traži razdvajanje.** Na poslužiteljima s više klijenata pomažu vlastiti PHP-FPM poolovi po web-stranici te `opcache.validate_permission` i `opcache.restrict_api`. Direktorij za `opcache.file_cache` smije biti upisiv samo za PHP korisnika.

> **Savjet:**
> Nakon svakog ažuriranja provjerite je li vrijeme pokretanja PHP procesa poslije ažuriranja. Pun OPcache s visokom stopom pogodaka nije dokaz da radi novi interpreter.

## Kako PHP SOS konkretno pomaže?

- **Provjeriti konfiguraciju:** Očitavamo aktivnu OPcache konfiguraciju po načinu rada i uspoređujemo je s Vašom aplikacijom.
- **Osigurati deploymente:** Uspostavljamo čvrst slijed za reset predmemorije i ponovno pokretanje kako nijedna stara izvedba koda ne bi nastavila raditi.
- **Razdvojiti klijente:** U okviru [ojačavanja poslužitelja](https://phpsos.de/hr/leistungen/server-haertung/) postavljamo odvojene poolove, `restrict_api` i odgovarajuća prava.
- **Provjeriti nakon ažuriranja:** Putem vremena pokretanja procesa dokazujemo da je ažurirani interpreter stvarno aktivan.


## Česta pitanja

**Je li OPcache prema zadanim postavkama aktivan?**  
OPcache se isporučuje s PHP-om od verzije 5.5.0 i prema priručniku radi s opcache.enable=1 kao zadanom vrijednosti čim se ekstenzija učita. Je li učitana, ovisi o Vašem paketu ili pružatelju hostinga. U naredbenom retku OPcache je, naprotiv, prema zadanim postavkama isključen (opcache.enable_cli=0).

**Zašto nakon deploymenta još vidim stari kod?**  
Vjerojatno OPcache izmjene datoteka provjerava samo u razmacima ili uopće ne. S opcache.revalidate_freq prema zadanim postavkama čeka dvije sekunde, a s opcache.validate_timestamps=0 nikad. Tada pomaže samo reset predmemorije ili ponovno pokretanje PHP-FPM-a odnosno Apachea.

**Je li opcache_reset() dovoljan nakon ažuriranja PHP-a?**  
Ne. opcache_reset() prazni samo predmemoriju s prevedenim skriptama. Ažuriranje PHP-a zamjenjuje sam interpreter, a on je učitan u svakom pokrenutom procesu. Zato se moraju ponovno pokrenuti svi PHP procesi.

**Je li JIT uključen u PHP-u 8.4?**  
Prema priručniku opcache.jit je od PHP-a 8.4.0 prema zadanim postavkama postavljen na disable, dok opcache.jit_buffer_size iznosi 64M. Prije je bilo obrnuto: jit na tracing, međuspremnik na 0. U oba slučaja JIT bez svjesne konfiguracije nije aktivan.

## Izvori

- [PHP priručnik: OPcache](https://www.php.net/manual/en/book.opcache.php)
- [PHP priručnik: Konfiguracija OPcachea](https://www.php.net/manual/en/opcache.configuration.php)
- [PHP priručnik: Instalacija OPcachea](https://www.php.net/manual/en/opcache.installation.php)
- [PHP RFC: JIT](https://wiki.php.net/rfc/jit)
