# OPcache vysvětlena: bytecode cache v PHP

> OPcache vysvětlena: jak pracuje bytecode cache PHP, která nastavení jsou důležitá, proč je nutné ji po aktualizacích vyprázdnit a jak ji zabezpečit.

Zdroj: https://phpsos.de/cs/php/opcache/  
Stav: 25.10.2026  
Poskytovatel: PHP SOS, Nouzová pomoc pro PHP a bezpečnost serverů. Okamžitá pomoc přes WhatsApp: https://wa.me/491736494914?text=Dobr%C3%BD%20den%2C%20PHP%20SOS%2C%20pot%C5%99ebujeme%20pomoc%20s%20na%C5%A1%C3%ADm%20PHP%20serverem.%20Firma%3A%20%E2%80%A6%20Web%3A%20%E2%80%A6

**Stručně:** OPcache je vestavěná bytecode cache PHP. Podle příručky ukládá předkompilovaný bytecode do sdílené paměti, takže PHP nemusí skripty při každém požadavku znovu načítat a překládat. Je součástí dodávky od PHP 5.5.0. OPcache PHP zrychluje, ale nenahrazuje aktualizaci: po záplatě PHP je nutné restartovat všechny procesy PHP, nestačí vyprázdnit cache.

## Co přesně OPcache dělá?

