Статьи

Отображать ошибки на экране даже с ошибками отображения = выключено с помощью PHP

В прошлом месяце я был в сеансе кодирования ката, играя с StingCalculator , и между итерациями и итерациями мы занимались проблемами общих хостингов. Общий хостинг дешевый, но обычно он не позволяет нам использовать какие-то функции. Например, мы не можем увидеть журнал ошибок . Это проблема, когда нам нужно посмотреть, что происходит в нашем приложении. Обычно я работаю со своими серверами, и у меня есть полный доступ к журналам ошибок. Но если мы не можем увидеть журнал ошибок и сервер настроен с отображением error = off в php.ini (типичная конфигурация на виртуальном хостинге), у нас проблема.

Мне пришло в голову одно сообщение « Мониторинг PHP-приложений в реальном времени с помощью websockets и node.js ». По сути, мы можем решить эту проблему с помощью этой техники, но если мы говорим о разделяемом хостинге без доступа к журналу ошибок, очень вероятно, что мы не сможем установить сервер node.js или даже использовать функции сокетов. Так что это не «реальное» решение нашей проблемы.

Идея состоит в том, чтобы создать вариант оригинального сценария (один из вариантов выделения сценария ;)). В этом scprit мы будем фиксировать ошибки и исключения и показывать их в скрипте в конце скрипта. У нас нет доступа к журналу ошибок, но мы покажем его в браузере.

Представьте себе следующий скрипт:

$a = 1/0;
throw new Exception("myException");
echo "hi";

Будет показано одно предупреждение (1/0) и одно исключение (myException)

  • Предупреждение: деление на ноль
  • Неустранимая ошибка: необработанное исключение «Exception» с сообщением «myException»

Если мы изменим php.ini show errors = off, мы увидим красивый белый экран.

Идея в том, чтобы добавить в скрипт:

include('ErrorSniffer.php');
ErrorSniffer::factory('127.0.0.1');

$a = 1/0;
throw new Exception("myException");
echo "hi";

Теперь с библиотекой ErrorSniffer мы увидим хороший вывод, даже с ошибками отображения = выкл.
Я также добавляю IP в конструктор класса, чтобы ограничить выходное сообщение одним IP. Идея состоит в том, чтобы запустить этот скрипт в производство, поэтому мы не хотим показывать сообщения об ошибках целым пользователям.

Если мы видим исходный код класса ErrorSniffer, то мы конструктор, подобный этому:

public function __construct($restingToIp)
{
    if ($this->getip() == $restingToIp) {
        self::register_exceptionHandler($this);
        self::set_error_handler($this);
        self::register_shutdown_function($this);
    }
}

private static function set_error_handler(ErrorSniffer &$that)
{
    set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$that) {
            $type = ErrorSniffer::getErrorName($errno);
            $that->registerError(array('type' => $type, 'message' => $errstr, 'file' => $errfile, 'line' => $errline));
            return false;
    });
}

private static function register_exceptionHandler(ErrorSniffer &$that)
{
    set_exception_handler(function($exception) use (&$that) {
            $exceptionName = get_class($exception);
            $message = $exception->getMessage();
            $file  = $exception->getFile();
            $line  = $exception->getLine();
            $trace = $exception->getTrace();

            $that->registerError(array('type' => 'EXCEPTION', 'exception' => $exceptionName, 'message' => $message, 'file' => $file, 'line' => $line, 'trace' => $trace));
            return false;
    });
}

private static function register_shutdown_function(ErrorSniffer &$that)
{
    register_shutdown_function(function() use (&$that) {
            $error = error_get_last();

            if ($error['type'] == E_ERROR) {
                $type = ErrorSniffer::getErrorName($error['type']);
                $that->registerError(array('type' => $type, 'message' => $error['message'], 'file' => $error['file'], 'line' => $error['line']));
            }

            $that->printErrors();
    });
}

Как мы видим, мы будем ловить ошибки и исключения, мы заполняем переменную-член $ errors и также используем register_shutdown_function для отображения информации о завершении работы.

Вы можете увидеть полный скрипт на github здесь .

Что вы думаете?