PHP

Скрипт форума на PHP своими руками. Часть 4

Итак, продолжаем наш разговор о пользователях сайта. Если пользователь забыл свой пароль, он может получить новый, заполнив форму, которую формирует функция newPasswordForm():
<?php 
// Если пользователь забыл свой пароль, он может получить новый, 
// заполнив эту форму (свой логин и e-mail) 
function newPasswordForm() 
{ 
  $html = ''; 
  if ( isset( $_SESSION['newPasswordForm']['error'] ) ) { 
    $info = file_get_contents( './templates/infoMessage.html' ); 
    $info = str_replace( '{infoMessage}', $_SESSION['newPasswordForm']['error'], $info ); 
    $html = $html.$info."n"; 
    unset( $_SESSION['newPasswordForm']['error'] ); 
  }   
  $action = $_SERVER['PHP_SELF'].'?action=sendNewPassword'; 
  $tpl = file_get_contents( './templates/newPasswordForm.html' ); 
  $tpl = str_replace( '{action}', $action, $tpl ); 
  $html = $html . $tpl; 
  return $html; 
} 
?>

Обработчик этой формы - функция sendNewPassword() высылает на e-mail пользователя новый пароль.
<?php 
// Функция высылает на e-mail пользователя новый пароль 
function sendNewPassword() 
{ 

  // Если не переданы методом POST логин и e-mail - перенаправляем пользователя 
  if ( !isset( $_POST['username'] ) or 
       !isset( $_POST['email'] ) 
      )  
  { 
    header( 'Location: '.$_SERVER['PHP_SELF'] ); 
    die(); 
  } 

  // Обрезаем переменные до длины, указанной в параметре maxlength тега input 
  $name  = substr( $_POST['username'], 0, 30 ); 
  $email = substr( $_POST['email'], 0, 60 ); 

  // Обрезаем лишние пробелы 
  $name = trim( $name ); 
  $email = trim( $email ); 

  // Проверяем, заполнены ли обязательные поля 
  $error = ""; 
  if ( empty( $name ) ) $error = $error.'<li>не заполнено поле "Имя"</li>'."n"; 
  if ( empty( $email ) ) $error = $error.'<li>не заполнено поле "Адрес e-mail"</li>'."n"; 

  // Проверяем поля формы на недопустимые символы 
  if ( !empty( $name ) and !ereg( "[-_[:blank:]0-9a-zA-Zа-яА-Я]+", $name ) ) 
    $error = $error.'<li>поле "Имя" содержит недопустимые символы</li>'."n"; 
  // Проверяем корректность e-mail 
  if ( !empty( $email ) and !preg_match( "#^[0-9a-z_-.]+@[0-9a-z-.]+.[a-z]{2,6}$#i", $email ) ) 
    $error = $error.'<li>поле "Адрес e-mail" должно соответствовать формату somebody@somewhere.ru</li>'."n"; 
  // Проверять существование такого пользователя есть смысл только в том 
  // случае, если поля не пустые и не содержат недопустимых символов 
  if ( empty( $error ) ) {     
    $query = "SELECT id_author FROM ".TABLE_USERS."  
              WHERE name='".mysql_real_escape_string( $name )."'  
              AND email='".mysql_real_escape_string( $email )."'"; 
    $res = mysql_query( $query ); 
    if ( !$res ) { 
      $msg = 'Ошибка при создании нового пароля.'; 
      $err = 'Ошибка при выполнении запроса: <br/>'. 
             $query.'<br/>'.mysql_errno().': '.mysql_error().'<br/>'. 
             '(Файл '. __FILE__ .', строка '. __LINE__ .')'; 
      return showErrorMessage( $msg, $err, true, 'action=newPasswordForm' ); 
    } 
     
    // Если пользователь с таким логином и e-mail существует 
    if ( mysql_num_rows( $res ) > 0 ) { 
      // Небольшой код, который читает содержимое директории activate 
      // и удаляет старые файлы для активации пароля (были созданы более суток назад) 
      if ( $dir = opendir( './activate' ) ) { 
        chdir( './activate' ); 
        $tmp = 24*60*60; 
        while ( false !== ( $file = readdir($dir) ) ) {  
          if ( is_file( $file ) )  
            if ( ( time() - filemtime( $file ) ) > $tmp ) unlink( $file ); 
        } 
        chdir( '..' ); 
        closedir( $dir ); 
      } 
      // Как происходит процедура восстановления пароля? Пользователь ввел свой логин 
      // и e-mail, мы проверяем существование такого пользователя в таблице БД. Потом 
      // генерируем с помощью функции getNewPassword() новый пароль, создаем файл с именем 
      // md5( $newPassword ) в директории activate. Файл содержит ID пользователя. 
      // В качестве кода активации выступает хэш пароля - md5( $newPassword ).  
      // Когда пользователь перейдет по ссылке в письме для активации своего нового пароля, 
      // мы проверяем наличие в директории activate файла с именем кода активации, 
      // и если он существует, активируем новый пароль. 
      $id = mysql_result( $res, 0, 0 ); 
      $newPassword = getNewPassword(); 
      $code = md5( $newPassword ); 
      // file_put_contents( './activate/'.$code, $id ); 
      $fp = fopen( './activate/'.$code, "w" ); 
      fwrite($fp, $id); 
      fclose($fp); 
      // Посылаем письмо пользователю с просьбой активировать пароль 
      $headers = "From: ".$_SERVER['SERVER_NAME']." <".ADMIN_EMAIL.">n"; 
      $headers = $headers."Content-type: text/html; charset="windows-1251"n"; 
      $headers = $headers."Return-path: <".ADMIN_EMAIL.">n"; 
      $message = '<p>Добрый день, '.$name.'!</p>'."n"; 
      $message = $message.'<p>Вы получили это письмо потому, что вы (либо кто-то, выдающий себя  
                 за вас) попросили выслать новый пароль к вашей учётной записи на форуме '. 
                 $_SERVER['SERVER_NAME'].'. Если вы не просили выслать пароль, то не обращайте  
                 внимания на это письмо, если же подобные письма будут продолжать приходить,  
                 обратитесь к администратору форума</p>'."n"; 
      $message = $message.'<p>Прежде чем использовать новый пароль, вы должны его активировать.  
                 Для этого перейдите по ссылке:</p>'."n"; 
      $link = 'http://'.$_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF']. 
              '?action=activatePassword&code='.$code;         
      $message = $message.'<p><a href="'.$link.'">Активировать пароль</a></p>'."n"; 
      $message = $message.'<p>В случае успешной активации вы сможете входить в систему, используя  
                 следующий пароль: '.$newPassword.'</p>'."n"; 
      $message = $message.'<p>Вы сможете сменить этот пароль на странице редактирования профиля.  
                 Если у вас возникнут какие-то трудности, обратитесь к администратору форума.</p>'."n"; 
      $subject = 'Активация пароля на форуме '.$_SERVER['SERVER_NAME']; 
      $subject = '=?koi8-r?B?'.base64_encode(convert_cyr_string($subject, "w","k")).'?='; 
      mail( $email, $subject, $message, $headers ); 
  
      $msg = 'На ваш e-mail выслано письмо. Чтобы активировать новый пароль, зайдите  
              по адресу, указанному в письме.'; 
      $html = file_get_contents( './templates/infoMessage.html' ); 
      $html = str_replace( '{infoMessage}', $msg, $html ); 
       
      return $html;   
    } else { 
      $error = $error.'<li>неправильный логин или e-mail</li>'."n"; 
    } 
  } 
     
  // Если были допущены ошибки при заполнении формы - перенаправляем посетителя 
  if ( !empty( $error ) ) { 
    $_SESSION['newPasswordForm'] = array(); 
    $_SESSION['newPasswordForm']['error'] = '<p class="errorMsg">При заполнениии формы были допущены 
    ошибки:</p>'."n".'<ul class="errorMsg">'."n".$error.'</ul>'."n"; 
    header( 'Location: '.$_SERVER['PHP_SELF'].'?action=newPasswordForm' ); 
    die(); 
  } 

} 
?>

