Этот урок связан с проектом Создание регистрации на сайте на PHP + MySQL

Создание регистрации на сайте на PHP + MySQL. Часть II

Здравствуйте! Если Вы не читали первую часть статьи, то она находится здесь.

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

Исходники по этому уроку находятся здесь.

Для начала мы усовершенствуем страничку регистрации, добавив возможность загружать аватар. Исходное изображение должно быть формата jpg, gif или png. Так же оно должно быть не более 2 Мб. Не беспокойтесь, после его сжатия скриптом, размер аватара будет около 3 кб и формат jpg. Откройте страницу reg.php и допишите в теге <form> строчку enctype="multipart/form-data", как в примере:

<body>
<h2>Регистрация</h2>
<form action="save_user.php" method="post" enctype="multipart/form-data">

Далее, после поля для ввода пароля, необходимо добавить форму для загрузки аватара:

  <p>
    <label>Ваш пароль *:<br></label>
    <input name="password" type="password" size="15" maxlength="15">
  </p>
<!-- В поле для паролей (name="password" type="password") пользователь вводит свой пароль --> 
   <p>
    <label>Выберите аватар. Изображение должно быть формата jpg, gif или png:<br></label>
    <input type="FILE" name="fupload">
  </p>
<!-- В переменную fupload отправится изображение, которое выбрал пользователь -->
<p>
<input type="submit" name="submit" value="Зарегистрироваться">

Теперь сохраняем reg.php

2.Затем необходимо создать еще одно поле в таблице users. Заходим в phpmyadmin, выбираем нужную базу и таблицу.

Выставляем все значения, как на рисунке:

В это поле будет записываться путь до аватара, а сам он сохраняется в отдельную папку, назовем ее «avatars». Папка будет расположена в том же каталоге, что и остальные файлы скрипта.

3.Переходим к файлу save_user.php и дописываем следующий код после удаления пробелов у логина и пароля:

//удаляем лишние пробелы
$login = trim($login);
$password = trim($password);
 
// дописываем новое********************************************
 
//добавляем проверку на длину логина и пароля
if (strlen($login) < 3 or strlen($login) > 15) {
exit ("Логин должен состоять не менее чем из 3 символов и не более чем из 15.");
}
if (strlen($password) < 3 or strlen($password) > 15) {
exit ("Пароль должен состоять не менее чем из 3 символов и не более чем из 15.");
}
 
