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ć →

Zend Engine: serce PHP

Zend Engine tłumaczy kod PHP na opcody i je wykonuje. Kto zna jej elementy, rozumie, dlaczego luki w rdzeniu, takie jak PHP2Shell, usuwa tylko aktualizacja PHP.

Stan 4 min czytaniaWiedza o PHP

Krótko: Zend Engine to rdzeń PHP. Tłumaczy kod PHP na opcody, wykonuje je w maszynie wirtualnej i zarządza przy tym zmiennymi oraz pamięcią. Od PHP 4 znajduje się w każdej instalacji PHP. Ponieważ luki PHP2Shell tkwią w tym rdzeniu, nie pomagają wtyczki ani aktualizacje CMS, lecz tylko zaktualizowane PHP z restartem.

Czym jest Zend Engine?

Zend Engine to ta część PHP, która wykonuje właściwą pracę. Wszystko inne, na przykład połączenie z serwerem WWW czy rozszerzenia do baz danych, opiera się na niej. Można ją porównać do silnika samochodu: nadwozie i wyposażenie się różnią, a silnik napędza wszystko.

Według podręcznika PHP nazwa powstała z imion twórców, Zeeva Suraskiego i Andiego Gutmansa. Silnik przedstawiono w połowie 1999 roku, a od PHP 4.0, wydanego w maju 2000 roku, był rdzeniem PHP. Od tego czasu był kilkakrotnie gruntownie przepracowywany.

Wersja PHP Silnik Najważniejsza zmiana według podręcznika i RFC
PHP 4.0 (2000) Zend Engine pierwszy wspólny rdzeń, lepsza wydajność
PHP 5.0 (2004) Zend Engine 2.0 nowy model obiektowy
PHP 7.0 (2015) Zend Engine 3.0 PHPNG: bardziej zwarte struktury danych, AST
PHP 8.0 (2020) dalszy rozwój kompilator JIT jako część OPcache

Elementy: kompilator, maszyna wirtualna, pamięć

Silnik pracuje w wyraźnie rozdzielonych etapach. Od PHP 7 według RFC o abstrakcyjnym drzewie składni są to trzy fazy do bajtkodu:

  1. Lexer: rozbija kod źródłowy na tokeny, na przykład słowa kluczowe, nazwy zmiennych i ciągi znaków.
  2. Parser: buduje z tokenów abstrakcyjne drzewo składni (AST), które odwzorowuje strukturę programu.
  3. Kompilator: tworzy z AST tablice op, czyli listy opcodów, po jednej dla każdego pliku i funkcji.
  4. Executor (Zend VM): przetwarza opcody. Według RFC dotyczącego JIT do każdego opcode należy funkcja obsługi, która go wykonuje.
  5. Zarządzanie pamięcią: rezerwuje i zwalnia pamięć dla każdego żądania, pilnując przy tym limitu z memory_limit.

Tokeny skryptu można uwidocznić za pomocą rozszerzenia Tokenizer. To nieszkodliwe i pouczające:

<?php
$code = '<?php $summe = 2 + 3; echo $summe;';
foreach (token_get_all($code) as $token) {
    if (is_array($token)) {
        echo token_name($token[0]), ': ', trim($token[1]), "\n";
    } else {
        echo 'Zeichen: ', $token, "\n";
    }
}

Wyjście pokazuje wpisy takie jak T_VARIABLE: $summe czy T_LNUMBER: 2. Z takimi właśnie elementami parser pracuje dalej.

Jak Zend Engine zarządza zmiennymi?

Według podręcznika każda zmienna PHP leży w kontenerze o nazwie zval. Zawiera typ i wartość oraz informacje zarządcze, w tym licznik referencji (refcount). Licznik wskazuje, ile nazw zmiennych wskazuje na ten sam kontener.

<?php
$a = str_repeat('x', 10);
$b = $a;        // brak kopiowania, obie wskazują na tę samą wartość
$b .= 'y';      // dopiero teraz następuje kopiowanie (copy on write)
unset($a);      // licznik maleje, pamięć zostaje zwolniona, gdy osiągnie 0

Gdy licznik osiąga zero, silnik zwalnia pamięć. Dla odwołań cyklicznych między obiektami istnieje dodatkowo garbage collector. Więcej w artykule Zarządzanie pamięcią w PHP.

