Aktualna sytuacja: PHP2Shell. Dwie krytyczne luki w PHP (CVSS 9,2) umożliwiają wykonanie złośliwego kodu bez logowania. Poprawki od 21.10.2026.Co należy teraz zrobić →

OPcache wyjaśniony: pamięć podręczna bajtkodu PHP

OPcache trzyma przetłumaczony kod PHP we wspólnej pamięci. Oszczędza to moc obliczeniową, ale wymaga staranności przy wdrożeniach, restartach i na serwerach z wieloma klientami.

Stan 4 min czytaniaWiedza o PHP

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. 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:

; 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:

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
$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.

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.
  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 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

Kontakt natychmiast

Liczy się każda godzina. Proszę napisać do nas teraz.

Proszę krótko opisać system, wersję PHP i obserwacje. Skontaktujemy się z Państwem, ustalimy sytuację i będziemy pracować zdalnie, aż incydent zostanie zamknięty i udokumentowany.

Natychmiastowa pomoc