Друзья, сегодня мы поговорим о том, что доводит до белого каления каждого, кто хоть раз ковырялся в чужом PHP-коде. Вы открываете сайт, а там — пусто. Белый экран. Ни ошибки, ни намёка, что пошло не так.
Знакомо?
Это классический случай фатальной ошибки PHP, которая просто убивает скрипт и уходит в закат, не попрощавшись. Сегодня мы научимся заставлять PHP говорить, включать логи и находить те самые фатальные ошибки, которые прячутся за «белым экраном смерти».
Почему PHP молчит: немного теории
Для начала давайте разберёмся, как PHP вообще обрабатывает ошибки. Это не просто «ошибка — лог». Там целая иерархия.
В PHP 7+ всё, что может пойти не так, реализует интерфейс Throwable . У него два основных наследника: - Error — внутренние ошибки PHP (фатальные, парсинг, тип данных) - Exception — исключения, которые можно ловить через try-catch
Фатальные ошибки (E_ERROR, E_PARSE, E_CORE_ERROR) — это самый страшный сон разработчика. Они убивают скрипт мгновенно, и стандартные обработчики через set_error_handler() их не ловят . Единственный способ зацепить фатальную ошибку — это использовать register_shutdown_function() .
Но давайте по порядку. Сначала нужно просто включить логи, чтобы они куда-то писались.
Шаг 1. Включаем логирование через php.ini
Самый правильный способ настроить логи — отредактировать конфигурационный файл PHP. Где он лежит — зависит от системы :
| Система | Путь к php.ini |
|---------|----------------|
| Ubuntu/Debian (Apache) | /etc/php/7.x/apache2/php.ini |
| Ubuntu/Debian (CLI) | /etc/php/7.x/cli/php.ini |
| Ubuntu/Debian (PHP-FPM) | /etc/php/7.x/fpm/php.ini |
| CentOS/RHEL | /etc/php.ini или /etc/php.d/ |
| Windows (XAMPP) | C:\xampp\php\php.ini |
| Windows (WAMP) | C:\wamp\bin\php\phpX.X.X\php.ini |
В этом файле нас интересуют следующие директивы :
```ini ; Включаем запись ошибок в лог (обязательно!) log_errors = On
; Указываем путь к файлу лога error_log = /var/log/php_errors.log
; Отключаем вывод ошибок на экран (для продакшена!) display_errors = Off
; Для разработки можно включить, но потом выключи display_startup_errors = Off
; Уровень отчёта — все ошибки error_reporting = E_ALL ```
Важно: для командной строки (CLI) используется свой php.ini, и логи могут писаться в другое место . Если вы тестируете скрипт в консоли, проверьте отдельно.
После изменений нужно перезапустить веб-сервер :
bash
sudo systemctl restart apache2 # для Apache
sudo systemctl restart php7.4-fpm # для PHP-FPM
Что означают эти настройки
- log_errors = On — включает запись ошибок в файл. Если этого не сделать, PHP будет молчать, как партизан .
- error_log — путь к файлу, куда всё писать. Важно, чтобы у веб-сервера (обычно пользователь
www-dataилиapache) были права на запись в этот файл и директорию . - display_errors = Off — на проде обязательно отключаем, чтобы не светить деталями перед пользователями .
- error_reporting = E_ALL — логировать все типы ошибок. Для продакшена можно ограничить, но для отладки лучше видеть всё.
Шаг 2. Альтернатива: включаем логи прямо в коде
Если у вас нет доступа к php.ini (например, на хостинге), можно попытаться включить логирование прямо в скрипте с помощью функции ini_set() .
Вставьте в самое начало проблемного файла:
```php
/dev/null ``` Или создать php-файл с вызовом `phpinfo();` и найти там секцию **error_log**. ## Шаг 4. Читаем логи: инструменты и приёмы Когда логи уже пишутся, нужно научиться их быстро просматривать и фильтровать. ### tail — смотрим последние события ```bash # Последние 50 строк tail -n 50 /var/log/php_errors.log # В реальном времени (как docker logs -f) tail -f /var/log/php_errors.log ``` ### grep — ищем конкретные ошибки ```bash # Только фатальные ошибки grep "Fatal error" /var/log/php_errors.log # Ошибки парсинга (синтаксические) grep "Parse error" /var/log/php_errors.log # Игнорируем регистр grep -i "warning" /var/log/php_errors.log ``` ### less — удобный просмотр с навигацией ```bash less /var/log/php_errors.log ``` Внутри less можно нажимать `/` и вводить слово для поиска, `n` — следующее совпадение, `N` — предыдущее. ### Комбинации — мощный конвейер ```bash # Показать последние 100 строк и искать ошибки tail -n 100 /var/log/php_errors.log | grep -i fatal # Следить и сразу фильтровать tail -f /var/log/php_errors.log | grep --line-buffered "error" # Посчитать количество ошибок по типам grep -o "PHP [A-Za-z]* error" /var/log/php_errors.log | sort | uniq -c ``` ## Шаг 5. Расшифровываем ошибки: что есть что Типичная запись в логе выглядит так : ``` [2026-03-04 14:35:22 UTC] PHP Fatal error: Uncaught Error: Call to undefined function foo() in /var/www/html/index.php on line 10 ``` Разбираем по косточкам: - **Дата и время** — когда случилось - **PHP Fatal error** — уровень ошибки - **Uncaught Error: Call to undefined function foo()** — сообщение - **/var/www/html/index.php:10** — файл и строка Основные уровни ошибок : | Уровень | Что значит | Пример | |---------|------------|--------| | **E_ERROR** / **Fatal error** | Фатальная ошибка, скрипт умирает | Вызов несуществующей функции, нехватка памяти | | **E_WARNING** / **Warning** | Предупреждение, но скрипт жив | include несуществующего файла | | **E_PARSE** / **Parse error** | Синтаксическая ошибка, скрипт не запускается | Пропущена точка с запятой | | **E_NOTICE** / **Notice** | Замечание, обычно не критично | Обращение к неопределённой переменной | | **E_DEPRECATED** | Устаревшая конструкция | Использование mysql_connect() | ## Шаг 6. Ловим фатальные ошибки (самое интересное) Фатальные ошибки — это те, которые не ловятся обычным `set_error_handler()`. Они убивают скрипт мгновенно, и стандартный обработчик просто не успевает сработать . Но есть способ! Используем `register_shutdown_function()` — эта функция вызывается в любом случае, даже при фатальной ошибке . ### Простой обработчик фатальных ошибок ```php getMessage()." | ".$e->getFile().":".$e->getLine()." | $url\n"; file_put_contents($logFile, $msg, FILE_APPEND); }); // Обработчик фатальных ошибок register_shutdown_function(function() use ($logFile) { $error = error_get_last(); if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) { $url = ($_SERVER['HTTP_HOST'] ?? 'CLI') . ($_SERVER['REQUEST_URI'] ?? ''); $msg = "[".date('Y-m-d H:i:s')."] [FATAL] ".$error['message']." | ".$error['file'].":".$error['line']." | $url\n"; file_put_contents($logFile, $msg, FILE_APPEND); } }); ``` Такой код можно вставить в самый начало главного файла (например, `index.php` или `header.php`), и он будет ловить вообще всё . ## Шаг 7. Логи в популярных фреймворках Если вы используете современный фреймворк, там уже всё настроено, но пути к логам другие. ### Laravel Логи хранятся в `storage/logs/laravel.log` . По умолчанию используется Monolog, формат — текст или JSON. Чтобы увидеть ошибки: ```bash tail -f storage/logs/laravel.log ``` ### Symfony Логи по умолчанию: `var/log/dev.log` и `var/log/prod.log` . Тоже Monolog, можно настраивать под себя. ### WordPress По умолчанию WordPress не пишет логи, но можно включить, добавив в `wp-config.php`: ```php define('WP_DEBUG', true); define('WP_DEBUG_LOG', true); define('WP_DEBUG_DISPLAY', false); ``` Логи будут в `/wp-content/debug.log`. ## Шаг 8. Типичные проблемы и их решения ### Проблема: логи не пишутся вообще Что проверить: 1. Точно ли включено `log_errors = On` 2. Есть ли права на запись в файл и директорию 3. Тот ли php.ini вы правили (проверьте через `phpinfo()`) 4. Перезапустили ли веб-сервер после изменений ### Проблема: фатальные ошибки не ловятся Даже с включёнными логами фатальные ошибки иногда не пишутся, если они совсем ранние (например, ошибка парсинга в самом файле, где вы включаете логи). Тут поможет только правильное размещение кода — в самом начале, до всего . ### Проблема: слишком много логов Если на проде включено `E_ALL`, логи будут расти как на дрожжах. Настройте `error_reporting` разумно : ```ini error_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE ``` ### Проблема: логи забивают диск Настройте ротацию логов через `logrotate` . Конфиг для PHP-логов: ``` /var/log/php_errors.log { daily rotate 30 compress delaycompress missingok notifempty create 644 www-data www-data } ``` ## Шаг 9. Практический пример: расследуем белую страницу Представим ситуацию: открываете сайт, а там пусто. Что делать по шагам: 1. **Смотрим логи веб-сервера** (Apache/Nginx) — часто там есть подсказка 2. **Смотрим PHP-логи** — ищем записи за последние минуты ```bash tail -n 50 /var/log/php_errors.log | grep -A5 -B5 "$(date +%Y-%m-%d)" ``` 3. **Видим ошибку**: ``` [2026-03-04 15:30:22] PHP Fatal error: Uncaught Error: Class 'DB' not found in /var/www/site/index.php on line 12 ``` 4. **Открываем файл**, смотрим строку 12 — действительно, забыли подключить класс. 5. **Исправляем**, проверяем — сайт работает. Магия! ## Коротко: шпаргалка | Действие | Команда / код | |----------|---------------| | Включить логи в php.ini | `log_errors = On` + `error_log = /путь/к/файлу` | | Включить в коде | `ini_set('log_errors', 'On');` | | Смотреть последние строки | `tail -f /var/log/php_errors.log` | | Искать фатальные ошибки | `grep "Fatal error" /var/log/php_errors.log` | | Ловить фатальные ошибки | `register_shutdown_function()` + `error_get_last()` | | Где лежат логи Laravel | `storage/logs/laravel.log` | | Где лежат логи Symfony | `var/log/dev.log` и `var/log/prod.log` | ## Вместо заключения PHP не так страшен, как его малюют. Да, белый экран смерти — это жутко, но за ним всегда стоит конкретная ошибка, которая просто не хочет говорить. Научитесь включать логи, и PHP заговорит. Главные правила: - На проде **всегда** включайте `log_errors` и отключайте `display_errors` - Пишите логи в отдельный файл, а не в syslog — так проще искать - Для ловли фатальных ошибок используйте `register_shutdown_function` - Регулярно смотрите логи — хотя бы раз в день И помните: идеальный код не пишет ошибок. Но если ошибка случилась, пусть она хотя бы оставит записку. ?>