# display_errors off: wyłączanie komunikatów błędów w produkcji

> display_errors Off i więcej: jakie ustawienia PHP chronią działającą stronę przed wyświetlaniem błędów, co dodają frameworki i jak sprawdzić wycieki.

Źródło: https://phpsos.de/pl/blog/display-errors-produktion/  
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:** Na działającej stronie `display_errors = Off` należy do php.ini, razem z `display_startup_errors = Off`, `log_errors = On` i logiem błędów poza katalogiem głównym strony. Dodatkowo systemy CMS i frameworki muszą działać w trybie produkcyjnym, w przeciwnym razie ich własne strony błędów pokazują szczegóły. Zablokowane przez `php_admin_flag` i sprawdzane po każdej aktualizacji, błędy zostają w logu, a nie w przeglądarce.

## Co zdradza pojedynczy komunikat błędu

Ostrzeżenie na górze strony, „Fatal error” zamiast podsumowania zamówienia: takie wyświetlenia wyglądają niewinnie. Dla atakującego są mapą. Pokazują pełne ścieżki plików, nazwy baz danych i tabel, używane biblioteki, a często także wersję PHP.

Właśnie w sytuacjach takich jak PHP2Shell, gdy masowo szuka się podatnych serwerów, serwer powinien zdradzać o sobie jak najmniej. Nie zamyka to luki w interpreterze PHP, ale utrudnia każdy kolejny krok po włamaniu i czyni celowane ataki na Państwa aplikację mozolniejszymi.

Dochodzi ochrona danych. Komunikaty błędów mogą zawierać fragmenty żądań, na przykład adresy e-mail z formularzy. To, co pojawia się w przeglądarce odwiedzającego, nie jest już pod Państwa kontrolą.

## Wartości domyślne nie są przeznaczone do produkcji

Wielu zakłada, że PHP samo ukrywa błędy. Podręcznik PHP mówi coś innego: wbudowana wartość domyślna `display_errors` to 1, a `display_startup_errors` jest od PHP 8.0 również domyślnie włączone. Dopiero dołączony szablon `php.ini-production` ustawia oba na Off. Podręcznik wyraźnie nazywa `display_errors` funkcją deweloperską, której nigdy nie należy używać w systemach dostępnych w internecie.

To, czy Państwa serwer używa szablonu produkcyjnego, nie jest oczywiste. Obrazy kontenerów startują częściowo w ogóle bez php.ini, panele hostingu ustawiają własne wartości, a po przeprowadzce chętnie kopiuje się szablon deweloperski.

## display_errors off: ustawienia w skrócie

Poniższe wartości są sensowne dla serwerów produkcyjnych. Stałe takie jak `E_ALL` działają tylko w php.ini; w konfiguracji Apache nie mają według podręcznika PHP znaczenia i trzeba podawać je jako liczbę.

| Ustawienie | Produkcja | Cel |
|---|---|---|
| `display_errors` | `Off` | brak błędów w przeglądarce |
| `display_startup_errors` | `Off` | brak błędów przy starcie PHP w wyjściu |
| `log_errors` | `On` | zapisywanie błędów do dziennika |
| `error_log` | ścieżka poza katalogiem głównym strony | osobny plik logu dla każdej strony lub puli |
| `error_reporting` | `E_ALL` | rejestrować wszystkie błędy, nie wyświetlać |
| `html_errors` | `Off` | zwykły tekst zamiast HTML w dziennikach |
| `zend.exception_ignore_args` | `On` | brak argumentów funkcji w śladach stosu |
| `fatal_error_backtraces` | `0` do aktualizacji (tylko PHP 8.5) | środek przejściowy według php.net |

`zend.exception_ignore_args` jest szczególnie cenne. Bez tego ustawienia ślady stosu w logach i na stronach błędów mogą zawierać argumenty wywołań funkcji, a więc także hasła lub tokeny, które właśnie były przetwarzane.