Как происходит процедура восстановления пароля? Пользователь вводит свой логин и e-mail, мы проверяем существование такого пользователя в таблице БД. Потом генерируем с помощью функции getNewPassword() новый пароль, создаем файл с именем md5( $newPassword ) в директории activate. Файл содержит ID пользователя. В качестве кода активации выступает хэш пароля - md5( $newPassword ). Когда пользователь перейдет по ссылке в письме для активации своего нового пароля, мы проверяем наличие в директории activate файла с именем кода активации, и если он существует, активируем новый пароль.
<?php 
// Активация нового пароля 
function activatePassword() 
{ 
  if ( !isset( $_GET['code'] ) ) { 
    header( 'Location: '.$_SERVER['PHP_SELF'] ); 
    die(); 
  } 
  // Т.к. код активации создан с помощью md5, то он  
  // представляет собой 32-значное шестнадцатеричное число 
  $code = substr( $_GET['code'], 0, 32 ); 
  $code = preg_replace( "#[^0-9a-f]#i", '', $code ); 
  if ( is_file( './activate/'.$code ) and  ( ( time() - filemtime('./activate/'.$code) ) < 24*60*60 ) ) { 
    $file = file( './activate/'.$code ); 
    unlink( './activate/'.$code ); 
    $id_user = (int)trim( $file[0] ); 
    $query = "UPDATE ".TABLE_USERS."  
              SET passw='".mysql_real_escape_string( $code )."'  
              WHERE id_author=".$id_user; 
    $res = mysql_query( $query ); 
    if ( !$res ) { 
      $msg = 'Ошибка при активации нового пароля. Обратитесь к администратору.'; 
      $err = 'Ошибка при выполнении запроса: <br/>'. 
             $query.'<br/>'.mysql_errno().': '.mysql_error().'<br/>'. 
             '(Файл '. __FILE__ .', строка '. __LINE__ .')'; 
      return showErrorMessage( $msg, $err, true, 'action=newPasswordForm' ); 
    }   
    $message = 'Ваш новый пароль успешно активирован.'; 
  } else { 
    $message = 'Ошибка при активации нового пароля. Обратитесь к администратору.'; 
  } 
   
  $html = file_get_contents( './templates/infoMessage.html' ); 
  $html = str_replace( '{infoMessage}', $message, $html ); 
  return $html; 
} 
?>

