# OPcache wyjaśniony: pamięć podręczna bajtkodu PHP

> OPcache wyjaśniony: jak działa pamięć podręczna bajtkodu PHP, które ustawienia się liczą, dlaczego po aktualizacji trzeba ją opróżnić i jak ją zabezpieczyć.

Źródło: https://phpsos.de/pl/php/opcache/  
Stan: 25.10.2026  
Dostawca: PHP SOS, Pomoc awaryjna PHP i bezpieczeństwo serwerów. Natychmiastowa pomoc przez WhatsApp: https://wa.me/491736494914?text=Dzie%C5%84%20dobry%2C%20PHP%20SOS%2C%20potrzebujemy%20pomocy%20z%20naszym%20serwerem%20PHP.%20Firma%3A%20%E2%80%A6%20Strona%20internetowa%3A%20%E2%80%A6

**Krótko:** OPcache to wbudowana pamięć podręczna bajtkodu PHP. Według podręcznika przechowuje prekompilowany bajtkod we wspólnej pamięci, dzięki czemu PHP nie musi ładować i tłumaczyć skryptów przy każdym żądaniu. Wchodzi w skład dystrybucji od PHP 5.5.0. OPcache przyspiesza PHP, ale nie zastępuje aktualizacji: po poprawce PHP wszystkie procesy PHP muszą się zrestartować, a nie tylko pamięć podręczna zostać opróżniona.

## Co dokładnie robi OPcache?