```ini
; php.ini SAPI WWW
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php/website-fehler.log
error_reporting = E_ALL
html_errors = Off
zend.exception_ignore_args = On
; tylko PHP 8.5, środek przejściowy do aktualizacji do 8.5.12:
; fatal_error_backtraces = 0
```

W puli FPM najważniejsze wartości blokuje się dodatkowo, aby żadna aplikacja nie włączyła ich ponownie przez `ini_set()`:

```ini
; np. /etc/php/8.3/fpm/pool.d/seite1.conf
php_admin_flag[display_errors] = off
php_admin_flag[display_startup_errors] = off
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/log/php/seite1-fehler.log
```

Następnie zrestartować odpowiednią usługę PHP. Jak dokładnie działa blokowanie, wyjaśnia artykuł [php_admin_value: blokowanie ustawień przed nadpisaniem](https://phpsos.de/pl/blog/php-admin-value-sperren/). Pełną konfigurację podstawową znajdą Państwo w artykule [Bezpieczna konfiguracja php.ini](https://phpsos.de/pl/ratgeber/php-ini-sicher-konfigurieren/).

## Drugi przełącznik: tryb debugowania aplikacji

PHP to tylko połowa sprawy. Nowoczesne frameworki same przechwytują błędy i pokazują własne, często bardzo szczegółowe strony błędów. W trybie debugowania zawierają fragmenty kodu źródłowego, wartości konfiguracji, a czasem zmienne środowiskowe. Strony te pojawiają się nawet wtedy, gdy `display_errors` w PHP jest wyłączone.

Dlatego proszę sprawdzić dla każdej aplikacji jej własny przełącznik. W WordPress są to `WP_DEBUG` i `WP_DEBUG_DISPLAY` w `wp-config.php`, w Laravel i Symfony `APP_DEBUG` oraz środowisko w pliku `.env`, w innych systemach tryb produkcyjny według dokumentacji producenta. W systemie produkcyjnym tryb debugowania ma być wyłączony na stałe, także „tylko na chwilę dla testu” jest ryzykiem.

Jak w aplikacji poprawnie obsługiwać błędy, zamiast je tłumić, opisuje artykuł [Błędy i wyjątki w PHP](https://phpsos.de/pl/php/fehler-und-exceptions/).

## Jak znaleźć wyświetlane błędy, zanim zrobią to inni

Jednorazowe ustawienie nie wystarczy. Wyświetlanie błędów wraca po aktualizacjach, przeprowadzkach lub zmianach w panelu. Pomaga krótki przebieg kontrolny:

1. Sprawdzić obowiązujące wartości w kontekście WWW, nie tylko w wierszu poleceń, na przykład krótko umieszczonym i zaraz usuniętym plikiem testowym.
2. Skontrolować tryb debugowania każdej aplikacji w jej pliku konfiguracyjnym.
3. Przeszukać dostarczane strony pod kątem typowych tekstów błędów, jak w bloku kodu poniżej.
4. W wyszukiwarce zapytaniem `site:` na Państwa domenę szukać pojęć takich jak „Fatal error” lub „Warning”.
5. Sprawdzić, czy log błędów jest zapisywany i czy nie leży w katalogu głównym strony.

```bash
# Przeszukać dostarczane strony pod kątem tekstów błędów PHP (tylko własne domeny)
for url in https://www.example.de/ https://www.example.de/kontakt/; do
  curl -s "$url" | grep -E -o "(Fatal error|Warning|Notice|Deprecated|Stack trace)[^<]{0,80}" | head -3
done
# Czy log błędów jest zapisywany?
ls -l /var/log/php/
```

> **Ważne:**
> Ukrywanie błędów nie zastępuje ich naprawiania. Log pełen ostrzeżeń to wskazówka, że potrzebna jest konserwacja, a po włamaniu jest często ważnym śladem. Co przy tym rejestrować, a czego nie, opisuje artykuł [Bezpieczne logowanie: rejestrowanie błędów bez wycieku danych](https://phpsos.de/pl/blog/sicher-loggen-php/).

## Wniosek: cicho w przeglądarce, wylewnie w logu

Zasada dla serwerów produkcyjnych jest prosta: błędy należą do dziennika, a nie na stronę. W praktyce przeszkadzają jej wartości domyślne nieprzeznaczone do produkcji, przełączniki debugowania w aplikacjach i konfiguracje, które po aktualizacjach lub przeprowadzkach wracają do stanu pierwotnego.

Kto wyłącza `display_errors` i `display_startup_errors`, blokuje wartości w puli, kontroluje tryb debugowania aplikacji i regularnie sprawdza wynik, zamyka jedno z najczęstszych źródeł niepotrzebnego ujawniania informacji. Nakład jest niewielki, a efekt trwa, dopóki kontrola pozostaje częścią każdej aktualizacji.

Jednego nie należy przeoczyć: log błędów nie jest koszem na śmieci. Kto go regularnie czyta, rozpoznaje błędne aktualizacje, przestarzałe funkcje, a czasem także pierwsze ślady ataku, na długo zanim klienci cokolwiek zauważą.

## Jak konkretnie pomaga PHP SOS?

- **Sprawdzenie:** odczytujemy obowiązujące ustawienia błędów dla każdej strony i puli oraz przeszukujemy dostarczane strony pod kątem wyświetlanych błędów.
- **Przestawienie:** ustawiamy PHP i aplikacje na tryb produkcyjny i blokujemy je przed nadpisaniem.
- **Konfiguracja dzienników:** logi błędów leżą poza katalogiem głównym strony, są rotowane i dostępne dla Państwa programistów.
- **Utrzymanie na stałe:** w ramach [umowy serwisowej bezpieczeństwa](https://phpsos.de/pl/leistungen/security-wartungsvertrag/) po każdej aktualizacji sprawdzamy ustawienia ponownie.


## Częste pytania

**Czy display_errors w PHP nie jest i tak wyłączone?**  
Nie automatycznie. Według podręcznika PHP wbudowana wartość domyślna display_errors to 1. Dopiero dołączony szablon php.ini-production ustawia Off. To, czy Państwa serwer używa tego szablonu, zależy od dystrybucji, panelu lub obrazu kontenera i należy to sprawdzić.

**Czy display_errors = Off wystarczy, gdy WordPress lub Laravel działają w trybie debugowania?**  
Nie. Wiele systemów CMS i frameworków ma własne strony błędów, które niezależnie od PHP mogą wyświetlać szczegóły. Dlatego należy też wyłączyć tryb debugowania aplikacji, na przykład WP_DEBUG_DISPLAY w WordPress lub APP_DEBUG w Laravel i Symfony.

**Dokąd trafiają błędy, gdy nie są już wyświetlane?**  
Przy log_errors = On PHP zapisuje je do pliku wskazanego przez error_log lub do dziennika danego trybu pracy, na przykład logu błędów Apache lub PHP-FPM. Plik powinien leżeć poza katalogiem głównym strony i być regularnie rotowany.

**Co fatal_error_backtraces ma wspólnego z PHP2Shell?**  
Ustawienie istnieje od PHP 8.5 i jest domyślnie aktywne. php.net podaje fatal_error_backtraces=0 z następującym po tym restartem jako jeden ze środków przejściowych dla PHP 8.5, dopóki aktualizacja do 8.5.12 jest jeszcze w toku. Nie zastępuje aktualizacji.

## Źródła

- [Podręcznik PHP: obsługa błędów i logowanie](https://www.php.net/manual/en/errorfunc.configuration.php)
- [Podręcznik PHP: zmiana konfiguracji (php_admin_flag)](https://www.php.net/manual/en/configuration.changes.php)
- [php.net: komunikaty bezpieczeństwa](https://www.php.net/)
- [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/)