Функция getNewPassword() возвращает случайно сгенерированный пароль:
<?php 
// Функция возвращает случайно сгенерированный пароль 
function getNewPassword() 
{ 
  $length = rand( 10, 30 ); 
  $password = ''; 
  for( $i = 0; $i < $length; $i++ ) { 
    $range = rand(1, 3); 
    switch( $range ) { 
      case 1: $password = $password.chr( rand(48, 57) );  break; 
      case 2: $password = $password.chr( rand(65, 90) );  break; 
      case 3: $password = $password.chr( rand(97, 122) ); break; 
    } 
  } 
  return $password; 
} 
?>

Пользователь должен иметь возможность изменить свои данные - за это отвечают функции getEditUserForm() и updateUser().
<?php 
// Функция возвращает html формы для редактирования данных о пользователе 
function getEditUserForm() 
{ 
  // Если информацию о пользователе пытается редактировать  
  // не зарегистрированный пользователь 
  if ( !isset( $_SESSION['user'] ) ) { 
    header( 'Location: '.$_SERVER['PHP_SELF'] ); 
    die(); 
  } 
   
  $html = ''; 
   
  // Если при заполнении формы были допущены ошибки 
  if ( isset( $_SESSION['editUserForm'] ) ) { 
    $info = file_get_contents( './templates/infoMessage.html' ); 
    $info = str_replace( '{infoMessage}', $_SESSION['editUserForm']['error'], $info ); 
    $html = $html.$info."n"; 
    $email     = htmlspecialchars( $_SESSION['editUserForm']['email'] ); 
    $timezone  = $_SESSION['editUserForm']['timezone']; 
    $icq       = htmlspecialchars( $_SESSION['editUserForm']['icq'] ); 
    $url       = htmlspecialchars( $_SESSION['editUserForm']['url'] ); 
    $about     = htmlspecialchars( $_SESSION['editUserForm']['about'] ); 
    $signature = htmlspecialchars( $_SESSION['editUserForm']['signature'] ); 
    unset( $_SESSION['editUserForm'] ); 
  } else { 
    $email     = htmlspecialchars( $_SESSION['user']['email'] ); 
    $timezone  = 0; 
    $icq       = htmlspecialchars( $_SESSION['user']['icq'] ); 
    $url       = htmlspecialchars( $_SESSION['user']['url'] ); 
    $about     = htmlspecialchars( $_SESSION['user']['about'] ); 
    $signature = htmlspecialchars( $_SESSION['user']['signature'] ); 
  } 
   
  $action = $_SERVER['PHP_SELF'].'?action=updateUser'; 
   
  $tpl = file_get_contents( './templates/editUserForm.html' ); 
  $tpl = str_replace( '{action}', $action, $tpl ); 
  $tpl = str_replace( '{email}', htmlspecialchars( $email ), $tpl ); 
  $tpl = str_replace( '{icq}', htmlspecialchars( $icq ), $tpl ); 
  $tpl = str_replace( '{url}', htmlspecialchars( $url ), $tpl ); 
  $tpl = str_replace( '{about}', htmlspecialchars( $about ), $tpl ); 
  $tpl = str_replace( '{signature}', htmlspecialchars( $signature ), $tpl ); 
   
  $options = ''; 
  for ( $i = -12; $i <= 12; $i++ ) { 
    if ( $i < 1 )  
      $value = $i.' часов'; 
    else 
      $value = '+'.$i.' часов'; 
    if ( $i == $_SESSION['user']['timezone'] ) 
      $options = $options . '<option value="'.$i.'" selected>'.$value.'</option>'."n"; 
    else 
      $options = $options . '<option value="'.$i.'">'.$value.'</option>'."n"; 
  } 
  $tpl = str_replace( '{options}', $options, $tpl); 
  $tpl = str_replace( '{servertime}', date( "d.m.Y H:i:s" ), $tpl ); 
  // Если ранее был загружен файл - надо предоставить возможность удалить его 
  $unlinkfile = ''; 
  if ( is_file( './photo/'.$_SESSION['user']['id_author'] ) ) { 
    $unlinkfile = '<br/><input type="checkbox" name="unlink" value="1" /> 
                  Удалить загруженный ранее файл'."n"; 
  } 
  $tpl = str_replace( '{unlinkfile}', $unlinkfile, $tpl ); 
   
  $html = $html.$tpl; 
   
  return $html; 
} 
?>