if (!empty($_POST['fupload'])) //проверяем, отправил ли пользователь изображение
{
$fupload=$_POST['fupload']; $fupload = trim($fupload);
  if ($fupload =='' or empty($fupload)) {
                     unset($fupload);// если переменная $fupload пуста, то удаляем ее
                                                }
}
if (!isset($fupload) or empty($fupload) or $fupload =='')
{
//если переменной не существует (пользователь не отправил изображение),то присваиваем ему заранее приготовленную картинку с надписью "нет аватара"
$avatar = "avatars/net-avatara.jpg"; //можете нарисовать net-avatara.jpg или взять в исходниках
}
else
{
//иначе - загружаем изображение пользователя
$path_to_90_directory = 'avatars/';//папка, куда будет загружаться начальная картинка и ее сжатая копия
        
if(preg_match('/[.](JPG)|(jpg)|(gif)|(GIF)|(png)|(PNG)$/',$_FILES['fupload']['name']))//проверка формата исходного изображения
          {                
                   $filename = $_FILES['fupload']['name'];
                   $source = $_FILES['fupload']['tmp_name'];
                   $target = $path_to_90_directory . $filename;
                   move_uploaded_file($source, $target);//загрузка оригинала в папку $path_to_90_directory
         if(preg_match('/[.](GIF)|(gif)$/', $filename)) {
         $im = imagecreatefromgif($path_to_90_directory.$filename) ; //если оригинал был в формате gif, то создаем изображение в этом же формате. Необходимо для последующего сжатия
         }
         if(preg_match('/[.](PNG)|(png)$/', $filename)) {
         $im = imagecreatefrompng($path_to_90_directory.$filename) ;//если оригинал был в формате png, то создаем изображение в этом же формате. Необходимо для последующего сжатия
         }
        
         if(preg_match('/[.](JPG)|(jpg)|(jpeg)|(JPEG)$/', $filename)) {
                   $im = imagecreatefromjpeg($path_to_90_directory.$filename); //если оригинал был в формате jpg, то создаем изображение в этом же формате. Необходимо для последующего сжатия
         }
//СОЗДАНИЕ КВАДРАТНОГО ИЗОБРАЖЕНИЯ И ЕГО ПОСЛЕДУЮЩЕЕ СЖАТИЕ ВЗЯТО С САЙТА www.codenet.ru
// Создание квадрата 90x90
// dest - результирующее изображение
// w - ширина изображения
// ratio - коэффициент пропорциональности
$w = 90;  // квадратная 90x90. Можно поставить и другой размер.
// создаём исходное изображение на основе
// исходного файла и определяем его размеры
$w_src = imagesx($im); //вычисляем ширину
$h_src = imagesy($im); //вычисляем высоту изображения
         // создаём пустую квадратную картинку
         // важно именно truecolor!, иначе будем иметь 8-битный результат
         $dest = imagecreatetruecolor($w,$w);
         // вырезаем квадратную серединку по x, если фото горизонтальное
         if ($w_src>$h_src)
         imagecopyresampled($dest, $im, 0, 0,
                          round((max($w_src,$h_src)-min($w_src,$h_src))/2),
                          0, $w, $w, min($w_src,$h_src), min($w_src,$h_src));
         // вырезаем квадратную верхушку по y,
         // если фото вертикальное (хотя можно тоже серединку)
         if ($w_src<$h_src)
         imagecopyresampled($dest, $im, 0, 0, 0, 0, $w, $w,
                          min($w_src,$h_src), min($w_src,$h_src));
         // квадратная картинка масштабируется без вырезок
         if ($w_src==$h_src)
         imagecopyresampled($dest, $im, 0, 0, 0, 0, $w, $w, $w_src, $w_src);
$date=time(); //вычисляем время в настоящий момент.
imagejpeg($dest, $path_to_90_directory.$date.".jpg");//сохраняем изображение формата jpg в нужную папку, именем будет текущее время. Сделано, чтобы у аватаров не было одинаковых имен.
//почему именно jpg? Он занимает очень мало места + уничтожается анимирование gif изображения, которое отвлекает пользователя. Не очень приятно читать его комментарий, когда краем глаза замечаешь какое-то движение.
$avatar = $path_to_90_directory.$date.".jpg";//заносим в переменную путь до аватара.
$delfull = $path_to_90_directory.$filename;
unlink ($delfull);//удаляем оригинал загруженного изображения, он нам больше не нужен. Задачей было - получить миниатюру.
}
else
         {
                    //в случае несоответствия формата, выдаем соответствующее сообщение
         exit ("Аватар должен быть в формате <strong>JPG,GIF или PNG</strong>");
              }
//конец процесса загрузки и присвоения переменной $avatar адреса загруженной авы
}
$password = md5($password);//шифруем пароль
$password = strrev($password);// для надежности добавим реверс
$password = $password."b3p6f";
//можно добавить несколько своих символов по вкусу, например, вписав "b3p6f". Если этот пароль будут взламывать методом подбора у себя на сервере этой же md5,то явно ничего хорошего не выйдет. Но советую ставить другие символы, можно в начале строки или в середине.
//При этом необходимо увеличить длину поля password в базе. Зашифрованный пароль может получится гораздо большего размера.
// дописали новое********************************************
// Далее идет все из первой части статьи,но необходимо дописать изменение в запрос к базе.
//подключаемся к базе
include ("bd.php");// файл bd.php должен быть в той же папке, что и все остальные, если это не так, то просто измените путь
// проверка на существование пользователя с таким же логином
$result = mysql_query("SELECT id FROM users WHERE login='$login'",$db);
$myrow = mysql_fetch_array($result);
if (!empty($myrow['id'])) {
exit ("Извините, введённый вами логин уже зарегистрирован. Введите другой логин.");
}
// если такого нет, то сохраняем данные
$result2 = mysql_query ("INSERT INTO users (login,password,avatar) VALUES('$login','$password','$avatar')");
// Проверяем, есть ли ошибки
if ($result2=='TRUE')
{
echo "Вы успешно зарегистрированы! Теперь вы можете зайти на сайт. <a href='index.php'>Главная страница</a>";
}
else {
echo "Ошибка! Вы не зарегистрированы.";
     }
