Best-club - портал хорошего настроения!
→◊ Библиотека ◊←
Меню сайта
  • Драмы
  • Ужасы
  • Фэнтези
  • Боевики
  • Мистика
  • Комедии
  • Триллеры
  • Мелодрамы
  • Фантастика
  • Мультфильмы
  • Приключения
  • Связь с админом
  • Список пользователей
  • Полная статистика сайта
  • ТОП наград
  • Переводчик
  • Конвертер величин
  • Проверка правописания
  • Раздача ICQ
  • Оставить отзыв о сайте
  • Раскрутка сайтов

  • Поиск по сайту
    Введите ключевое слово
    для поиска



    Статистика сайта




    ProfiSmart TOP webgari.com Рейтинг сайтов

    Каталог сайтов

    bodr_top
    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0

    Зарегистрировано:
    Всего: 1117
    Парней: 1070
    Девушек: 47
    Последний: molodoo

    Облако тегов
    Важная информация
    Главная » Статьи » Wap/Web Мастеру » PHP, Perl, ASP

    Ловля ошибок в php
    На серъезных сайтах странно видеть, когда ошибки выводятся пользователю в браузер в самых неожиданных местах. Почему они появляются - это отдельный разговор. Но почему они выводятся ? Ведь текст ошибок является информацией для дебага и предназначена для разработчика, а не для клиента. 

    Кроме того, именно эта служебная информация обычно помогает злым хакерам ломать сайт. В качестве классического примера можно привести вариант с выводом запроса при ошибке: "you have an error in query near WHERE id= "... Большое спасибо. Подставляем после "WHERE id=..." строку "0 OR 1>0" и запрос выполняется по всей таблице. Если запрос на удаление, то...сами понимаете, весело =). Поэтому я всегда переменные в запросах заключаю в кавычки. На всякий случай... 

    Но я увлекся. Сегодня не об этом. Сегодня поговорим о том, как избежать вывода ошибок клиенту, сохранив при этом все сообщения вебмастеру на память. 

    Начнем, пожалуй, с краткого обзора видов ошибок в РНР.
    Таблица 1. Описания ошибок в PHP4 (оригинальный список)
    Числовое
    значение Константа Описание Ловится/нет
    1 E_ERROR Фатальные ошибки. Например, ошибка при обращении к памяти. Выполнение скрипта при этом прерывается. нет
    2 E_WARNING Предупреждения (не фатальные ошибки). Выполнение скрипта не прерывается. да
    4 E_PARSE Ошибки во время анализа синтаксиса. Генерируются парсером. нет
    8 E_NOTICE Замечания (менее серьезные ошибки, чем предупреждения). Указывают на ситуацию, которая может стать причиной более серьезной ошибки, но могут случаться и в процессе нормальной работы скрипта. да
    16 E_CORE_ERROR Ошибки во время загрузки РНР. Аналог E_ERROR, генерируется ядром РНР. нет
    32 E_CORE_WARNING Предупреждения во время загрузки РНР Аналог E_WARNING, генерируется ядром РНР. нет
    64 E_COMPILE_ERROR Фатальные ошибки во время компиляции кода. Аналог E_ERROR, генерируется зендовским движком. нет
    128 E_COMPILE_WARNING Предупреждения во время компиляции кода. Аналог E_WARNING, генерируется зендовским движком. нет
    256 E_USER_ERROR Пользовательская ошибка. да
    512 E_USER_WARNING Пользовательское предупреждение. да
    1024 E_USER_NOTICE Пользовательское замечание да


    Нас интересуют те ошибки, которые мы можем перехватить. К ним относятся: E_WARNING, E_NOTICE и E_USER_*. Остальные виды ошибок перехвату не поддаются либо из-за того, что происходят они еще до окончания загрузки самого ядра РНР, либо из-за того, что происходят на этапе синтаксического анализа и компилирования РНР-кода, поэтому их вывод придется просто отключить:
    ini_set('display_errors',0);

    Но я предполагаю, что наши скрипты достаточно отлажены, чтобы в них не было элементарных синтаксических ошибок, поэтому потерять мы ничего не должны. 

    По умолчанию уровень ошибок в РНР имеет значение E_ALL & ~E_NOTICE (или 2039 в числовой форме), что означает, что мы пропускаем мимо ушей замечания, но сообщаем о всех остальных ошибках. 

    Кстати, сами разработчики рекомендуют включать на стадии разработки и E_NOTICE - помогает обнаружить потенциально опасные места. 

    Поэтому изменим уровень вывода ошибок на E_ALL: 
    error_reporting(E_ALL);

    Теперь переопределим хэндлер ошибок и подставим вместо него нашу функцию user_log(), которая и будет заниматься теперь обработкой ошибок:
    set_error_handler('user_log');

    Рассмотрим эту функцию подробней. Ей передаются 5 параметров:
    код ошибки 
    текст ошибки 
    имя файла, в котором произошла ошибка 
    строка в файле 
    массив переменных 

    Возвращать эта функция ничего не обязана. Так как мы собираемся просматривать потом лог ошибок, то надо сделать запись лога, например, в файл так, чтобы нам потом было удобно с ним работать. 

    Итак, код с комментариями: 

    /* Наша функция-хэндлер */
    function user_log ($errno, $errmsg, $file, $line) {
      // время события
      $timestamp = time();

      //формируем новую строку в логе
      $err_str = $timestamp.'||';
      $err_str .= $errno.'||'; 
      $err_str .= $file.'||';  
      $err_str .= $line.'||'; 
      $err_str .= $errmsg."n"; 

      //проверка на максимальный размер
      if (is_file(LOG_FILE_NAME) AND filesize(LOG_FILE_NAME)>=(LOG_FILE_MAXSIZE*1024)) {
      //проверяем настройки, если установлен лог_ротэйт,
      //то "сдвигаем" старые файлы на один вниз и создаем пустой лог
      //если нет - чистим и пишем вместо старого лога
      if (LOG_ROTATE===true) {
      $i=1;
      //считаем старые логи в каталоге
      while (is_file(LOG_FILE_NAME.'.'.$i)) { $i++; }
      $i--;
      //у каждого из них по очереди увеличиваем номер на 1
      while ($i>0) {
      rename(LOG_FILE_NAME.'..'.$i,LOG_FILE_NAME. '.' .(1+$i--));
      }
      rename (LOG_FILE_NAME,LOG_FILE_NAME.'.1');
      touch(LOG_FILE_NAME);
      }
      elseif(is_file(LOG_FILE_NAME)) {
      //если пишем логи сверху, то удалим 
      //и создадим заново пустой файл
      unlink(LOG_FILE_NAME);
      touch(LOG_FILE_NAME);
      }
      }

      /*
      проверяем есть ли такой файл
      если нет - можем ли мы его создать
      если есть - можем ли мы писать в него
      */
      if(!is_file(LOG_FILE_NAME)) {
      if (!touch(LOG_FILE_NAME)) {
      return 'can't create log file';
      }
      }
      elseif(!is_writable(LOG_FILE_NAME)) {
      return 'can't write to log file';
      }
       
      //обратите внимание на функцию, которой мы пишем лог.
      error_log($err_str, 3, LOG_FILE_NAME);
    }

    ?>
    Весь код вы можете посмотреть тут или взять все в архиве. 

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

    Собственно, это все. Остальное, я думаю, не составит для вас труда, особенно, если пользоваться функциями file(); & explode();. А если все-таки составит, то вы можете воспользоваться [вот этим кодом]. 

    Предвидя вопрос "почему я не использовал CSV, который, казалось бы, логично использовать в этой ситуации?", отвечаю: сообщения об ошибках могут содержать неизвестное количество служебных символов (ака запятых и точек с запятой), что явно затруднило бы разбор CSV. Да и не собираюсь я просматривать лог в Экселе. 

    Еще разные мысли на эту тему:
    при устаревании лога gz'иповать файл и складывать его в архив; 
    то же, но с посылкой на почту; 
    при возникновении критических ошибок - слать мэйл (см. пример из мануала по функции set_error_handler); 
    для мазохистов можно использовать при этом XML. 

    Вздохнули спокойно? Я надеюсь, что нет. Ибо переопределение еррор-хэндлера - это никак не панацея, просто одна из удобных фич РНР. 

    Кто предупрежден, тот защищен - так ведь? 

    ps Признаю, немного параноидален. Но лучше два раза проверить, чем один раз сделать ошибку. 

    ps2 По просьбе Maxim Naumenko добавляю комменты к статье: 

    Q: Ну и чем это лучше, чем просто в php.ini указать error_log = "log_file.log" ?

    A: Файл пишется в нашем формате. Нам же потом этот файл смотреть надо. Плюс - можно делать что угодно с этими ошибками (файл - это просто для примера). А в случае с error_log = "" - они ТОЛЬКО пишутся в файл и ничего более. Да и не везде вас пустят к php.ini.  

    Категория: PHP, Perl, ASP | Добавил: Admin | Дата: 12.09.2009 | Просмотры: 760 | Рейтинг:
    Всего комментариев: 0
    Добавлять комментарии могут только зарегистрированные пользователи.
    [ Регистрация | Вход ]
    Вход на сайт
    Гость, добро пожаловать на best-club! Тапки в углу, пиво в холодильнике. Располагайся:) Для получения большего комфорта войди как пользователь или зарегистрируйся.



    Обмен музыкой [?]
    Открыть в новом окне

    Партнёры





    Опрос

    Какой номер icq вы хотели бы больше всего?
    Всего ответов: 15

     
    Best-club team © 2008 - 2025

    SiteMap Партнёры и друзья Поддержать проект
    Третий Мир: Война Королей - Форум
    Администрация сайта не несёт ответственности за материалы опубликованные на сайте! Все материалы исключительно для ознакомления!
    Мини профиль