Опубликован: 22.10.2016 | Доступ: свободный | Студентов: 828 / 84 | Длительность: 04:02:00
Лекция 1:

Обзор технологий. Начало кодирования

Лекция 1: 1234 || Лекция 2 >

Начала навигации. Первые ошибки в работе программы

Обратите внимание на строчку $id = $_GET['id']; в файле index0.php. Эта строчка рассчитана на то, что пользователь из браузера пошлёт на сервер запрос вида http://localhost/index0.php?id=3, а мы на сервере извлечём этот параметр ("3") и используем его для получения нужной строчки таблицы с помощью sql-запроса ("SELECT * FROM `mypages` where id = 3"). То есть мы именно так пока организуем связь запросов клиента и ответов сервера – через параметр id.

Размер нашего кода по сравнению с первоначальным чистым HTML вырос в 3-4 раза. Но на вопрос, стоит ли оно того, здесь быстро ответить нельзя. Для начала надо немного добавить реализма. На сайте редко бывает только одна страница (даже на казалось бы единственной landing-page попросту собрано в кучу много разных страниц). Начнём с двадцати (как будто бы у нас на сайте по астрологии 20 разных страниц). Тогда начальный html-код надо будет размножить на 20 файлов (то есть количество его возрастёт в 20 раз), а последний php-фрагмент у нас находится в единственном файле index0.php и все 20 страниц мы можем вызвать с помощью параметра в адресной строке: http://localhost/index0.php?id=12, http://localhost/index0.php?id=19. Налицо явная экономия, казалось бы.

Но вот с этого места и начинается "экспонента" сложностей. Наш Код в файле index0.php в таком виде попросту не будет работать. Вам это утверждение может показаться слишком сильным. Проверим.

  1. При переходе по адресу http://localhost/index0.php вы получите сообщение Notice: Undefined index: id in /var/www/html/index0.php on line 2.
  2. При переходе по адресам от http://localhost/index0.php?id=1 до http://localhost/index0.php?id=20 вы будете видеть какую-то информацию (если вы занесли в таблицу mypages 20 строк, как планировали) – возможно, это будут "кракозябры" или вопросики из-за несоответствия кодировки.
  3. При параметре id > 20 вы будете видеть пустую страницу (http://localhost/index0.php?id=21).
  4. И да, во всех случаях вы будете видеть сообщение об ошибке, связанное с установкой часового пояса (если у вас php не очень древний).
  5. Или вы совсем не будете видеть сообщения об ошибках, а только пустую страницу – что хуже всего в нашем случае.

Вот с последнего и начнём. В работе сайта желательно предусмотреть два состояния: рабочее (для пользователей) и режим отладки. Пользователи не должны видеть всякие notice. Заведём для переключения этого состояния переменную и в зависимости от её значения будем отображать сообщения об ошибках; а для обработки "возражения 4." добавим часовой пояс по умолчанию (листинг 1.6 пример 1.6):

<?php
$debug = true;
error_reporting(E_ALL);
ini_set('log_errors', true);
ini_set('display_errors', $debug);
date_default_timezone_set('Asia/Yakutsk');
//...
?>
Листинг 1.6.

Добавьте этот код к первоначальному php-коду и сохраните в Папке сайта под именем index1.php. Проверьте код, он должен выглядеть примерно так: http://nichtig.ru/index1.php?code. Чтобы при добавлении параметра "code" можно было видеть php-код файла (вместо результата работы программы) мы использовали дальше следующий фрагмент:

<?php
//...
if (array_key_exists('code', $_GET)) {
    header('Content-Type: text/html; charset=UTF-8');
    $code = file_get_contents(__FILE__);
    highlight_string($code);
    exit;
}
//...
?>

Это было самое простое. Дальше будет всё хуже и хуже. Каждый раз, когда вы обращаетесь к переменной по её имени (например, к переменной $debug в конструкции ini_set('display_errors', $debug);), вы должны ожидать неприятностей разного рода:

  1. переменная не существует;
  2. тип переменной не соответствует ожидаемому;
  3. значение переменной не соответствует ожидаемому диапазону.

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

Проблема 2 – одна из самых неприятных: в php действует "незаметное" приведение типов к нужному (в данном месте кода), и программист быстро привыкает особо не обращать внимания на типы, что иногда внезапно вылезает боком (например, при попытке обратиться к элементу массива по индексу – $arr[1] – когда переменная $arr не является массивом).

Проблема 1 уже встретилась нам при обращении к странице index1.php без параметра ("Notice: Undefined index: id..."). Проблема 3 – при попытке вызвать страницу с id > 20. Решение этих проблем не является тривиальным, так как зависит совсем не от программиста. Как именно следует их решать, должен сказать владелец сайта, но он не подозревает об этих проблемах, и возникает замкнутый круг, разорвать который можно только путём долгих и мучительных переговоров – поэтому на большинстве сайтов эти проблемы вообще не решаются никак (либо решаются путём банального отключения сообщения об ошибках).

Проблему 1 мы решим с помощью следующей конструкции (листинг 1.7 пример 1.7):

<?php
$id = isset($_GET['id']) ? $_GET['id'] : 1;
?>
Листинг 1.7.

Если посетитель сайта не обращается к нашей таблице явно по id, нам всё равно нужно выдать ему какие-то значения по умолчанию, введённые владельцем сайта в таблицу под тем номером, который он сообщит программисту. Мы делаем допущение, что этот номер – 1, то есть обратившись к адресу index1.php без параметра id, пользователь увидит запись с id = 1.

Лекция 1: 1234 || Лекция 2 >
Михаил Гутентог
Михаил Гутентог

Этот курс ( Практикум по разработке CMS ) создавался, когда у PHP была версия 5.3 или 5.4. Со временем какие-то функции PHP устаревают (mysql, each), какие-то начинают работать по-другому (empty). Пожалуйста, следите за изменениями в PHP по сайту php.net!

Александр Мельников
Александр Мельников

Изучаю курс "Практикум по созданию CMS" в листинге 4.3

$n = count($_GET); if ($n > 0) { $param = each($_GET); // самое простое: пропускаем только первый параметр if ($n > 1 || !isset($valid[$param['key']])) { _404(); }

При попытке просмотра в браузере получаю ошибку: Deprecated: The each() function is deprecated.  И не пойму как исправить ситуацию.