программирование :: разное

PHP и MySQL. Часть 5

PHP и MySQL. Часть 5

Продолжение. Начало в КГ №№ 11, 22, 24, 29.

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

Создание проекта начнем с обзора требований, подобных тем, которые выдвигает заказчик. Затем постараемся преобразовать эти требования в набор компонентов решения, построим схему решения и затем опишем каждый компонент.
Итак, проект реализует следующие функции: регистрация, аутентификация пользователей; управление паролями; запись предпочтений пользователей; персонализация содержимого.
Нам требуется создать прототип интерактивной системы закладок, подобной системе, которую предоставляет портал http://open.by в своей почтовой службе, но более ограниченной функционально и с неизмеримо более бедным дизайном. Требования к своей системе разобьем на две группы. Первая: необходимо иметь возможность идентифицировать отдельных пользователей. Кроме того, следует располагать методом их аутентификации. Вторая группа: реализовать хранение закладок для отдельного пользователя. Пользователи должны иметь возможность добавлять и удалять записи.
Теперь, когда требования к системе определены, можно приступить к разработке решения. Рассмотрим каждую из групп требований более тщательно.

Существует несколько альтернатив аутентификации пользователей. Поскольку требуется связать с пользователем некоторую личную информацию, его входное имя и пароль будут храниться в базе данных MySQL и применяться каждый раз для аутентификации. Если необходимо предоставить пользователям операцию входа в систему, указывая свое имя и пароль, это рождает необходимость в следующих компонентах.
Идентификация пользователей. Пользователи должны иметь возможность регистрироваться в системе. При этом необходимо ограничить длину и формат имени и пароля. Пароль следует хранить в зашифрованном виде.
Пользователям необходимо предоставить вход в систему с указанием сведений, которые они предоставили при регистрации. Они должны иметь возможность выйти из системы по завершении работы, так как это особенно важно для лиц, обращающихся к сайту из интернет-кафе или других публичных мест доступа.
Сайт обязан проверять, вошел ли пользователь в систему, а также предоставлять данные тем, кто эту процедуру выполнил.
Пользователи имеют право изменить свой пароль в любой момент времени.
Пользователи забывчивы и часто забывают свои пароли. Значит, следует предоставить сервис по переустановке пароля без участия администратора. Типичный метод состоит в отправке пароля на e-mail, указанный при регистрации. Значит, необходимо сохранять адрес электронной почты в базе данных, а также заменять старый пароль на новый, полученный каким-либо генератором паролей.
В процессе работы над проектом будут созданы функции для реализации всех перечисленных возможностей. Большинство их может быть использованы повторно в других проектах практически без изменений.

Хранение закладок. Для хранения закладок пользователя требуется создать некоторое пространство объектов в базе данных. Пользователи должны извлекать и просматривать закладки, удалять и добавлять их. Также необходимо проверять данные об URL-адресах на допустимость, то есть существование сайта по введенному адресу.
Структура проекта. Для начала опишем набор исполняемых сценариев и библиотек, которые будут использоваться в этом проекте:
bookmarks.sql — файл содержит набор SQL-команд для создания базы данных PHPBookmark.
Сценарии register_new.php, forgot_passwd. php, add_bms.php, delete_bms.php, change_passwd.php, logout.php выполняют регистрацию пользователя, восстановление пароля, добавление закладки, ее удаление, смену пароля и выход из системы.
Формы register_form.php, forgot_form.php, add_bm_form.php, change_passwd_form.php отображают поля для регистрации пользователя, восстановления пароля пользователя, добавления закладки и смены пароля пользователем.
В начале работы пользователь будет видеть стартовую страницу login.php, а после удачного входа в систему — результат работы сценария members.php — окно со списком внесенных закладок.
Также в проекте будет использоваться файл bookmark_fns.php, библиотека функций для проверки полученных данных, работы с базой данных, аутентификации и добавления и удаления закладок.
Ниже приводится блок-схема проекта.

Начнем с реализации базы данных MySQL, так как наличие базы обязательно для осуществления почти всех функций приложения. Затем мы приступим к исследованию кода в порядке его написания. Начнем с начала, то есть с титульной страницы, затем перейдем к аутентификации пользователей, потом к хранению и извлечению закладок. Такая последовательность вполне логична — определяются зависимости и создаются в первую очередь элементы, которые понадобятся для других модулей.
База данных для проекта довольно проста. Необходимо хранение имен пользователей, их адресов электронной почты и паролей. Кроме того, следует хранить URL-адреса закладок. Один пользователь может иметь множество закладок, а одну и ту же закладку могут зарегистрировать несколько пользователей. Поэтому база данных содержит две таблицы: пользователей и закладок, связанных по имени пользователя связью "один ко многим". Таблица пользователей содержит имена пользователей (как первичный ключ), пароли и адреса электронной почты. Таблица закладок содержит пары имен пользователей и закладок. Имена пользователей этой таблицы ссылаются на соответствующие значения таблицы пользователей. Ниже приведен код файла bookmark.sql, который содержит код создания базы данных, а также создания пользователя для подключения к ней из Web.