?>
 

4. Необходимо добавить одну таблицу в ту же базу. В ней будут хранится ip-адреса, которые допустили ошибки при входе. Таким образом мы сможем ограничить доступ тем, кто ошибся больше трёх раз подряд на минут 15. Думаю программам, подбирающим пароли, долго придется возиться.
Зайдем в phpmyadmin и создадим новую таблицу с 3-мя полями:


ip – ip-адрес.
date – дата неудачного входа за последние 15 минут у пользователя с данным ip. col – количество ошибок за последние 15 минут у пользователя с данным ip.
Отлично! Готово, теперь изменим файл проверки логина и пароля, ведь теперь у нас пароль зашифрован. Открываем testreg.php и удаляем все, что дальше удаления пробелов с логина и пароля.  Далее добавляем следующий код:

//удаляем лишние пробелы
$login = trim($login);
$password = trim($password);
 
// заменяем новым********************************************
// подключаемся к базе
include ("bd.php");// файл bd.php должен быть в той же папке, что и все остальные, если это не так, то просто измените путь
// минипроверка на подбор паролей
$ip=getenv("HTTP_X_FORWARDED_FOR");
if (empty($ip) || $ip=='unknown') { $ip=getenv("REMOTE_ADDR"); }//извлекаем ip
mysql_query ("DELETE FROM oshibka WHERE UNIX_TIMESTAMP() - UNIX_TIMESTAMP(date) > 900");//удаляем ip-адреса ошибавшихся при входе пользователей через 15 минут.
$result = mysql_query("SELECT col FROM oshibka WHERE ip='$ip'",$db);// извлекаем из базы количество неудачных попыток входа за последние 15 у пользователя с данным ip
$myrow = mysql_fetch_array($result);
if ($myrow['col'] > 2) {
//если ошибок больше двух, т.е три, то выдаем сообщение.
exit("Вы набрали логин или пароль неверно 3 раз. Подождите 15 минут до следующей попытки.");
}
$password = md5($password);//шифруем пароль
$password = strrev($password);// для надежности добавим реверс
$password = $password."b3p6f";
//можно добавить несколько своих символов по вкусу, например, вписав "b3p6f". Если этот пароль будут взламывать методом подбора у себя на сервере этой же md5,то явно ничего хорошего не выйдет. Но советую ставить другие символы, можно в начале строки или в середине.
//При этом необходимо увеличить длину поля password в базе. Зашифрованный пароль может получится гораздо большего размера.
 