Při každém požadavku musí PHP skript přečíst, rozložit a přeložit do opcodů, tedy do příkazů pro virtuální stroj [Zend Engine](https://phpsos.de/cs/php/zend-engine/). U CMS se stovkami souborů je to hodně práce, která se neustále opakuje.

OPcache ukládá výsledek tohoto překladu do sdílené paměti (shared memory). Přistupují k ní všichni workeři služby PHP-FPM nebo všechny procesy Apache s mod_php. Pokud se soubor nezmění, jeho bytecode se použije přímo.

OPcache se načítá jako rozšíření Zend, nikoli jako běžné rozšíření:

```ini
; Linux (cesta podle balíčku)
zend_extension=opcache.so
; Windows
; zend_extension=php_opcache.dll
```

Podle příručky se má OPcache načítat před Xdebugem, pokud jsou aktivní oba.

Důležité je, komu sdílená paměť patří. U PHP-FPM ji vytváří hlavní proces (master) a využívají ji všichni workeři všech poolů této služby. U mod_php patří k hlavnímu procesu Apache. Restart služby proto cache vyprázdní úplně, jeden nový worker však ne. V příkazové řádce neexistuje sdílená paměť napříč voláními, protože každé volání je samostatný proces; tam je OPcache standardně vypnuta.

Pro rozhodovatele stačí jednoduché pravidlo: OPcache je na produkčních serverech téměř vždy užitečná, vyžaduje ale jasný postup pro nasazování a aktualizace.

## Která nastavení OPcache jsou důležitá?

Následující hodnoty pocházejí ze stránky o konfiguraci v příručce PHP. Sloupec „Měnitelné“ ukazuje, kde lze nastavení provést: `INI_SYSTEM` jen v php.ini nebo v konfiguraci serveru, `INI_ALL` všude.

| Direktiva | Výchozí | Měnitelné | Význam |
|---|---|---|---|
| `opcache.enable` | 1 | INI_ALL | cache zapnuta nebo vypnuta, za běhu lze jen vypnout |
| `opcache.enable_cli` | 0 | INI_SYSTEM | cache pro příkazovou řádku |
| `opcache.memory_consumption` | 128 | INI_SYSTEM | velikost sdílené paměti v MB |
| `opcache.interned_strings_buffer` | 8 | INI_SYSTEM | paměť pro sdílené řetězce v MB |
| `opcache.max_accelerated_files` | 10000 | INI_SYSTEM | maximální počet skriptů v cache |
| `opcache.validate_timestamps` | 1 | INI_ALL | kontroluje, zda se soubory změnily |
| `opcache.revalidate_freq` | 2 | INI_ALL | interval kontroly v sekundách, 0 = při každém požadavku |
| `opcache.restrict_api` | prázdné | INI_SYSTEM | povoluje funkce API jen z jedné cesty |
| `opcache.validate_permission` | 0 | INI_SYSTEM | kontroluje oprávnění k souborům vůči aktuálnímu uživateli |
| `opcache.validate_root` | 0 | INI_SYSTEM | zabraňuje kolizím názvů při chroot |
| `opcache.file_cache` | prázdné | INI_SYSTEM | druhá úroveň cache na disku |

Typická produkční konfigurace by mohla vypadat takto. Hodnoty předem ověřte se svou aplikací:

```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
```

Kdo nastaví `opcache.validate_timestamps=0`, získá trochu výkonu. OPcache pak ale změněné soubory už vůbec nepozná a každé nasazení vyžaduje reset cache nebo restart.

## Sledování cache a cílené vyprazdňování

OPcache má vlastní funkce, mimo jiné `opcache_get_status()`, `opcache_get_configuration()`, `opcache_invalidate()` a `opcache_reset()`. Krátký pohled jen pro čtení na naplnění:

```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 serverech s více weby by neměla mít každá aplikace možnost vyprazdňovat nebo číst cache všech ostatních. K tomu slouží `opcache.restrict_api`: funkce API smějí volat jen skripty pod zadanou cestou.

## JIT: kompilátor strojového kódu v OPcache

Od PHP 8.0 obsahuje OPcache kompilátor JIT, který překládá opcody na strojový kód. Podle RFC k JIT je téměř samostatnou součástí OPcache a vytvořený kód ukládá do vlastní oblasti sdílené paměti. Řídí se pomocí `opcache.jit` a `opcache.jit_buffer_size`. Od PHP 8.4.0 je `opcache.jit` standardně nastaveno na `disable`. Kdy se JIT vyplatí, vysvětluje článek [JIT a výkon v PHP 8](https://phpsos.de/cs/php/jit-und-performance/).

## OPcache a bezpečnost: co platí po PHP2Shell

OPcache není bezpečnostní nástroj, má ale důsledky pro bezpečnost. Po PHP2Shell jsou důležité tři body:

1. **Reset cache není aktualizace.** `opcache_reset()` vyprázdní jen skripty v cache. Interpret se zranitelnostmi CVE-2026-109618 a CVE-2026-109619 zůstává v paměti, dokud nejsou restartovány všechny procesy. Jak na to, popisuje článek [Restart PHP-FPM a všech workerů](https://phpsos.de/cs/php2shell/php-fpm-neustart/).
2. **Vložený kód může v cache přežít.** Pokud byl soubor zmanipulován a později nahrazen, může se při vypnuté kontrole časových razítek dál provádět stará verze. Po vyčištění proto patří k postupu restart.
3. **Sdílená paměť vyžaduje oddělení.** Na serverech s více zákazníky pomáhají samostatné pooly PHP-FPM pro každý web a také `opcache.validate_permission` a `opcache.restrict_api`. Adresář pro `opcache.file_cache` smí být zapisovatelný jen pro uživatele PHP.

> **Tip:**
> Po každé aktualizaci zkontrolujte, zda je doba spuštění procesů PHP později než aktualizace. Plná OPcache s vysokou úspěšností není důkazem, že běží nový interpret.

## Jak konkrétně pomáhá PHP SOS?

- **Zkontrolovat konfiguraci:** Načteme aktivní konfiguraci OPcache pro každý provozní režim a porovnáme ji s vaší aplikací.
- **Zabezpečit nasazování:** Zavedeme pevný postup pro reset cache a restart, aby nepokračovala žádná stará verze kódu.
- **Oddělit klienty:** V rámci [zpevnění serveru](https://phpsos.de/cs/leistungen/server-haertung/) nastavíme oddělené pooly, `restrict_api` a vhodná oprávnění.
- **Kontrolovat po aktualizacích:** Podle časů spuštění procesů doložíme, že aktualizovaný interpret skutečně běží.


## Časté dotazy

**Je OPcache standardně aktivní?**  
OPcache se s PHP dodává od PHP 5.5.0 a podle příručky běží s výchozím nastavením opcache.enable=1, jakmile je rozšíření načteno. Zda je načteno, závisí na vašem balíčku nebo poskytovateli hostingu. V příkazové řádce je OPcache naopak standardně vypnuta (opcache.enable_cli=0).

**Proč po nasazení stále vidím starý kód?**  
Pravděpodobně OPcache kontroluje změny souborů jen v intervalech, nebo vůbec. S opcache.revalidate_freq čeká standardně dvě sekundy, s opcache.validate_timestamps=0 nikdy. Pak pomůže jen reset cache nebo restart PHP-FPM, resp. Apache.

**Stačí po aktualizaci PHP opcache_reset()?**  
Ne. opcache_reset() vyprázdní jen cache s přeloženými skripty. Aktualizace PHP nahrazuje samotný interpret a ten je načten v každém běžícím procesu. K tomu je nutné restartovat všechny procesy PHP.

**Je JIT v PHP 8.4 zapnutý?**  
Podle příručky je opcache.jit od PHP 8.4.0 standardně nastaveno na disable, zatímco opcache.jit_buffer_size činí 64M. Dříve to bylo naopak: jit na tracing, vyrovnávací paměť na 0. V obou případech není JIT bez vědomé konfigurace aktivní.

## Zdroje

- [Příručka PHP: OPcache](https://www.php.net/manual/en/book.opcache.php)
- [Příručka PHP: Konfigurace OPcache](https://www.php.net/manual/en/opcache.configuration.php)
- [Příručka PHP: Instalace OPcache](https://www.php.net/manual/en/opcache.installation.php)
- [PHP RFC: JIT](https://wiki.php.net/rfc/jit)