Przy każdym żądaniu PHP musi przeczytać skrypt, rozbić go i przetłumaczyć na opcody, czyli polecenia dla maszyny wirtualnej [Zend Engine](https://phpsos.de/pl/php/zend-engine/). W CMS z setkami plików to dużo pracy, która ciągle się powtarza.

OPcache zapisuje wynik tego tłumaczenia we wspólnej pamięci (shared memory). Korzystają z niej wszystkie workery usługi PHP-FPM albo wszystkie procesy Apache z mod_php. Jeśli plik się nie zmienia, jego bajtkod jest używany bezpośrednio ponownie.

OPcache ładuje się jako rozszerzenie Zend, a nie jako zwykłe rozszerzenie:

```ini
; Linux (ścieżka zależna od pakietu)
zend_extension=opcache.so
; Windows
; zend_extension=php_opcache.dll
```

Według podręcznika OPcache powinien być ładowany przed Xdebug, jeśli oba są aktywne.

Ważne jest, do kogo należy wspólna pamięć. W PHP-FPM tworzy ją proces główny, a korzystają z niej wszystkie workery wszystkich pul tej usługi. W mod_php należy do głównego procesu Apache. Restart usługi opróżnia więc pamięć podręczną całkowicie, natomiast pojedynczy nowy worker nie. W wierszu poleceń nie ma wspólnej pamięci między wywołaniami, ponieważ każde wywołanie to odrębny proces; tam OPcache jest domyślnie wyłączony.

Dla osób podejmujących decyzje wystarczy reguła kciuka: OPcache jest na serwerach produkcyjnych prawie zawsze sensowny, ale wymaga jasnej procedury wdrożeń i aktualizacji.

## Które ustawienia OPcache mają znaczenie?

Poniższe wartości pochodzą ze strony konfiguracji w podręczniku PHP. Kolumna „Zmienialna” pokazuje, gdzie ustawienie wolno ustawiać: `INI_SYSTEM` tylko w php.ini lub konfiguracji serwera, `INI_ALL` wszędzie.

| Dyrektywa | Domyślnie | Zmienialna | Znaczenie |
|---|---|---|---|
| `opcache.enable` | 1 | INI_ALL | pamięć podręczna włączona lub wyłączona, w czasie działania można ją tylko wyłączyć |
| `opcache.enable_cli` | 0 | INI_SYSTEM | pamięć podręczna dla wiersza poleceń |
| `opcache.memory_consumption` | 128 | INI_SYSTEM | rozmiar wspólnej pamięci w MB |
| `opcache.interned_strings_buffer` | 8 | INI_SYSTEM | pamięć na wspólne ciągi znaków w MB |
| `opcache.max_accelerated_files` | 10000 | INI_SYSTEM | maksymalna liczba buforowanych skryptów |
| `opcache.validate_timestamps` | 1 | INI_ALL | sprawdza, czy pliki zostały zmienione |
| `opcache.revalidate_freq` | 2 | INI_ALL | odstęp sprawdzania w sekundach, 0 = przy każdym żądaniu |
| `opcache.restrict_api` | puste | INI_SYSTEM | dopuszcza funkcje API tylko z jednej ścieżki |
| `opcache.validate_permission` | 0 | INI_SYSTEM | sprawdza uprawnienia plików względem bieżącego użytkownika |
| `opcache.validate_root` | 0 | INI_SYSTEM | zapobiega kolizjom nazw przy chroot |
| `opcache.file_cache` | puste | INI_SYSTEM | druga warstwa pamięci podręcznej na dysku |

Typowa konfiguracja produkcyjna mogłaby wyglądać tak. Proszę wcześniej sprawdzić wartości na swojej aplikacji:

```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
```

Kto ustawi `opcache.validate_timestamps=0`, zyskuje nieco wydajności. Wtedy jednak OPcache w ogóle nie rozpoznaje zmienionych plików i każde wdrożenie wymaga resetu pamięci podręcznej albo restartu.

## Obserwowanie pamięci podręcznej i celowe opróżnianie

OPcache ma własne funkcje, w tym `opcache_get_status()`, `opcache_get_configuration()`, `opcache_invalidate()` i `opcache_reset()`. Krótki, tylko odczytowy wgląd w stopień wypełnienia:

```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 serwerach z wieloma stronami nie każda aplikacja powinna móc opróżniać lub odczytywać pamięć podręczną wszystkich pozostałych. Do tego służy `opcache.restrict_api`: funkcje API mogą wywoływać tylko skrypty znajdujące się poniżej podanej ścieżki.

## JIT: kompilator kodu maszynowego w OPcache

Od PHP 8.0 OPcache zawiera kompilator JIT, który tłumaczy opcody na kod maszynowy. Według RFC dotyczącego JIT jest to niemal samodzielna część OPcache, która zapisuje wytworzony kod w osobnym obszarze wspólnej pamięci. Steruje się nim przez `opcache.jit` i `opcache.jit_buffer_size`. Od PHP 8.4.0 `opcache.jit` jest domyślnie ustawione na `disable`. Kiedy JIT się opłaca, wyjaśnia artykuł [JIT i wydajność w PHP 8](https://phpsos.de/pl/php/jit-und-performance/).

## OPcache i bezpieczeństwo: co obowiązuje po PHP2Shell

OPcache nie jest narzędziem bezpieczeństwa, ale ma skutki dla bezpieczeństwa. Trzy punkty są ważne po PHP2Shell:

1. **Reset pamięci podręcznej nie jest aktualizacją.** `opcache_reset()` opróżnia tylko buforowane skrypty. Interpreter z lukami CVE-2026-109618 i CVE-2026-109619 pozostaje w pamięci, dopóki wszystkie procesy nie zostaną zrestartowane. Jak to zrobić, opisujemy na stronie [Restart PHP-FPM i wszystkich workerów](https://phpsos.de/pl/php2shell/php-fpm-neustart/).
2. **Wstrzyknięty kod może przetrwać w pamięci podręcznej.** Jeśli plik został zmanipulowany, a później wymieniony, przy wyłączonym sprawdzaniu znaczników czasu może być nadal wykonywana stara wersja. Po oczyszczeniu należy więc wykonać restart.
3. **Wspólna pamięć wymaga rozdzielenia.** Na serwerach z wieloma klientami pomagają osobne pule PHP-FPM dla każdej strony oraz `opcache.validate_permission` i `opcache.restrict_api`. Katalog dla `opcache.file_cache` może być zapisywalny tylko dla użytkownika PHP.

> **Wskazówka:**
> Proszę po każdej aktualizacji sprawdzić, czy czas startu procesów PHP przypada po aktualizacji. W pełni wypełniony OPcache z wysokim współczynnikiem trafień nie jest dowodem, że działa nowy interpreter.

## Jak konkretnie pomaga PHP SOS?

- **Sprawdzenie konfiguracji:** Odczytujemy aktywną konfigurację OPcache dla każdego trybu pracy i porównujemy ją z Państwa aplikacją.
- **Zabezpieczenie wdrożeń:** Ustanawiamy stałą procedurę resetu pamięci podręcznej i restartu, aby nie działała dalej stara wersja kodu.
- **Rozdzielenie klientów:** W ramach [utwardzania serwera](https://phpsos.de/pl/leistungen/server-haertung/) ustawiamy oddzielne pule, `restrict_api` i odpowiednie uprawnienia.
- **Kontrola po aktualizacjach:** Na podstawie czasów startu procesów dowodzimy, że zaktualizowany interpreter rzeczywiście jest aktywny.


## Częste pytania

**Czy OPcache jest domyślnie aktywny?**  
OPcache jest dostarczany z PHP od wersji 5.5.0 i według podręcznika działa domyślnie z opcache.enable=1, o ile rozszerzenie jest załadowane. To, czy jest załadowane, zależy od Państwa pakietu lub dostawcy hostingu. W wierszu poleceń OPcache jest natomiast domyślnie wyłączony (opcache.enable_cli=0).

**Dlaczego po wdrożeniu nadal widzę stary kod?**  
Prawdopodobnie OPcache sprawdza zmiany plików tylko w odstępach albo wcale. Z opcache.revalidate_freq czeka domyślnie dwie sekundy, z opcache.validate_timestamps=0 nigdy. Wtedy pomaga tylko reset pamięci podręcznej albo restart PHP-FPM lub Apache.

**Czy opcache_reset() wystarcza po aktualizacji PHP?**  
Nie. opcache_reset() opróżnia tylko pamięć podręczną z przetłumaczonymi skryptami. Aktualizacja PHP wymienia sam interpreter, a ten jest załadowany w każdym działającym procesie. W tym celu trzeba zrestartować wszystkie procesy PHP.

**Czy JIT w PHP 8.4 jest włączony?**  
Według podręcznika opcache.jit jest od PHP 8.4.0 domyślnie ustawione na disable, a opcache.jit_buffer_size wynosi 64M. Wcześniej było odwrotnie: jit na tracing, bufor na 0. W obu przypadkach JIT bez świadomej konfiguracji nie jest aktywny.

## Źródła

- [Podręcznik PHP: OPcache](https://www.php.net/manual/en/book.opcache.php)
- [Podręcznik PHP: konfiguracja OPcache](https://www.php.net/manual/en/opcache.configuration.php)
- [Podręcznik PHP: instalacja OPcache](https://www.php.net/manual/en/opcache.installation.php)
- [PHP RFC: JIT](https://wiki.php.net/rfc/jit)
