# display_errors off: изключване на изхода на грешки в продукция

> display_errors Off и още: кои настройки на PHP държат грешките далеч от живия сайт, какво добавят рамките и как да проверите за изтичане на информация.

Източник: https://phpsos.de/bg/blog/display-errors-produktion/  
Актуалност: 25.10.2026  
Доставчик: PHP SOS, Спешна помощ за PHP и сигурност на сървъри. Незабавна помощ по WhatsApp: https://wa.me/491736494914?text=%D0%97%D0%B4%D1%80%D0%B0%D0%B2%D0%B5%D0%B9%D1%82%D0%B5%2C%20PHP%20SOS%2C%20%D0%B8%D0%BC%D0%B0%D0%BC%D0%B5%20%D0%BD%D1%83%D0%B6%D0%B4%D0%B0%20%D0%BE%D1%82%20%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%20%D1%81%20%D0%BD%D0%B0%D1%88%D0%B8%D1%8F%20PHP%20%D1%81%D1%8A%D1%80%D0%B2%D1%8A%D1%80.%20%D0%A4%D0%B8%D1%80%D0%BC%D0%B0%3A%20%E2%80%A6%20%D0%A3%D0%B5%D0%B1%D1%81%D0%B0%D0%B9%D1%82%3A%20%E2%80%A6

**Накратко:** На жив сайт `display_errors = Off` принадлежи в php.ini, заедно с `display_startup_errors = Off`, `log_errors = On` и лог за грешки извън уеб корена. Освен това CMS и рамките трябва да работят в продукционен режим, иначе собствените им страници с грешки показват подробностите. Заключени с `php_admin_flag` и проверявани след всяка актуализация, грешките остават в лога, а не в браузъра.

## Какво издава едно-единствено съобщение за грешка

Предупреждение в горния край на страницата, „Fatal error" вместо прегледа на поръчката: такива изходи изглеждат безобидни. За атакуващия те са карта. Те показват пълни пътища до файлове, имена на бази данни и таблици, използвани библиотеки и често версията на PHP.

Особено в положения като PHP2Shell, когато масово се търсят уязвими сървъри, един сървър трябва да издава възможно най-малко за себе си. Това не затваря уязвимост в интерпретатора на PHP, но затруднява всяка следваща стъпка след пробив и прави целенасочените атаки срещу Вашето приложение по-трудни.

Към това се добавя защитата на данните. Съобщенията за грешки могат да съдържат части от заявки, например имейл адреси от формуляри. Което се появи в браузъра на посетител, вече не е под Вашия контрол.

## Стойностите по подразбиране не са предвидени за продукция

Мнозина предполагат, че PHP сам скрива грешките. Ръководството на PHP казва друго: вградената стойност по подразбиране на `display_errors` е 1, а `display_startup_errors` е от PHP 8.0 също включен по подразбиране. Едва доставеният шаблон `php.ini-production` задава и двете на Off. Ръководството изрично нарича `display_errors` функция за разработка, която никога не бива да се използва на системи в интернет.

Дали Вашият сървър ползва продукционния шаблон, не е очевидно. Образите на контейнери понякога стартират изцяло без php.ini, хостинг панелите задават собствени стойности, а след преместване обичайно се копира шаблонът за разработка.

## display_errors off: преглед на настройките

Следните стойности са смислени за продукционни сървъри. Константи като `E_ALL` работят само в php.ini; в конфигурацията на Apache те според ръководството на PHP нямат значение и трябва да се задават като число.

| Настройка | Продукция | Цел |
|---|---|---|
| `display_errors` | `Off` | без грешки в браузъра |
| `display_startup_errors` | `Off` | без грешки при стартиране на PHP в изхода |
| `log_errors` | `On` | записване на грешките в протокола |
| `error_log` | път извън уеб корена | собствен лог файл за всеки сайт или пул |
| `error_reporting` | `E_ALL` | протоколиране на всички грешки, без показване |
| `html_errors` | `Off` | чист текст вместо HTML в протоколите |
| `zend.exception_ignore_args` | `On` | без аргументи на функции в stack trace |
| `fatal_error_backtraces` | `0` до актуализацията (само PHP 8.5) | преходна мярка според php.net |

`zend.exception_ignore_args` е особено ценна. Без тази настройка stack trace в логовете и на страниците с грешки могат да съдържат аргументите на извикванията на функции, тоест и пароли или токени, които тъкмо са се обработвали.

```ini
; php.ini на уеб SAPI
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
; само PHP 8.5, преходна мярка до актуализацията до 8.5.12:
; fatal_error_backtraces = 0
```

В пула на FPM заключвате най-важните стойности допълнително, за да не ги включи отново никое приложение чрез `ini_set()`:

```ini
; напр. /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
```