Обработчик формы:
<?php 
// Функция обновляет данные пользователя (обновляет запись в таблице TABLE_USERS) 
function updateUser() 
{ 
  // Если это не зарегистрированный пользователь - функция вызвана по ошибке 
  if ( !isset( $_SESSION['user'] ) ) { 
    header( 'Location: '.$_SERVER['PHP_SELF'] ); 
    die(); 
  } 

  // Если не переданы данные формы - функция вызвана по ошибке 
  if ( !isset( $_POST['timezone'] ) or 
       !isset( $_POST['icq'] ) or 
       !isset( $_POST['url'] ) or 
       !isset( $_POST['about'] ) or 
       !isset( $_POST['signature'] ) or 
       !isset( $_FILES['avatar'] )  
    ) 
  { 
    header( 'Location: '.$_SERVER['PHP_SELF'] ); 
    die(); 
  } 

  // Обрезаем переменные до длины, указанной в параметре maxlength тега input 
  $password     = substr( $_POST['password'], 0, 30 ); 
  $newpassword  = substr( $_POST['newpassword'], 0, 30 ); 
  $confirm      = substr( $_POST['confirm'], 0, 30 ); 
  $email        = substr( $_POST['email'], 0, 60 ); 
  $icq          = substr( $_POST['icq'], 0, 12 ); 
  $url          = substr( $_POST['url'], 0, 60 ); 
  $about        = substr( $_POST['about'], 0, 1000 ); 
  $signature    = substr( $_POST['signature'], 0, 500 ); 

  // Обрезаем лишние пробелы 
  $password     = trim( $password ); 
  $newpassword  = trim( $newpassword ); 
  $confirm      = trim( $confirm ); 
  $email        = trim( $email ); 
  $icq          = trim( $icq ); 
  $url          = trim( $url ); 
  $about        = trim( $about ); 
  $signature    = trim( $signature ); 

  // Проверяем, заполнены ли обязательные поля 
  $error = ''; 
   
  // Если заполнено поле "Текущий пароль" - значит пользователь 
  // хочет изменить его или поменять свой e-mail  
  $changePassword = false; 
  $changeEmail = false; 
  if ( !empty( $_POST['password'] ) ) { 
    if ( md5( $_POST['password'] ) != $_SESSION['user']['passw'] )  
      $error = $error.'<li>текущий пароль введен не верно</li>'."n"; 
    // Надо выяснить, что хочет сделать пользователь:  
    // поменять свой e-mail, изменить пароль или и то и другое 
    if ( !empty( $newpassword ) ) { // хочет изменить пароль 
      $changePassword = true; 
      if ( empty( $confirm ) ) $error = $error.'<li>не заполнено поле "Подтвердите пароль"</li>'."n"; 
      // Проверяем, не слишком ли короткий новый пароль 
      if ( strlen( $newpassword ) < MIN_PASSWORD_LENGTH ) 
        $error = $error.'<li>длина пароля должна быть не меньше '.MIN_PASSWORD_LENGTH.' символов</li>'."n"; 
      // Проверяем, совпадают ли пароли 
      if ( !empty( $confirm ) and $newpassword != $confirm )  
        $error = $error.'<li>не совпадают пароли</li>'."n"; 
      // Проверяем поля формы на недопустимые символы 
      if (  !preg_match( "#^[-_0-9a-z]+$#i", $newpassword ) ) 
        $error = $error.'<li>поле "Новый пароль" содержит недопустимые символы</li>'."n"; 
      if ( !empty( $confirm ) and !preg_match( "#^[-_0-9a-z]+$#i", $confirm ) ) 
        $error = $error.'<li>поле "Подтвердите пароль" содержит недопустимые символы</li>'."n"; 
    } 
    if ( $email != $_SESSION['user']['email'] ) { // хочет изменить e-mail 
      $changeEmail = true; 
      if ( empty( $email ) ) $error = $error.'<li>не заполнено поле "Адрес e-mail"</li>'."n"; 
      // Проверяем корректность e-mail 
      if ( !empty( $email ) and !preg_match( "#^[0-9a-z_-.]+@[0-9a-z-.]+.[a-z]{2,6}$#i", $email ) ) 
        $error = $error.'<li>поле "Адрес e-mail" должно соответствовать формату  
                 somebody@somewhere.ru</li>'."n";     
    }   
  }   
   
  // Проверяем поля формы на недопустимые символы 
  if ( !empty( $icq ) and !preg_match( "#^[0-9]+$#", $icq ) ) 
    $error = $error.'<li>поле "ICQ" содержит недопустимые символы</li>'."n"; 
  if ( !empty( $about ) and !preg_match( "#^[-[].;:,?!/)(_"s0-9а-яА-Яa-z]+$#i", $about ) ) 
    $error = $error.'<li>поле "Интересы" содержит недопустимые символы</li>'."n"; 
  if ( !empty( $signature ) and !preg_match( "#^[-[].;:,?!/)(_"s0-9а-яА-Яa-z]+$#i", $signature ) ) 
    $error = $error.'<li>поле "Подпись" содержит недопустимые символы</li>'."n"; 
     
  // Проверяем корректность URL домашней странички     
  if ( !empty( $url ) and !preg_match( "#^(http://)?(www.)?[-0-9a-z]+.[a-z]{2,6}/?$#i", $url ) ) 
    $error = $error.'<li>поле "Домашняя страничка" должно соответствовать формату http://www.homepage.ru</li>'."n";

  if ( !empty( $_FILES['avatar']['name'] ) ) { 
    $ext = strrchr( $_FILES['avatar']['name'], "." ); 
    $extensions = array( ".jpg", ".gif", ".bmp", ".png" ); 
    if ( !in_array( $ext, $extensions ) )  
      $error = $error.'<li>недопустимый формат файла аватара</li>'."n"; 
    if ( $_FILES['avatar']['size'] > MAX_AVATAR_SIZE )  
      $error = $error.'<li>размер файла аватора больше '.(MAX_AVATAR_SIZE/1024).' Кб</li>'."n"; 
  } 

  $timezone = (int)$_POST['timezone']; 
  if ( $timezone < -12 or $timezone > 12 ) $timezone = 0; 

  // Если были допущены ошибки при заполнении формы -  
  // перенаправляем посетителя на страницу редактирования 
  if ( !empty( $error ) ) { 
    $_SESSION['editUserForm'] = array(); 
    $_SESSION['editUserForm']['error'] = '<p class="errorMsg">При заполнениии формы были допущены ошибки:</p>'. 
    "n".'<ul class="errorMsg">'."n".$error.'</ul>'."n"; 
    $_SESSION['editUserForm']['email'] = $email; 
    $_SESSION['editUserForm']['timezone'] = $timezone; 
    $_SESSION['editUserForm']['icq'] = $icq; 
    $_SESSION['editUserForm']['url'] = $url; 
    $_SESSION['editUserForm']['about'] = $about; 
    $_SESSION['editUserForm']['signature'] = $signature; 
    header( 'Location: '.$_SERVER['PHP_SELF'].'?action=editUserForm' ); 
    die(); 
  }     

  // Если выставлен флажок "Удалить загруженный ранее файл" 
  if ( isset( $_POST['unlink'] ) and is_file( './photo/'.$_SESSION['user']['id_author'] ) ) { 
    unlink( './photo/'.$_SESSION['user']['id_author'] ); 
  }  
  if ( !empty( $_FILES['avatar']['name'] ) and  
       move_uploaded_file ( $_FILES['avatar']['tmp_name'], './photo/'.$_SESSION['user']['id_author'] ) ) { 
    chmod( './photo/'.$_SESSION['user']['id_author'], 0644 ); 
  } 
   
  // Все поля заполнены правильно - записываем изменения в БД 
  $tmp = '';   
  if ( $changePassword ) { 
    $tmp = $tmp."passw='".mysql_real_escape_string( md5( $newpassword ) )."', "; 
    $_SESSION['user']['passw'] = md5( $newpassword ); 
  } 
  if ( $changeEmail ) { 
    $tmp = $tmp."email='".mysql_real_escape_string( $email )."', "; 
    $_SESSION['user']['email'] = $email; 
  } 
  $query = "UPDATE ".TABLE_USERS." SET ".$tmp." 
            timezone=".$timezone.", 
            url='".mysql_real_escape_string( $url )."', 
            icq='".$icq."', 
            about='".mysql_real_escape_string( $about )."', 
            signature='".mysql_real_escape_string( $signature )."' 
            WHERE id_author=".$_SESSION['user']['id_author']; 
            //echo $query; 
            //die(); 
  $res = mysql_query( $query ); 
  if ( !$res ) { 
    $msg = 'Ошибка при обновлении профиля'; 
    $err = 'Ошибка при выполнении запроса: <br/>'. 
           $query.'<br/>'.mysql_errno().': '.mysql_error().'<br/>'. 
          '(Файл '. __FILE__ .', строка '. __LINE__ .')'; 
    return showErrorMessage( $msg, $err, true, '' ); 
  } 
  // Теперь надо обновить данные о пользователе в массиве $_SESSION['user'] 
  if ( $changePassword ) $_SESSION['user']['passw'] = md5( $newpassword ); 
  if ( $changeEmail ) $_SESSION['user']['email'] = $email; 
  $_SESSION['user']['timezone'] = $timezone; 
  $_SESSION['user']['url'] = $url; 
  $_SESSION['user']['icq'] = $icq; 
  $_SESSION['user']['about'] = $about; 
  $_SESSION['user']['signature'] = $signature; 
  // ... и в массиве $_COOKIES 
  if ( isset( $_COOKIE['autologin'] ) ) { 
    $tmppos = strrpos( $_SERVER['PHP_SELF'], '/' ) + 1; 
    $path = substr( $_SERVER['PHP_SELF'], 0, $tmppos ); 
    setcookie( 'autologin', 'yes', time() + 3600*24*COOKIE_TIME, $path ); 
    setcookie( 'username', $_SESSION['user']['name'], time() + 3600*24*COOKIE_TIME, $path ); 
    setcookie( 'password', $_SESSION['user']['passw'], time() + 3600*24*COOKIE_TIME, $path ); 
  } 

  return showInfoMessage( 'Ваш профиль был изменён', '' ); 
} 
?>

Продолжение следует...
Теги:
форум
Добавлено: 22 Сентября 2013 01:42:59 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...