$result = mysql_query("SELECT * FROM users WHERE login='$login' AND password='$password'",$db); //извлекаем из базы все данные о пользователе с введенным логином и паролем
$myrow = mysql_fetch_array($result);
if (empty($myrow['id']))
{
//если пользователя с введенным логином и паролем не существует
//Делаем запись о том, что данный ip не смог войти.
$select = mysql_query ("SELECT ip FROM oshibka WHERE ip='$ip'");
$tmp = mysql_fetch_row ($select);
if ($ip == $tmp[0]) {//проверяем, есть ли пользователь в таблице "oshibka"
$result52 = mysql_query("SELECT col FROM oshibka WHERE ip='$ip'",$db);
$myrow52 = mysql_fetch_array($result52);
$col = $myrow52[0] + 1;//прибавляем еще одну попытку неудачного входа
mysql_query ("UPDATE oshibka SET col=$col,date=NOW() WHERE ip='$ip'");
}
else {
mysql_query ("INSERT INTO oshibka (ip,date,col) VALUES ('$ip',NOW(),'1')");
//если за последние 15 минут ошибок не было, то вставляем новую запись в таблицу "oshibka"
}
 
exit ("Извините, введённый вами логин или пароль неверный.");
}
else {
nbsp;         //если пароли совпадают, то запускаем пользователю сессию! Можете его поздравить, он вошел!
          $_SESSION['password']=$myrow['password'];
                     $_SESSION['login']=$myrow['login'];
          $_SESSION['id']=$myrow['id'];//эти данные очень часто используются, вот их и будет "носить с собой" вошедший пользователь
                    
//Далее мы запоминаем данные в куки, для последующего входа.
//ВНИМАНИЕ!!! ДЕЛАЙТЕ ЭТО НА ВАШЕ УСМОТРЕНИЕ, ТАК КАК ДАННЫЕ ХРАНЯТСЯ В КУКАХ БЕЗ ШИФРОВКИ
if ($_POST['save'] == 1) {
//Если пользователь хочет, чтобы его данные сохранились для последующего входа, то сохраняем в куках его браузера
setcookie("login", $_POST["login"], time()+9999999);
setcookie("password", $_POST["password"], time()+9999999);
}}                 
echo "<html><head><meta http-equiv='Refresh' content='0; URL=index.php'></head></html>";//перенаправляем пользователя на главную страничку, там ему и сообщим об удачном входе
?>

5. Полностью изменим главную страничку. Необходимо на ней вывести аватар пользователя, вывести ссылку на выход из аккаунта и добавить чекбокс для запоминания пароля при входе.
Index.php

<?php 
// вся процедура работает на сессиях. Именно в ней хранятся данные пользователя, пока он находится на сайте. Очень важно запустить их в самом начале странички!!!
session_start();
include ("bd.php");// файл bd.php должен быть в той же папке, что и все остальные, если это не так, то просто измените путь
if (!empty($_SESSION['login']) and !empty($_SESSION['password']))
{
//если существует логин и пароль в сессиях, то проверяем их и извлекаем аватар
$login = $_SESSION['login'];
$password = $_SESSION['password'];
$result = mysql_query("SELECT id,avatar FROM users WHERE login='$login' AND password='$password'",$db);
$myrow = mysql_fetch_array($result);
//извлекаем нужные данные о пользователе
}
?>
<html>
<head>
<title>Главная страница</title>
</head>
<body>
<h2>Главная страница</h2>
 