create database bookmarks;
use bookmarks;

create table user (
username varchar(16) primary key,
passwd char(16) not null,
email varchar(100) not null
);

create table bookmark (
username varchar(16) not null,
bm_URL varchar(255) not null,
index (username),
index (bm_URL)
);

grant select, insert, update, delete
on bookmarks.*
to bm_user@localhost identified by 'password';

Эту базу данных можно создать, выполнив набор команд в консоли Linux: mysql -u root
-p < bookmark.sql или из консоли Windows: source bookmark.sql;.
Основа будущего приложения заложена, приступим к созданию сайта.
Первая страница будет называться login.php, поскольку предоставляет пользователю возможность входа в систему. Код страницы показан ниже:

<?
require_once("bookmark_fns.php");
do_html_header("");
display_site_info();
display_login_form();
do_html_footer();
?>

Этот код выглядит очень простым, поскольку в нем, в основном, вызываются функции из API-интерфейса, который мы построим для данного приложения. Подробное описание функций будет приведено ниже. Заметьте: вначале выполняется подключение файла, содержащего функции, а затем выполняются функции визуализации HTML-заголовка, отображения содержимого и отображения нижнего колонтитула.
Содержимое файла bookmark_fns.php приводить нет смысла: он очень велик из-за содержащихся в нем функций и будет рассмотрен по частям при упоминании содержащихся в нем функций. На рис. 1 показан результат работы сценария login.php.
Заметим, что этот файл (book-mark_fns.php) служит лишь контейнером для функций, которые будут использоваться в приложении. Данная структура объясняется тем, что функции таким образом отделяются от стандартного HTML-кода. Чтобы не подключать каждый раз несколько файлов, по которым разбросаны функции, будем подключать один — так проще.
Заметим, что конструкция require_ once() существует только в РНР версии 4.0.2pl2 и выше. Если работа ведется с более ранней версией, следует использовать операторы include или require. В этом случае проверка, чтобы файлы не загружались по несколько раз, ложится полностью на программиста.
В данном отдельном случае используются функции, которые реализуют вывод простого HTML-содержимого. Основной функциональный файл включает четыре функции, которые были использованы в файле login.php: do_html_ footer(), do_html_header(), display_site_info(), display_login_form(), и еще несколько других.
Функции эти достаточно просты, поэтому рассмотрим только одну в качестве примера. Функция do_html_header() выводит стандартный заголовок, который отображается на каждой странице:

function do_html_header($title)
{
// печать HTML-заголовка
?>
<html> <head>
<title> <?=$title?> </title>
</head> <body>
<img src="bookmark.gif" alt="PHPbookmark logo" border=0
align=left valign=bottom height = 55 width = 57>
<h1> PHPbookmark</h1>
<hr>
<?
if($title)
do_html_heading($title);
}

Можно видеть, что логика функции сводится к добавлению заголовка и логотипа к странице. Остальные функции, использованные в файле login.php, подобны вышеописанной функции. Так, display_site_info() добавляет текстовое описание сайта; display_login_form() отображает форму для входа в систему (рис. 1); do_html_footer() включает в страницу стандартный нижний колонтитул HTML.
На рисунке 1 показано, что страница предоставляет три опции: пользователь может зарегистрироваться, войти в систему, если он уже зарегистрирован, либо переустановить забытый пароль. Для реализации этих модулей перейдем к следующей логической единице программы — аутентификации пользователей.
Модуль аутентификации пользователей содержит четыре главных элемента: регистрацию пользователей, вход и выход из системы, смену паролей и переустановку паролей. Рассмотрим их поочередно.
Чтобы зарегистрировать пользователя, необходимо через форму получить сведения о нем и поместить их в базу данных. Когда пользователь выполняет щелчок на ссылке на странице login.php ("Not a member?"), для него выводится форма регистрации, сгенерированная сценарием register_form.php. Код сценария прост, так как состоит из вызовов функций API:

<?
require_once("bookmark_fns.php");
do_html_header("User Registration");
display_registration_form();
do_html_footer();
?>

Эта страница также довольно проста и осуществляет лишь вызов функций из нашей библиотеки функций. Форма регистрации показана на рис. 2. Форма серого цвета на этой странице представляет собой вывод функции display_registration_form(), которая выводит поля и кнопки формы. Когда пользователь выполняет щелчок на кнопке Register, выполняется сценарий register_new.php, который является первым более-менее сложным сценарием этого примера. Он начинается с подключения файлов функций и запуска сеанса. После регистрации пользователя создается переменная сеанса, содержащая имя пользователя, как это было сделано в предыдущей статье.
Затем выполняется проверка допустимости данных, введенных пользователем. Сначала проверяем, что форма заполнена функцией filled_out(), затем проверяем правильность написания почтового адреса электронной почты функцией valid_email(), идентичность обоих вариантов пароля и допустимость длины пароля.