След това рестартирайте съответната PHP услуга. Как точно работи заключването, обяснява статията [php_admin_value: заключване на настройки срещу презаписване](https://phpsos.de/bg/blog/php-admin-value-sperren/). Пълна основна конфигурация ще намерите в [Сигурна конфигурация на php.ini](https://phpsos.de/bg/ratgeber/php-ini-sicher-konfigurieren/).

## Вторият превключвател: режимът за отстраняване на грешки на приложението

PHP е само половината работа. Съвременните рамки сами прихващат грешките и показват собствени, често много подробни страници с грешки. В режим на отстраняване на грешки те съдържат откъси от изходния код, конфигурационни стойности и понякога променливи на средата. Тези страници се появяват дори когато `display_errors` в PHP е изключен.

Затова проверете за всяко приложение собствения му превключвател. При WordPress това са `WP_DEBUG` и `WP_DEBUG_DISPLAY` в `wp-config.php`, при Laravel и Symfony `APP_DEBUG` и средата във файла `.env`, при други системи продукционният режим според документацията на производителя. На жива система режимът за отстраняване на грешки трябва да е изключен трайно, дори „само за кратко за тест" е риск.

Как грешките в приложението се обработват чисто, вместо да се потискат, описва [Грешки и изключения в PHP](https://phpsos.de/bg/php/fehler-und-exceptions/).

## Така откривате изхода на грешки, преди други да го направят

Еднократната настройка не е достатъчна. Изходът на грешки се връща след актуализации, преместване или промени в панела. Помага кратък ред на проверка:

1. Проверете действащите стойности в уеб контекст, не само в командния ред, например с проверочен файл, поставен за кратко и изтрит веднага след това.
2. Проверете режима за отстраняване на грешки на всяко приложение в неговия конфигурационен файл.
3. Претърсете върнатите страници за типични текстове на грешки, както в кодовия блок по-долу.
4. Потърсете в търсачката със заявка `site:` към Вашия домейн за термини като „Fatal error" или „Warning".
5. Проверете дали лог файлът за грешки се пише и дали не е в уеб корена.

```bash
# Претърсване на върнатите страници за текстове на грешки на PHP (само собствени домейни)
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
# Пише ли се лог файлът за грешки?
ls -l /var/log/php/
```

> **Важно:**
> Скриването на грешките не е заместител на тяхното отстраняване. Лог, пълен с предупреждения, е знак за нужда от поддръжка, а след пробив често е важна следа. Какво протоколирате при това и какво не, описва [Сигурно протоколиране: записване на грешки без изтичане на данни](https://phpsos.de/bg/blog/sicher-loggen-php/).

## Извод: тихо в браузъра, словоохотливо в лога

Правилото за продукционни сървъри е просто: грешките принадлежат в протокола, не на сайта. На практика то се проваля заради стойности по подразбиране, които не са предвидени за продукция, заради превключватели за отстраняване на грешки в приложенията и заради конфигурации, които се връщат назад след актуализации или преместване.

Който изключи `display_errors` и `display_startup_errors`, заключи стойностите в пула, провери режима за отстраняване на грешки на приложението и редовно проверява резултата, затваря един от най-честите източници на ненужно разкриване на информация. Усилието е малко, ефектът трае, докато проверката остава част от всяка актуализация.

Един момент не бива да се изпуска: лог файлът за грешки не е кош за боклук. Който го чете редовно, разпознава неуспешни актуализации, остарели функции и понякога и първите следи от атака, много преди клиентите да забележат нещо.

## Как помага PHP SOS конкретно?

- **Проверка:** прочитаме действащите настройки за грешки за всеки сайт и пул и претърсваме върнатите страници за изход на грешки.
- **Превключване:** задаваме настройките на PHP и приложението за продукционна работа и ги заключваме срещу презаписване.
- **Настройка на протоколите:** логовете за грешки са извън уеб корена, ротират се и са достъпни за Вашите разработчици.
- **Трайно поддържане:** в [договора за поддръжка на сигурността](https://phpsos.de/bg/leistungen/security-wartungsvertrag/) проверяваме настройките наново след всяка актуализация.


## Често задавани въпроси

**Не е ли display_errors в PHP така или иначе изключен?**  
Не автоматично. Според ръководството на PHP вградената стойност по подразбиране на display_errors е 1. Едва доставеният шаблон php.ini-production задава Off. Дали Вашият сървър ползва този шаблон, зависи от дистрибуцията, панела или образа на контейнера и трябва да се провери.

**Достатъчно ли е display_errors = Off, ако WordPress или Laravel работят в режим на отстраняване на грешки?**  
Не. Много CMS и рамки носят собствени страници с грешки, които могат да показват подробности независимо от PHP. Затова изключете и режима за отстраняване на грешки на приложението, например WP_DEBUG_DISPLAY при WordPress или APP_DEBUG при Laravel и Symfony.

**Къде отиват грешките, когато вече не се показват?**  
С log_errors = On PHP ги записва във файла, посочен от error_log, или в протокола на съответния режим на работа, например лога за грешки на Apache или PHP-FPM. Файлът трябва да е извън уеб корена и да се ротира редовно.

**Какво общо има fatal_error_backtraces с PHP2Shell?**  
Настройката съществува от PHP 8.5 и е активна по подразбиране. php.net посочва fatal_error_backtraces=0 с последващо рестартиране като една от преходните мерки за PHP 8.5, докато актуализацията до 8.5.12 още предстои. Тя не замества актуализацията.

## Източници

- [Ръководство на PHP: обработка на грешки и протоколиране](https://www.php.net/manual/en/errorfunc.configuration.php)
- [Ръководство на PHP: промяна на конфигурацията (php_admin_flag)](https://www.php.net/manual/en/configuration.changes.php)
- [php.net: Съобщения за сигурност](https://www.php.net/)
- [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/)