<?php
if (!isset($myrow['avatar']) or $myrow['avatar']=='') {
//проверяем, не извлечены ли данные пользователя из базы. Если нет, то он не вошел, либо пароль в сессии неверный. Выводим окно для входа. Но мы не будем его выводить для вошедших, им оно уже не нужно.
print <<<HERE
<form action="testreg.php" method="post">
<!-- testreg.php - это адрес обработчика. То есть, после нажатия на кнопку "Войти", данные из полей отправятся на страничку testreg.php методом "post"  -->
  <p>
    <label>Ваш логин:<br></label>
    <input name="login" type="text" size="15" maxlength="15"
HERE;
        
if (isset($_COOKIE['login'])) //есть ли переменная с логином в COOKIE. Должна быть, если пользователь при предыдущем входе нажал на чекбокс "Запомнить меня"
{
//если да, то вставляем в форму ее значение. При этом пользователю отображается, что его логин уже вписан в нужную графу
echo ' value="'.$_COOKIE['login'].'">';
}
 
print <<<HERE
  </p>
<!-- В текстовое поле (name="login" type="text") пользователь вводит свой логин --> 
  <p>
    <label>Ваш пароль:<br></label>
    <input name="password" type="password" size="15" maxlength="15"
HERE;
        
if (isset($_COOKIE['password']))//есть ли переменная с паролем в COOKIE. Должна быть, если пользователь при предыдущем входе нажал на чекбокс "Запомнить меня"
{
//если да, то вставляем в форму ее значение. При этом пользователю отображается, что его пароль уже вписан в нужную графу
echo ' value="'.$_COOKIE['password'].'">';
}
        
print <<<HERE
  </p>
<!-- В поле для паролей (name="password" type="password") пользователь вводит свой пароль --> 
  <p>
    <input name="save" type="checkbox" value='1'> Запомнить меня.
  </p>
<p>
<input type="submit" name="submit" value="Войти">
<!-- Кнопочка (type="submit") отправляет данные на страничку testreg.php  -->
<br>
<!-- ссылка на регистрацию, ведь как-то же должны гости туда попадать  -->
<a href="reg.php">Зарегистрироваться</a>
</p></form>
<br>
Вы вошли на сайт, как гость<br><a href='#'>Эта ссылка доступна только зарегистрированным пользователям</a>
HERE;
}
else
{
//при удачном входе пользователю выдается все, что расположено ниже между звездочками.
//************************************************************************************
 
print <<<HERE
<!-- Между оператором  "print <<<HERE" выводится html код с нужными переменными из php -->
Вы вошли на сайт, как $_SESSION[login] (<a href='exit.php'>выход</a>)<br>
<!-- выше ссылка на выход из аккаунта -->
<a href='http://tvpavlovsk.sk6.ru/'>Эта ссылка доступна только зарегистрированным пользователям</a><br>
Ваш аватар:<br>
<img alt='$_SESSION[login]' src='$myrow[avatar]'>
<!-- Выше отображается аватар. Его адрес содержит переменная $myrow[avatar] -->
<!-- Именно здесь можно добавлять формы для отправки комментариев и прочего... -->
HERE;
 
//************************************************************************************
//при удачном входе пользователю выдается все, что расположено ВЫШЕ между звездочками.
}
?>
</body>
</html>

6. Необходимо сделать возможность выйти из аккаунта пользователям, которые вошли. На главной странице уже была ссылка на выход. Но этого файла пока не существует. Так создадим новый файл exit.php с кодом:

<?php
session_start();
if (empty($_SESSION['login']) or empty($_SESSION['password']))
{
//если не существует сессии с логином и паролем, значит на этот файл попал невошедший пользователь. Ему тут не место. Выдаем сообщение об ошибке, останавливаем скрипт
exit ("Доступ на эту страницу разрешен только зарегистрированным пользователям. Если вы зарегистрированы, то войдите на сайт под своим логином и паролем<br><a href='index.php'>Главная страница</a>");
}

unset($_SESSION['password']);
unset($_SESSION['login']);
unset($_SESSION['id']);// уничтожаем переменные в сессиях
exit("<html><head><meta http-equiv='Refresh' content='0; URL=index.php'></head></html>");
// отправляем пользователя на главную страницу.
?>

Ну вот и все! Пользуйтесь на здоровье! Удачи!

Автор: Стороженко Евгений. Опубликовал: Максим Шкурупий :) !

Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: www.ruseller.com
Автор: Максим Шкурупий
Урок создан: 27 Июля 2009
Просмотров: 392736
Правила перепечатки


5 последних уроков рубрики "PHP"

  • Фильтрация данных с помощью zend-filter

    Когда речь идёт о безопасности веб-сайта, то фраза "фильтруйте всё, экранируйте всё" всегда будет актуальна. Сегодня поговорим о фильтрации данных.

  • Контекстное экранирование с помощью zend-escaper

    Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.

  • Подключение Zend модулей к Expressive

    Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.

  • Совет: отправка информации в Google Analytics через API

    Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.

  • Подборка PHP песочниц

    Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.

^ Наверх ^