<?
require_once("bookmark_fns.php");
session_start();
if (!filled_out($HTTP_POST_VARS))
{
do_html_header("Ошибка:");
echo "Вы неправильно заполнили форму — вернитесь и попробуйте снова.";
do_html_footer();
exit;
}
if (!valid_email($email))
{
do_html_header("Ошибка:");
echo "Неверный адрес почты. Вернитесь и повторите снова.";
do_html_footer();
exit;
}
if ($passwd != $passwd2)
{
do_html_heading("Ошибка:");
echo "Пароли, которые вы ввели, не совпадают. Вернитесь и повторите снова.";
do_html_footer();
exit;
}
if (strlen($passwd)<6 || strlen ($passwd) > 16)
{
do_html_header("Problem:");
echo "Ваш пароль должен быть длиной от 6 до 16 символов. Вернитесь и повторите снова.";
do_html_footer();
exit;
}
$reg_result = register($username, $email, $passwd);
if ($reg_result == "true")
{
$valid_user = $username;
session_register("valid_user");
do_html_header("Регистрация успешна");
echo "Ваша регистрация успешна. Перейдите на страницу закладок и начните создавать закладки!";
do_HTML_URL("member.php", "Страница закладок");
}
else
{
do_html_header("Problem:");
echo $reg_result;
do_html_footer();
exit;
}
do_html_footer();
?>

Использованные в сценарии функции проверки допустимости данных filled_out() и valid_email() показаны, соответственно, ниже:

function filled_out($form_vars)
{
foreach ($form_vars as $key => $value)
{if (!isset($key) || ($value == ""))
return false;}
return true;
}

function valid_email($address)
{
if (ereg("^[a-zA-Z0-9_\.\-]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+$",$address) )
return true;
else
return false;
}

Первая функция ожидает передачи массива переменных — $HTTP_POST_VARS или $HTTP_ GET_VARS. Если массив заполнен, она возвращает true, в противном случае — false. В функции valid_email() применяется регулярное выражение, специально написанное для проверки адресов электронной почты. Если адрес является допустимым, возвращается true, иначе — false.
Затем после проверки введенных данных предпринимается попытка регистрации пользователя. Это выполняется функцией register(), в которую передаются имя пользователя, адрес электронной почты и пароль, введенные в форме регистрации. В случае успешного исхода имя пользователя регистрируется в качестве переменной сеанса и предоставляется ссылка на главную страницу зарегистрированных пользователей. Результат работы сценария показан на рис. 3. Эта функция не содержит ничего нового — она осуществляет подключение к созданной ранее базе данных. Если выбранное имя пользователя уже задействовано либо база данных не может быть обновлена, функция возвращает значение false. В противном случае база данных обновляется, и возвращается значение true.
Заметим, что подключение к базе данных реализуется через написанную ранее функцию db_connect(), которая просто предоставляет единственную область хранения имени пользователя и пароля для подключения к базе данных. Таким образом, для изменения пароля базы данных достаточно модернизировать один файл приложения. Приводить эту функцию также нет смысла: она была описана ранее.
Зарегистрированные пользователи могут входить и выходить из системы через обычные страницы, предназначенные для этих целей. Принцип их работы будет освещен чуть ниже, когда будем разбирать пункты меню программы. После того, как пользователи внесут свои данные в форму login.php и отправят ее, выполнится сценарий member.php. Этот сценарий позволит им войти в систему. Кроме того, отобразятся связанные с пользователями закладки. Это краеугольное событие оставшейся части приложения. Суть сценария member.php изложена ниже.

<?
require_once("bookmark_fns.php");
session_start();
if ($username && $passwd)
{
if (login($username, $passwd))
{ $valid_user = $username;
session_register("valid_user"); }
else
{ do_html_header("Ошибка:");
echo "Вы не можете войти в систему. Вы должны войти, чтобы попасть на эту страницу.";
do_html_url("login.php", "Login");
do_html_footer();
exit;}
}
do_html_header("Home");
check_valid_user();
if ($url_array = get_user_urls($valid_ user));
display_user_urls($url_array);
display_user_menu();
do_html_footer();
?>

И опять действие сценария развивается по шаблону. Сначала подключается файл с необходимыми функциями. Затем выполняется проверка, вошел ли пользователь в систему через титульную страницу. Другими словами, заполнял ли он форму входа в систему. После этого выполняется попытка зарегистрировать пользователя в системе. Для входа в систему используется функция login.php.
Если попытка входа в систему успешна, сеанс будет зарегистрирован, как и ранее. При этом имя пользователя сохраняется в переменной сеанса $valid_user. Когда все идет нормально, отображается страница зарегистрированных пользователей, которая также формируется функциями вывода. В ней будет использоваться несколько новых функций — check_valid_user(), get_user_urls(), display_user_urls(). Функция check_valid_user() проверяет, что с текущим пользователем связан зарегистрированный сеанс. Она предназначена для пользователей, которые открыли сеанс ранее, и для пользователей, только что вошедших в систему, не работает. Функция get_user_urls() извлекает закладки пользователя из базы данных, а display_user_urls() отображает закладки в браузере. Код всех функций будет рассмотрен далее, во время обзора процесса хранения и извлечения закладок.

Продолжение следует.

Денис "Denver" Мигачев, dtm@tut.by




© компьютерная газета