Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

PHP5_nachinayushim

.pdf
Скачиваний:
29
Добавлен:
20.03.2015
Размер:
26.79 Mб
Скачать

254 Глава 5

Вторая строка удаляет ограничивающие символы косой черты или обратной косой черты:

$outpath = ereg_replace("^[\/]+", "", $outpath);

Третья строка удаляет префиксы DOS/Windows+стиля (например, "C:\"):

$outpath = ereg_replace("\^[A-Za-z][:\|][\/]?", "", $outpath);

Изящная обработка ошибок

Главное отличие между изящной и неряшливой обработкой ошибок заключается

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

Как и многие другие языки программирования, PHP постепенно становится более зрелым. В PHP5 появились новые встроенные возможности обработки ошибок (они рассматриваются в следующем разделе). Для начала следует описать, в чем заключает+ ся обработка ошибок, а затем рассмотреть обработку ошибок с момента загрузки PHP

всистеме и до выполнения программ в реальном времени.

Конфигурирование обработки ошибок в PHP

Главными конфигурационными параметрами, которые следует использовать в разрабатываемых (а не в уже действующих) системах, являются уровень ошибок (error_reporting), настройка отображения сообщений об ошибках (display_errors) и параметр log_errors. В приложении ‘‘Конфигурация PHP5’’ рассматриваются и мно+ гие другие настройки, однако данные три параметра вызывают наибольший интерес. Первый параметр устанавливает уровень отображаемых ошибок, второй включает или выключает отображение сообщений об ошибках в браузере (в реально действующих сайтах отображать стандартные сообщения об ошибках нежелательно), а третий вклю+ чает или выключает протоколирование ошибок в файле журнала.

Подавление сообщений об ошибках

Подавление ошибок, строго говоря, нельзя назвать элементом отладки, но иногда известно, что ошибки в PHP+сценарии есть и избавляться от соответствующих сооб+ щений нежелательно, необходимо просто проигнорировать их или обработать ошиб+ ки особым образом. Для таких ситуаций в PHP используется специальная форма запи+ си: @+нотация. Когда символ @ используется с какой+либо функцией, PHP подавляет все сообщения об ошибках, возникающие в данной функции. Например, следующая функция вызывается с предшествующим символом @:

function ProcessFormDetails ($Name, $Email)

{

//какая-либо обработка

}

@ProcessFormDetails($Name, $Email);

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

Надежный и понятный код 255

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

Проверка журнала ошибок

По умолчанию PHP не записывает сообщения об ошибках в журнал Web+сервера, однако такое поведение можно исправить. PHP может протоколировать ошибки в файл журнала, если в файле php.ini присутствуют следующие директивы:

log_errors = On

error_log = /var/log/php.log

В PHP также имеется функция error_log, которая позволяет протоколировать не+ ожиданные ситуации, не предусмотренные программистом и не имеющие специального способа программной обработки. Это позволяет изучать возникающие ошибки, даже если вывод соответствующих сообщений был подавлен описанным выше способом.

Функция error_log может принимать до четырех аргументов, но обязательными являются только первые два из них. Функция имеет следующий формат:

error_log("Error Message", MessageType, "Destination", "Extra Headers");

Первый аргумент Error Message представляет собой фактическое сообщение об ошибке. Второй аргумент, MessageType, ++++++ код, означающий то место, куда необхо+ димо отправлять сообщение об ошибке; существует четыре возможных значения это+ го аргумента:

0:сообщения отправляются в журнал ошибок PHP;

1:сообщения отправляются на e+mail+адрес, заданный третьим аргументом;

2:сообщения отправляются в отладочный канал PHP (только если включен ре+ жим отладки);

3:сообщения отправляются в файл журнала, путь к которому задается третьим аргументом.

Третий аргумент, Destination, принимает либо e+mail+адрес, либо путь к файлу, а четвертый аргумент, Extra Headers, можно использовать для отправки дополни+ тельной информации в форме e+mail+заголовоков.

Чтобы получить подробные сведения о возникшей ошибке, можно включить про+ токолирование ошибок в журнал или использовать функцию error_log, а затем про+ смотреть содержащуюся в журнале информацию.

Try/Catch — нововведения в PHP5

Несколько новых средств в PHP5 позволяют программам изящно реагировать на возникающие ошибки. Речь идет о новых возможностях по обработке исключитель+ ных ситуаций ++++++ блоках try/catch. По существу, создается блок try и в него помещает+ ся обрабатываемый код, который может генерировать ошибки. Затем в зависимости от сгенерированной ошибки используется блок catch, в котором принимается реше+ ние о том, что следует делать с этой ошибкой. Одно из важных преимуществ такой схемы состоит в том, что она облегчает перехват ошибок в блоках функций.

256 Глава 5

Функциональность try/catch генерирует исключения, а исключения являются объек+ тами. Из блока try с помощью оператора new Exception ‘‘выбрасываются’’ исключе+ ния, которыми затем занимается блок catch. Созданное исключение представляет со+ бой объект, его можно использовать так же, как и любой другой объект (подробнее объекты рассматриваются в этой книге далее). Метод getMessage объекта Exception позволяет получить сообщение, связанное с возникшей ошибкой. Использование функциональности try/catch наглядно демонстрируется в следующем примере.

Практика Использование блоков try/catch для проверки данных формы

1. Запустите HTML+редакотор и создайте файл со следующим кодом:

<html>

<head><title>PHP5 для начинающих</title></head> <body bgcolor="#FFFFFF">

<?php

if (isset($_POST['posted'])) {

//записать переданные значения в обычные переменные

$first_name = $_POST['first_name']; $last_name = $_POST['last_name']; $birth_date = $_POST['birth_date']; $phone = $_POST['phone'];

$age = $_POST['age']; $address = $_POST['address']; $city = $_POST['city']; $state = $_POST['state'];

$postal_code = $_POST['postal_code'];

//создать массив из имен полей и типов данных

$field_names = array("first_name" => "string", "last_name" => "string", "birth_date" => "date",

"phone" => "string", "age" => "integer", "address" => "string", "city" => "string", "state" => "string",

"postal_code" => "string");

//по имени поля проверить тип данных каждого переданного значения

function form_validate($fns) {

foreach ($fns as $key => $value) { $field_value = $key;

global $$field_value;

//echo "фактическое значение поля " . $$field_value . "<br>"; switch ($value) {

Case "string";

if ((strlen($$field_value) < 1) or (strlen($$field_value) > 99)) { throw new Exception("Пожалуйста, введите в поле

<b>$key</b> строку от 1 до 100 символов");

}

break; Case "date";

if (!ereg("^[0-9]{4}\-([1-9]|(0[1-9])|(1[0-2]))\-([1-9]| (0[1-9])|([1-2][0-9])|3[0-1])$",$$field_value)) {

Надежный и понятный код 257

throw new Exception("Пожалуйста, введите в поле <b>$key</b>

корректную дату в формате ГГГГ-ММ-ДД");

}

break;

Case "integer";

if (!is_numeric($$field_value)) {

throw new Exception("Пожалуйста, введите в поле <b>$key</b>

число без десятичных разделителей или алфавитных символов.");

}

break;

default;

break;

}

}

}

//перехватить исключение и сгенерировать сообщение об ошибке try

{

form_validate($field_names);

}

catch (Exception $e)

{

echo $e -> getMessage(); echo "<br>";

}

}

//если ошибок не было, то поблагодарить пользователя

if (!is_object($e) and isset($posted)) {

echo "Спасибо за информацию, мы свяжемся с Вами."; } else {

//вернуть пользователю заполненную форму и предложить ввести исправленные данные

?>

<form action="try_catch.php" method=post> <input type="hidden" name="posted" value="true">

<table width="50%" border="1"> <tr>

<td colspan="2"><font face="Arial, Helvetica, sans-serif" size="-1">

Пожалуйста, введите контактную информацию:</font></td> </tr>

<tr>

<td width="26%"><font face="Arial, Helvetica, sans-serif" size="-1">Имя </font></td>

<td width="74%">

<input type="text" name="first_name" value="<?php echo $first_name; ?>"> </td>

</tr>

<tr>

<td width="26%"><font face="Arial, Helvetica, sans-serif" size="-1">

Фамилия

</font></td> <td width="74%">

<input type="text" name="last_name" value="<?php echo $last_name; ?>"> </td>

</tr>

<tr>

<td width="26%"><font face="Arial, Helvetica, sans-serif" size="-1">

Дата рождения</font></td> <td width="74%">

<input type="text" name="birth_date" value="<?php echo $birth_date; ?>"> </td>

</tr>

<tr>

258 Глава 5

<td width="26%"><font face="Arial, Helvetica, sans-serif" size="-1">

Номер телефона</font></td> <td width="74%">

<input type="text" name="phone" value="<?php echo $phone; ?>"> </td>

</tr>

<tr>

<td width="26%"><font face="Arial, Helvetica, sans-serif" size="-1"> Возраст</font></td>

<td width="74%">

<input type="text" name="age" value="<?php echo $age; ?>"> </td>

</tr>

<tr>

<td width="26%"><font face="Arial, Helvetica, sans-serif" size="-1"> Адрес</font></td>

<td width="74%">

<input type="text" name="address" value="<?php echo $address; ?>"> </td>

</tr>

<tr>

<td width="26%"><font face="Arial, Helvetica, sans-serif" size="-1"> Город</font></td>

<td width="74%">

<input type="text" name="city" value="<?php echo $city; ?>"> </td>

</tr>

<tr>

<td width="26%"><font face="Arial, Helvetica, sans-serif" size="-1"> Штат</font></td>

<td width="74%">

<input type="text" name="state" value="<?php echo $state; ?>"> </td>

</tr>

<tr>

<td width="26%"><font face="Arial, Helvetica, sans-serif" size="-1">

Почтовый индекс</font></td> <td width="74%">

<input type="text" name="postal_code" value="<?php echo $postal_code; ?>"> <input type="submit" value="Отправить информацию" name="submit">

</td>

</tr>

</table>

</form>

<?php

}

?>

</body>

</html>

2.Сохраните данный файл как try_catch.php и закройте его.

3. Откройте файл в браузере (рис. 5.7), введите значения для каждого поля и просмотрите полученные после отправки формы сообщения об ошибках. На рис. 5.8 и 5.9 показаны некоторые примеры сообщений об ошибках.

Если все данные ввести правильно, то появится сообщение с благодарностью.

Надежный и понятный код 259

Рис. 5.7.

Как это работает

Программа начинается с формы, в которую пользователь вводит данные. Эти дан+ ные должны быть определенных типов. Форму можно было бы легко расширить для многих других типов данных. Затем, как и во всех остальных примерах, чтобы опре+ делить, была ли отправлена данная форма, используется функция isset() (в данном случае проверка выполняется в нескольких местах). Переданные данные записывают+ ся в обычные переменные, и создается массив имен полей и типов данных, который будет использоваться позднее для настройки подпрограмм проверки данных. Массив выглядит следующим образом:

//создать массив из имен полей и типов данных

$field_names = array("first_name" => "string", "last_name" => "string", "birth_date" => "date",

"phone" => "string", "age" => "integer", "address" => "string", "city" => "string", "state" => "string",

"postal_code" => "string");

260 Глава 5

Рис. 5.8.

Рис. 5.9.

Надежный и понятный код 261

Разработка баз данных в книге пока еще не рассматривалась (эта тема описана в нескольких последующих главах), тем не менее, следует отметить, что имена полей и типы данных (а также другую информацию для проверки формы) можно легко по+ лучить из базы данных. На самом деле можно было бы хранить в базе данных большое количество сведений о форме и процессе проверки данных этой формы. И хотя такой подход требует несколько больших трудозатрат, заказчик приложения впоследствии сможет легко изменить количество и тип отображаемых в форме полей, зная, что форма все равно будет обрабатываться соответствующим образом.

Затем создается функция, осуществляющая проверку данных, переданных фор+ мой. Для того чтобы процесс проверки охватил все поля формы, внутри функции ис+ пользуется цикл foreach, проверяющий имена полей и их значения. Создавать дан+ ную функцию было необязательно, однако это облегчило бы работу, если бы надо было проверять несколько массивов значений полей. Функция начинается так:

function form_validate($fns) {

foreach ($fns as $key => $value) {

Затем имя поля передается в переменную, после чего используется способность PHP обращаться к значению определенного поля переданной HTML+формы (необходимо использовать ключевое слово global, потому что внутри области види+ мости функции внешние переменные не видны; функции и этот аспект их работы подробнее рассматриваются в главе 6):

$field_value = $key;

global $$field_value;

Затем используются Case+блоки оператора switch для выделения типов провер+ ки. Внутри блока выполняются различные проверки переданных значений:

switch ($value) { Case "string";

if ((strlen($$field_value) < 1) or (strlen($$field_value) > 99)) {

throw new Exception("Пожалуйста, введите в поле <b>$key</b> строку от 1 до 100 символов");

}

break; Case "date";

if (!ereg("^[0-9]{4}\-([1-9]|(0[1-9])|(1[0-2]))\-([1-9]|(0[1-9])|([1-2]

[0-9])|3[0-1])$",$$field_value)) {

throw new Exception("Пожалуйста, введите в поле <b>$key</b> корректную дату в формате ГГГГ-ММ-ДД");

}

break;

Case "integer";

if (!is_numeric($$field_value)) {

throw new Exception("Пожалуйста, введите в поле <b>$key</b> число без десятичных разделителей или алфавитных символов.");

}

break;

default;

break;

}

Обратите внимание, что оператор throw new Exception выполняется, когда значение не проходит какую+либо проверку. Например, если длина строкового значе+ ния не попадает в пределы 1++++99 символов, то генерируется исключение. Во время создания исключения ему назначается сообщение ++++++ строковое значение в круглых скобках после ключевого слова Exception.

262 Глава 5

Чтобы функция обрабатывала переданные значения, используются блоки try/catch. Функция выполняется внутри блока try, а в блоке catch перехватывается каждое исключение и выводится соответствующее сообщение. (В блоке catch при желании можно реализовать любой вид обработки ошибок.) Кроме того, если возни+ кает исключение, то работа функции прекращается и создается объект Exception (исключение) со своим сообщением:

try

{

form_validate($field_names); } catch (Exception $e)

{

echo $e -> getMessage(); echo "<br>";

}

Последняя особенность заключается в том, что если возникает ошибка, то ото+ бражаются введенное пользователем значение и сообщение об ошибке, чтобы поль+ зователь мог исправить проблему, не вводя все данные заново. Если ошибок не было, то выводится сообщение с благодарностью. Поля формы заполняются существующи+ ми данными, потому что в атрибутах value всех полей вызывается оператор echo, отображающий переданные данные (когда форма отображается впервые, атрибут value, естественно, не содержит никаких данных). В следующем блоке if выполня+ ется проверка того, возвращается ли пользователю сообщение с благодарностью. Для этого необходимо проверить, является ли исключение ($e) объектом, а также была ли форма отправлена:

//если ошибок не было, то поблагодарить пользователя

if (!is_object($e) and isset($posted)) {

echo "Спасибо за информацию, мы свяжемся с Вами."; } else {

//вернуть пользователю заполненную форму и предложить ввести исправленные данные

?>

Резюме

В данной главе рассматривались базовые функции тестирования, локализации не+ исправностей, отладки и обработки ошибок, а также проверка строк (для перехвата некорректных данных до того, как они нарушат работу программы), регулярные вы+ ражения (для улучшенной проверки) и новые функции PHP5 try/catch.

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

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

Надежный и понятный код 263

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

Планирование (и желательно разумное использование регулярных выражений) при обработке ошибок может значительно улучшить Web+сайт. Не забывайте закон Мерфи: если какая+либо ошибка может возникнуть, то она обязательно возникнет. Помня об этом, можно избежать неприятностей ++++++ проверить все места, где возникно+ вение ошибки наиболее вероятно, и соответствующим образом исправить сценарии. Предусмотрительность поможет сократить большое количество проблем в будущем.

Упражнение

Создайте не менее трех регулярных выражений и вставьте их в соответствующие места последнего примера в данной главе. Примерные регулярные выражения:

семи+ и десятизначные номера телефонов в США;

номера социального обеспечения;

буква для обозначения пола пользователя (М ++++++ для мужчин и Ж ++++++ для женщин).

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]