Содержание


Программирование с использованием PHP и MySQL в разработке Web-приложений

Часть 14. Обеспечение смены паролей пользователей. Восстановление забытых паролей. Ведение закладок

Comments

Серия контента:

Этот контент является частью # из серии # статей: Программирование с использованием PHP и MySQL в разработке Web-приложений

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Программирование с использованием PHP и MySQL в разработке Web-приложений

Следите за выходом новых статей этой серии.

В статье будет рассмотрена организация взаимодействия пользователей и веб-сайта. В предыдущих статьях рассматривались вопросы базовой аутентификации системными средствами и средствами apache, реализация аутентификации средствами модуля mod_auth_mysql. Все эти вопросы, а также любое другое взаимодействие зарегистрированных пользователей с системой, подразумевают вход пользователя в систему, сопровождающийся вводом пары «учетная запись+пароль». В случае утраты пользователем пароля необходимо предусмотреть возможность его восстановления или просто замены по желанию. В статье будет показано, как в рамках одного проекта осуществить решение этой задачи, а также освещены вопросы формирования и ведения закладок по нужным URL. Код, приводимый в данной статье, рассчитан на то, что предыдущие статьи цикла были программно реализованы в виде проекта с работающей базой данных и PHP кодом.

Смена пароля пользователем

Смена пароля пользователя может быть реализована сценарием, который должен проверить, вошел ли пользователь в систему, заполнил ли он поля формы и допустимую установленную длину пароля. Если все условия являются легитимными, то вызываются функции change_password(), reset_password(), get_random_word(), notify_password() из библиотеки функций user_auth_fns.php.

Форма для смены пароля:

<?php
 require_once('bookmark_fns.php');
 session_start();
 do_html_header('Изменить пароль');
 check_valid_user();
 
 display_password_form();

 display_user_menu(); 
 do_html_footer();
?>