Przepracowanie PHPNG dla PHP 7 dotyczyło właśnie tego miejsca. Według RFC autorstwa Dmitrego Stogova i Zeeva Suraskiego chodziło o bardziej zwarte struktury danych i zręczniejszą reprezentację wartości. RFC podawał wzrost wydajności od 20 do 110 procent w rzeczywistych aplikacjach.

OPcache i JIT: rozszerzenia silnika

Bez pamięci podręcznej silnik tłumaczy każdy skrypt od nowa przy każdym żądaniu. OPcache trzyma gotowe opcody we wspólnej pamięci. Od PHP 8.0 istnieje dodatkowo kompilator JIT. Według RFC opiera się na DynASM, narzędziu z projektu LuaJIT, i tworzy kod maszynowy bezpośrednio z bajtkodu. Maszyna wirtualna pozostaje przy tym niezmieniona; JIT zastępuje tylko punkty wejścia funkcji obsługi.

Dla operatorów oznacza to: OPcache i JIT przyspieszają silnik, ale nie zmieniają jego zachowania w razie błędów. Luka w rdzeniu pozostaje także przy aktywnej pamięci podręcznej.

Dlaczego luki w silniku są szczególnie poważne

Obie luki PHP2Shell tkwią w rdzeniu PHP. W przypadku CVE-2026-109618 stan braku pamięci (out of memory) może przerwać silnik, gdy dane żądania są dopiero częściowo zainicjowane; przy sprzątaniu nieprawidłowe dane są wtedy traktowane jako prawidłowe. W przypadku CVE-2026-109619 wewnętrzny stan pozostaje po zwolnieniu pamięci i może zostać użyty przez późniejsze żądanie w tym samym workerze.

Poprawione wersje 8.5.12, 8.4.27, 8.3.36 i 8.2.35 zmieniają według podręcznika PHP także zachowanie limitu pamięci: memory_limit jest tam limitem miękkim, a nowe ustawienie memory_hard_limit_percent określa twardą górną granicę. Podręcznik zwraca uwagę, że wersja, która tego ustawienia nie zna, jest dotknięta lukami. W dystrybucjach z backportami dodatkowo liczy się changelog pakietu.

Ważne

Silnik jest załadowany w każdym procesie PHP. Po aktualizacji należy więc zrestartować wszystkie workery PHP-FPM, procesy Apache z mod_php i pozostałe usługi PHP.

Co dzieje się wewnątrz przy braku pamięci, opisuje artykuł memory_limit i out of memory. Ocenę samej luki podajemy na stronie CVE-2026-109618.

Jak konkretnie pomaga PHP SOS?

  • Sprawdzenie wersji i stanu pakietów: Ustalamy, jaki stan silnika faktycznie działa, łącznie z backportami Państwa dystrybucji.
  • Aktualizacja i restart: W ramach usługi PHP Patch Service instalujemy aktualizację i kontrolujemy, że nie został żaden proces ze starym kodem.
  • Sensowne ustawienie limitów pamięci: Dopasowujemy memory_limit, nowy limit twardy i limity cgroup do Państwa aplikacji.
  • Badanie nieprawidłowości: Awarie workerów lub procesy ze statusem wyjścia 137 oceniamy i sprawdzamy, czy może za nimi stać atak.

Częste pytania

Skąd Zend Engine ma swoją nazwę?

Nazwa składa się z imion jej twórców: Zeeva Suraskiego i Andiego Gutmansa. Według podręcznika PHP silnik przedstawiono w połowie 1999 roku, a od PHP 4.0 w maju 2000 roku był rdzeniem PHP.

Czy Zend Engine to odrębny produkt, który muszę zainstalować?

Nie. Zend Engine jest stałym składnikiem każdej instalacji PHP. Kto aktualizuje PHP, automatycznie aktualizuje także silnik. Z komercyjnymi produktami firmy Zend nie ma to nic wspólnego.

Czym jest opcode?

Opcode to pojedyncze polecenie dla maszyny wirtualnej PHP, na przykład dodawanie, wywołanie funkcji lub przypisanie. Kompilator tłumaczy każdy skrypt na ciąg takich poleceń, które silnik następnie wykonuje.

Co Zend Engine ma wspólnego z memory_limit?

Silnik zarządza pamięcią każdego żądania i pilnuje przy tym limitu z memory_limit. Od wydań bezpieczeństwa z 21.10.2026 limit ten jest według podręcznika limitem miękkim, uzupełnionym limitem twardym przez memory_hard_limit_percent.

Ź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