Сценарий change_password.php меняет пароль:

 <?php
  require_once('bookmark_fns.php');
  session_start();
  do_html_header('Смена пароля');
 
  // Создать короткие имена переменных
  $old_passwd = $_POST['old_passwd'];
  $new_passwd = $_POST['new_passwd'];
  $new_passwd2 = $_POST['new_passwd2'];
 
  try
  { 
    check_valid_user();
    if (!filled_out($_POST))
      throw new Exception('Вы не заполнили корректно форму. '
                          .'Пожалуйста, попытайтесь еще раз.';
    if ($new_passwd != $new_passwd2)
       throw new Exception('Введенные пароли не совпадают. '
                           .'Изменение невозможно.';
    if (strlen($new_passwd) < 6)
       throw new Exception('Новый пароль должен иметь длину, как минимум, '
                              .'6 символов. Повторите попытку.';

     // Попытка обновить БД
     change_password($_SESSION['valid_user'], $old_passwd, $new_passwd);
     echo 'Пароль изменен.';
  }
  catch (Exception $e)
  {
    echo $e->getMessage();
  }

  display_user_menu(); 
  do_html_footer();
?>

Библиотека user_auth_fns.php

<?php

require_once('db_fns.php');

function register($username, $email, $password)
// Регистрирует нового пользователя в базе данных.
// Возвращает либо true, либо сообщение об ошибке.
{
 // Подключиться к базе данных
  $conn = db_connect();

  // Проверить, уникально ли имя пользователя 
  $result = $conn->query("select * from user where username='$username'"); 
  if (!$result)
     throw new Exception('Невозможно выполнить запрос к БД');
  if ($result->num_rows > 0) 
     throw new Exception('Это имя пользователя уже занято - вернитесь '
                         .'на форму регистрации и выберите другое имя.');

  // Если все в порядке, сохранить информацию в БД
  $result = $conn->query("insert into user values 
                         ('$username', sha1('$password'), '$email')");
  if (!$result)
    throw new Exception('Невозможно сохранение в БД - пожалуйста, '
                        .'попытайтесь позже.');

  return true;
}
 
function login($username, $password)
// Проверяет наличие имени пользователя и пароля в базе данных.
// Если они там содержатся, возвращается значение true, 
// в противном случае генерируется исключение.
{
  // Подключиться к базе данных
  $conn = db_connect();

  // Проверить уникальность имени пользователя
  $result = $conn->query("select * from user
                     where username='$username'
                     and passwd = sha1('$password')");
  if (!$result)
     throw new Exception('Вход в систему невозможен');

  if ($result->num_rows > 0)
     return true;
  else
     throw new Exception('Вход в систему невозможен');
}

function check_valid_user()    
// Определяет, вошел ли пользователь в систему и, 
// если нет, выводит соответствующее уведомление
{
  global $valid_user;
  if (isset($_SESSION['valid_user']))
  {
      echo 'Вы вошли в систему под именем '
           .stripslashes($_SESSION['valid_user']).'.';
      echo "<br />";
  }
  else
  {
     // Пользователь не вошел в систему
     do_html_heading("Проблема:");
     echo "Вы не вошли в систему.<br />";
     do_html_url('login.php', 'Вход');
     do_html_footer();
     exit;
  }
}

function change_password($username, $old_password, $new_password)
// Заменяет старый пароль новым.
// Возвращает значение true или генерирует исключение
{
  // Если прежний пароль введен правильно,
  // он заменяется новым и возвращается значение true,
  // в противном случае генерируется исключение
  login($username, $old_password);
  $conn = db_connect();
  $result = $conn->query( "update user
                           set passwd = password('$new_password')
                           where username = '$username'");
  if (!$result)
    throw new Exception('Пароль не может быть изменен.'); 
  else
    return true;  	// Пароль успешно изменен
}

function get_random_word($min_length, $max_length)
// grab a random word from dictionary between the two lengths
// and return it
{
   // generate a random word
  $word = '';
  // remember to change this path to suit your system
  $dictionary = '/usr/dict/words';  // the ispell dictionary
  $fp = @fopen($dictionary, 'r');
  if(!$fp)
    return false; 
  $size = filesize($dictionary);

  // go to a random location in dictionary
  srand ((double) microtime() * 1000000);
  $rand_location = rand(0, $size);
  fseek($fp, $rand_location);

  // get the next whole word of the right length in the file
  while (strlen($word)< $min_length || strlen($word)>$max_length || strstr($word, "'"))
  {  
     if (feof($fp))   
        fseek($fp, 0);        // if at end, go to start
     $word = fgets($fp, 80);  // skip first word as it could be partial
     $word = fgets($fp, 80);  // the potential password
  };
  $word=trim($word); // trim the trailing \n from fgets
  return $word;  
}

function reset_password($username)
// Устанавливает случайное значение для пароля.
// Возвращает новый пароль либо значение false в случае ошибки
{
  // Получить случайное слово из словаря длиной от 6 до 13 символов
  $new_password = get_random_word(6, 13);

  if($new_password == false)
    throw new Exception('Невозможно сгенерировать новый пароль.');
  // Добавить к нему число от 0 до 999
  // с целью небольшого улучшения 
  srand ((double) microtime() * 1000000);
  $rand_number = rand(0, 999);
  $new_password .= $rand_number;

  // Изменить пароль в базе данных или вернуть значение false
  $conn = db_connect();
  $result = $conn->query( "update user
                           set passwd = sha1('$new_password')
                           where username = '$username'");
  if (!$result)
    throw new Exception('Невозможно изменить пароль.');  // Пароль не изменен
  else
    return $new_password;  // Пароль успешно изменен
}

function notify_password($username, $password)
// Уведомляет пользователя о том, что его пароль изменен
{
  $conn = db_connect();
  $result = $conn->query("select email from user
                          where username='$username'");
  if (!$result)
  {
    throw new Exception('Адрес электронной почты не найден.'); 
  }
  else if ($result->num_rows == 0)
  {
    throw new Exception('Адрес электронной почты '
                        .'не найден.'); // имя пользователя отсутствует в БД
  }
  else
  {
    $row = $result->fetch_object();
    $email = $row->email;
    $from = "From: support@phpbookmark \r\n";
    $mesg = "Ваш пароль для входа в систему PHPBookmark изменен на $password \r\n"
            ."Пожалуйста, учтите это при будущем входе в систему. \r\n";
          
    if (mail($email, 'Информация о входе в систему PHPBookmark', $mesg, $from))
      return true;      
    else
      throw new Exception('Не удается отправить электронную почту.'); 
  }
}

?>

Восстановление забытых паролей

Форма для вывода и установки пароля

<?php
 require_once('bookmark_fns.php');
 do_html_header('Переустановка пароля');
 
 display_forgot_form();

 do_html_footer();
?>

Сценарий (forgot_passwd.php) переустановки пароля с возможностью его отправки на почтовый адрес:

<?php
  require_once('bookmark_fns.php');
  do_html_header('Переустановка пароля');

  // Создать короткие имена переменных
  $username = $_POST['username'];

  try
  {
    $password = reset_password($username);
    notify_password($username, $password);
    echo 'Новый пароль отправлен по адресу электронной почты, '
         .'который вы указали при регистрации.';
  }
  catch (Exception $e)
  {
      echo 'Пароль не может быть переустановлен. '
           .'Пожалуйста, повторите попытку позже.';
  }
  do_html_url('login.php', 'Вход');
  do_html_footer();
?>

Хранение и извлечение закладок

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

Добавление закладок

Сценарий реализации формы для добавления закладок

<?php

// Включить файлы функций для этого приложения
require_once('bookmark_fns.php');
session_start();

// Начать html-вывод
do_html_header('Добавление закладок');

check_valid_user();
display_add_bm_form();

display_user_menu();
do_html_footer();

?>

Добавление новых закладок на персональную страницу пользователя(add_bms.php)

<?php
 require_once('bookmark_fns.php');
 session_start();
 // Создать короткие имена переменных
 $new_url = $_POST['new_url'];
 
 do_html_header('Добавление закладок');

 try
 {
   check_valid_user();
   if (!filled_out($_POST))
   {
     throw new Exception('Форма заполнена не полностью.');
   }

   // Проверить формат URL
   if (strstr($new_url, 'http://')===false)
      $new_url = 'http://'.$new_url;

   // Проверить допустимость URL
   if (!(@fopen($new_url, 'r')))
     throw new Exception('Недопустимый URL-адрес.');

   // Попытаться добавить закладку
   add_bm($new_url);
   echo 'Закладка добавлена.';

   // Получить закладки, сохраненные данным пользователем
   if ($url_array = get_user_urls($_SESSION['valid_user']))
     display_user_urls($url_array);
  }
  catch (Exception $e)
  {
    echo $e->getMessage();
  }
  display_user_menu(); 
  do_html_footer();
?>

Библиотека функций url_fns.php

<?php
require_once('db_fns.php');

function get_user_urls($username)
{
  // Извлекает из базы данных все сохраненные пользователем URL-адреса
  $conn = db_connect();
  $result = $conn->query( "select bm_URL
                           from bookmark
                           where username = '$username'");
  if (!$result)
    return false;

  // Создать массив URL-адресов
  $url_array = array();
  for ($count = 1; $row = $result->fetch_row(); ++$count)
  {
    $url_array[$count] = $row[0];
  }
  return $url_array;
};
  
function add_bm($new_url)
{
  // Добавляет новую закладку в базу данных

  echo "Попытка добавления ".htmlspecialchars($new_url).'<br />';
  $valid_user = $_SESSION['valid_user'];
  
  $conn = db_connect();

  // Проверить, существует ли такая закладка
  $result = $conn->query("select * from bookmark
                         where username='$valid_user' 
                         and bm_URL='$new_url'");
  if ($result & ($result->num_rows>0))
    throw new Exception('Такая закладка уже существует.');

  // Вставить новую закладку
  if (!$conn->query( "insert into bookmark values
                     ('$valid_user', '$new_url')"))
    throw new Exception('Не удается вставить закладку в базу данных.'); 

  return true;
} 

function delete_bm($user, $url)
{
  // Удаляет один URL-адрес из базы данных 
  $conn = db_connect();

  // Удалить закладку
  if (!$conn->query( "delete from bookmark
                      where username='$user' and bm_url='$url'"))
    throw new Exception('Закладка не может быть удалена.');
  return true;
}

function recommend_urls($valid_user, $popularity = 1)
{
  $query = "select bm_URL
             from bookmark
             where username in
                  (select distinct(b2.username)
                    from bookmark b1, bookmark b2
                    where b1.username='$valid_user'
                    and b1.username != b2.username
                    and b1.bm_URL = b2.bm_URL)
             and bm_URL not in
                              (select bm_URL
                               from bookmark
                               where username='$valid_user')
              group by bm_url
              having count(bm_url)>$popularity";

  if (!($result = $conn->query($query)))
     throw new Exception('Не удается найти закладки для рекомендации.');
  if ($result->num_rows==0)
     throw new Exception('Не удается найти закладки для рекомендации.');

  $urls = array();

  // Сформировать массив подходящих URL-адресов
  for ($count=0; $row = $result->fetch_object(); $count++)
  {
     $urls[$count] = $row->bm_URL; 
  }
                              
  return $urls; 
}

?>

Удаление закладок (delete_bms.php)

<?php
  require_once('bookmark_fns.php');
  session_start();
 
  // Создать короткие имена переменных
  $del_me = $_POST['del_me'];
  $valid_user = $_SESSION['valid_user'];
 
  do_html_header('Удаление закладок');
  check_valid_user();
  if (!filled_out($_POST))
  {
    echo 'Не выбрано ни одной закладки для удаления. '
         .'Пожалуйста, повторите попытку.';
    display_user_menu();
    do_html_footer();  
    exit;
  }
  else 
  {
    if (count($del_me) >0)
    {
      foreach($del_me as $url)
      {
        if (delete_bm($valid_user, $url))
          echo 'Удалена '.htmlspecialchars($url).'.<br />';
        else
          echo 'Невозможно удалить '.htmlspecialchars($url).'.<br />';
      }  
    }
    else
      echo 'Не выбрано ни одной закладки для удаления';
  }

  // Получить закладки, сохраненные данным пользователем
  if ($url_array = get_user_urls($valid_user));
    display_user_urls($url_array);

  display_user_menu(); 
  do_html_footer();
?>

Рекомендации по ведению закладок

<?php
  require_once('bookmark_fns.php');
  session_start();
  do_html_header('Рекомендация URL-адресов');
  try
  { 
    check_valid_user();
    $urls = recommend_urls($_SESSION['valid_user']);
    display_recommended_urls($urls); 
  }
  catch(Exception $e)
  {
    echo $e->getMessage();
  }
  display_user_menu(); 
  do_html_footer();
?>

Данный сценарий предпринимает попытку выработки рекомендаций по ведению закладок путем поиска других пользователей сайта и совпадения их закладок с закладками пользователя. Если есть такие совпадения, то, вероятно, остальные закладки также могут иметь интерес в силу «схожести» мышления двоих людей.

Выводы

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


Ресурсы для скачивания


Похожие темы

  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 1.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 2.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 3.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 4.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 5.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 6.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 7.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 8.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 9.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 10.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 11.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 12.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 13.
  • Программирование с использованием PHP и MySQL в разработке Web-приложений. Часть 14.

Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux, Open source
ArticleID=632410
ArticleTitle=Программирование с использованием PHP и MySQL в разработке Web-приложений: Часть 14. Обеспечение смены паролей пользователей. Восстановление забытых паролей. Ведение закладок
publish-date=03152011