https://ruseller.com/lessons.php?rub_id=37&id=350
Для регистрации пользователей используются файлы:
• Страница с формой регистрации «form_registration.html».
• Страница сохранения пользователя «save_user.php».
• Страница активации пользователя «activation.php».
• Капча
Листинг 35. form_registration.html Путь: news/chat/admin/users/ form_registration.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/chat/style.css" />
<title>Регистрация на сайте</title>
</head>
<body class="chatbody">
<h2>Регистрация на сайте</h2>
<form
class="chatform"
action="save_user.php"
method="post"
enctype="multipart/form-data"
id="reg"
>
<fieldset class="chatfieldset">
<legend>Данные для авторизации</legend>
<label
>Ваш логин *: <input name="login" type="text" size="15" maxlength="15"
/></label>
<hr />
<label
>Ваш пароль *:
<input name="password" type="password" size="15" maxlength="15"
/></label>
<hr />
<label
>Ваш E-mail *:
<input name="email" type="email" size="15" maxlength="100"
/></label>
<br />
</fieldset>
<br />
<fieldset class="chatfieldset">
<legend>Выберите аватар</legend>
<label>
Изображение должно быть квадратной формы<br />
и иметь расширение jpg, gif или png:<br />
<br />
<input type="FILE" name="fupload"
/></label>
</fieldset>
<br />
<!– В переменную fupload отправится изображение, которое выбрал пользователь. –>
<fieldset class="chatfieldset">
<legend>Введите код с картинки *:</legend>
<input type="text" name="capcha" />
<div><img src="/chat/capcha/captcha.php" /></div>
</fieldset>
<p>
<input type="submit" name="submit" value="Зарегистрироваться" />
<!– Кнопочка (type="submit") отправляет данные на страничку save_user.php –>
</p>
</form>
Звездочками (*) обозначены поля, обязательные для заполнения.
<p><a href="/../">Вернуться</a></p>
</body>
</html>
Выводит страницу «Регистрация на сайте» и форму регистрации. В форме предусмотрена защита при помощи «капчи» и предлагается отправка для регистрации следующих данных: «Логин», «email», «Пароль», «Аватар».
Файлы капчи: обработчик и папка с шрифтами, выводят на форме регистрации проверочный код, который пользователь должен будет ввести.
Листинг 36. captcha.php Путь:chat\capcha\captcha.php
<?php
if (session_id() == '') {
session_start();
}
$string = "";
for ($i = 0; $i < 5; $i++) {
$string .= chr(rand(97, 122));
}
$_SESSION['rand_code'] = $string;
$dir = $_SERVER['DOCUMENT_ROOT'] . '/chat/capcha/fonts/verdana.ttf';
$image = @imagecreatetruecolor(170, 60) or die('Невозможно инициализировать GD поток'); // Создаём изображение
$black = imagecolorallocate($image, 0, 0, 0);
$color = imagecolorallocate($image, 200, 100, 90);
$white = imagecolorallocate($image, 255, 255, 255);
imagefilledrectangle($image, 0, 0, 399, 99, $white);
imagettftext($image, 30, 0, 10, 40, $color, $dir, $_SESSION['rand_code']);
header("Content-type: image/png");
imagepng($image);
Здесь в цикле генерируется строка из случайных чисел, при этом числа сразу преобразуются в символьные эквиваленты. Диапазон чисел 97-122 соответствует буквам латинского алфавита в диапазоне a-z по ASCII http://www.asciitable.com/ . Полученный набор букв в виде строки сохраняется в переменную сессии, а затем оформляется в виде изображения.
За сохранение и обработку полученных при регистрации данных пользователя отвечает файл «save_user.php»
Листинг 37. save_user.php Путь: news/chat/admin/users/ save_user.php
<?php
error_reporting(E_ALL);
if (session_id() == '') {
session_start();
}
/* заносим введенный пользователем логин в переменную $login, если он пустой, то уничтожаем переменную */
if (isset($_POST['login'])) {
$login = $_POST['login'];
if (mb_strlen($login) < 2 or mb_strlen($login) > 15) { //проверяем длину логина
exit("Логин должен состоять не менее чем из 3 символов и не более чем из 15."); //останавливаем выполнение сценариев
}
if ($login == '') {
unset($login);
}
}
/* заносим введенный пользователем пароль в переменную $password, если он пустой, то уничтожаем переменную */
if (isset($_POST['password'])) {
$password = $_POST['password'];
if (mb_strlen($password) < 3 or mb_strlen($password) > 15) { //проверяем длину пароля
exit("Пароль должен состоять не менее чем из 3 символов и не более чем из 15."); //останавливаем выполнение сценариев
}
if ($password == '') {
unset($password);
}
}
/* заносим введенный пользователем код в переменную $capcha, если он пустой, то уничтожаем переменную */
if (isset($_POST['capcha'])) {
$capcha = $_POST['capcha'];
if ($capcha == '') {
unset($capcha);
}
}
/* заносим введенный пользователем e-mail, если он пустой, то уничтожаем переменную */
if (isset($_POST['email'])) {
$email = $_POST['email'];
if ($email == '') {
unset($email);
}
}
$capcha = stripslashes($capcha); //sequrity чистим капчу
$capcha = htmlspecialchars($capcha);
$capcha = trim($capcha); //удаляем лишние пробелы
if (($capcha == $_SESSION["rand_code"]) && ($capcha != "")) { //проверяем капчу
} else {
exit("Капча введена неправильно");
}
if (empty($login) or empty($password) or empty($email) or empty($capcha)) { //если пользователь не ввел данные, то выдаем ошибку и останавливаем скрипт
exit("Вы ввели не всю информацию, вернитесь назад и заполните все поля!");
}
if (!preg_match("/[0-9a-z_]+@[0-9a-z_^\.]+\.[a-z]{2,3}/i", $email)) { //проверка е-mail адреса регулярными выражениями на корректность
exit("Неверно введен е-mail!");
}
$login = stripslashes($login); //если логин и пароль введены, то обрабатываем их, чтобы теги и скрипты не работали, мало ли что люди могут ввести
$login = htmlspecialchars($login);
$password = stripslashes($password);
$password = htmlspecialchars($password);
$login = trim($login); //удаляем лишние пробелы
$password = trim($password);
/*......................Шифруем пароль...........................*/
//можно добавить несколько своих символов по вкусу, например, вписав "she".
//Если этот пароль будут взламывать методом подбора у себя на сервере этой же md5,то явно ничего хорошего не выйдет.
//Но советую ставить другие символы, можно в начале строки или в середине.
//При этом необходимо увеличить длину поля password в базе. Зашифрованный пароль может получится гораздо большего размера.
$password = md5($_POST['password'] . 'swl'); //шифруем пароль
include $_SERVER['DOCUMENT_ROOT'] . '/chat/dsn.php'; // подключаемся к базе
$sth = $dsn->prepare("SELECT id FROM users WHERE login=:login"); // проверка на существование пользователя с таким же логином
$sth->execute(array(':login' => $login));
if (!empty($sth->fetch(PDO::FETCH_ASSOC))) {
exit("Извините, введённый вами логин уже зарегистрирован. Введите другой логин.");
}
/*....................avatar................................*/
if (empty($_FILES['fupload']['name'])) {
//если переменной не существует (пользователь не отправил изображение),то присваиваем ему заранее приготовленную картинку с надписью "нет аватара"
$avatar = "avatars/noavatar.png"; //можете нарисовать 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, то создаем изображение в этом же формате. Необходимо для последующего сжатия
}
// Создание квадрата 90x90
// dest – результирующее изображение
// w – ширина изображения
// ratio – коэффициент пропорциональности
$w = 90; // квадратная 90x90. Можно поставить и другой размер.
$h = 90;
// создаём исходное изображение на основе
// исходного файла и определяем его размеры
$w_src = imagesx($im); //вычисляем ширину
$h_src = imagesy($im); //вычисляем высоту изображения
if ($w_src !== $h_src) {
exit('<h4>Стороны изображения для загрузки должны быть равны. Например 256*256.<br>Рекомендую использовать готовые аватары со специализированных сайтов.<br>
Или подготовьте картинку в графическом редакторе</h4><br><i>p.s. грузим аватары, а не картины</i>');
}
// создаём пустую квадратную картинку
// важно именно truecolor!, иначе будем иметь 8-битный результат
$dest = imagecreatetruecolor($w, $w);
$white = imagecolorallocate($dest, 255, 255, 255);
imagefill($dest, 0, 0, $white);
imagecopyresampled($dest, $im, 0, 0, 0, 0, $w, $w, $w_src, $h_src);
$date = time(); //вычисляем время в настоящий момент.
imagejpeg($dest, $path_to_90_directory . $date . ".jpg"); //сохраняем изображение формата jpg в нужную папку, именем будет текущее время. Сделано, чтобы у аватаров не было одинаковых имен.
$avatar = $path_to_90_directory . $date . ".jpg"; //заносим в переменную путь до аватара.
$delfull = $path_to_90_directory . $filename;
unlink($delfull); //удаляем оригинал загруженного изображения, он нам больше не нужен. Задачей было – получить миниатюру.
} else {
//в случае несоответствия формата, выдаем соответствующее сообщение
exit("Аватар должен быть в формате <strong>JPG,GIF или PNG</strong>"); //останавливаем выполнение сценариев
}
//конец процесса загрузки и присвоения переменной $avatar адреса загруженной авы
}
/*.........................Сохраняем пользователя в базу......................*/
if (!isset($date)) {
$date = time();
}
try {
$sql = "INSERT INTO users (login,password,email,img,date) VALUES(:login,:password,:email,:img, :date)";
$result2 = $dsn->prepare($sql);
$result2->execute([
'login' => $login,
'password' => $password,
'email' => $email,
'img' => $avatar,
'date' => $date
]);
$role = 'user';
$authorid = $dsn->lastInsertId();
$sql = "INSERT INTO authorrole (authorid,roleid) VALUE (:authorid,:roleid)";
$resultrole = $dsn->prepare($sql);
$resultrole->execute([
'authorid' => $authorid,
'roleid' => $role
]);
echo '<img src="' . $avatar . '">';
echo ' ' . '<h3>' . $login . '</h3>' . ' ' . "Вы успешно зарегистрированы! <a href='/index.html'>Главная страница</a>";
} catch (PDOException $e) {
echo "You have an error: " . $e->getMessage() . "<br>";
echo "On line: " . $e->getLine();
}
$activation = md5($authorid) . md5($login);
$subject = "Подтверждение регистрации"; //тема сообщения
$message = "Здравствуйте! Спасибо за регистрацию в модуле комментариев chat\nВаш логин: " . $login . "\n
Перейдите по ссылке, чтобы активировать ваш аккаунт:\nhttp://" . $_SERVER['HTTP_HOST'] . "/chat/admin/users/activation.php?login=" . $login . "&code=" . $activation . "\nС уважением,\n
Администратор модуля"; //содержание сообщение
mail($email, $subject, $message, "Content-type:text/plane; Charset=utf-8\r\n"); //отправляем сообщение
echo "<hr><h3>Вам на E-mail выслано письмо с cсылкой, для подтверждения регистрации.</h3> <br><b>Внимание! Ссылка действительна 1 час.</b>"; //говорим о отправленном письме пользователю
В этом скрипте проверяются данные пользователя и сохраняются в БД. Обработка изображений для аватара сделана только для квадрата, т.к. PHP это язык серверный и обработка изображений явно не его конек. Результаты при обработке прямоугольников мягко говоря разочаровывают, поэтому загрузка и обработка прямоугольных исходников не предусмотрена. Лучше взять готовый или подготовить аватар в графическом редакторе. Код в данном скрипте прокомментирован практически построчно, думается вопросов быть не должно.
С административным разделом закончили, приступаем к комментариям.
Для работы с комментариями используем папку «say», созданную ранее в разделе 3. На данном этапе она пуста и кроме папки «smiles» в которой хранятся заранее подготовленные смайлы в ней ничего нет.
Для вывода комментариев создаем контроллер 3 «say_controller.php».
Листинг 38. say_controller.php Путь: news/chat/ say_controller.php
<?php
error_reporting(E_ALL);
include_once $_SERVER['DOCUMENT_ROOT'] .'/chat/admin/clean.php';
include $_SERVER['DOCUMENT_ROOT'].'/chat/function/print_comment.php';
include $_SERVER['DOCUMENT_ROOT'].'/chat/function/print_smile_set.php';
$page_id = $_SERVER['PHP_SELF']; //индексируем страницу
/* Если пользователь авторизован вставляем ссылку Добавить комментарий */
if (isset($_SESSION['login'])) {
$userid = $_SESSION['userid'];
echo '<div class="addsay" id=""><a href="?addsay" class="aaddsays">Добавить комментарий</a></div>';
}
else {
$userid = '';
}
/* Устанавливаем условие видимости блока комментариев и кнопок показать и скрыть комментарии */
if (isset($_GET['opensay'])) {
$display_say = 'display:none;';
$display_but = 'display:flow-root;';
}
else {
$display_say = 'display:flow-root;';
$display_but = 'display:none;';
}
/* Применяем условие видимости к кнопкам показать и скрыть комментарии */
echo '<div class="opensay" style="'.$display_but.'"><a href="?" class="aopensays">Показать комментарии</a></div>';
echo '<div class="opensay" style="'.$display_say.'"><a href="?opensay" class="aopensays">Скрыть комментарии</a></div>';
/* Вставляем форму добавить комментарий */
if (isset($_GET['addsay'])){
$pageid = strtok($_SERVER['PHP_SELF'],'?');
include_once $_SERVER['DOCUMENT_ROOT'].'/chat/say/form_addsay.html.php';
}
/* Выводим лист комментариев */
//сортируем в обратном порядке наверху последний комментарий
try {
include $_SERVER['DOCUMENT_ROOT'].'/chat/dsn.php';
$sql = 'SELECT say.id, say.userid, say.saydate, say.saytext, users.login, users.img FROM say INNER JOIN users ON users.`id` = say.userid WHERE say.page_id = :page_id ORDER BY say.id DESC';
$s = $dsn->prepare($sql);
$s -> bindValue(':page_id', $page_id);
$s -> execute();
}
catch (PDOException $e) {
echo $e->getMessage();
echo $e->getLine();
exit();
}
foreach ($s as $row) {
$say[] = array(
'id' => $row['id'],
'saytext' => $row['saytext'],
'saydate' => $row['saydate'],
'img' => $row['img'],
'login' => $row['login'],
'userid' => $row['userid']);
}
include_once $_SERVER['DOCUMENT_ROOT'].'/chat/say/form_say.html.php';
Контроллер определяет условия видимости управляющих комментариями кнопок и форм ввода комментариев, индексирует страницу и формирует массив say[] с комментариями, который будет выводится в форме form_say.html.php после обработки.
Как видим у него также есть файлы которые нужно обрабатывать. Если сейчас подключить контроллер, то на странице будет ошибка. Файлы еще не готовы. В папке «chat» создаем папку «function» в которой будут находиться функции по обработке комментариев.
Для вывода набора доступных смайлов написана функция «print_smile_set.php»
Листинг 39. print_smile_set.php Путь: news/function/ print_smile_set.php
<?php
error_reporting(E_ALL);
/* печать блока доступных смайлов в виде кнопок */
function print_smile_set()
{
try {
include $_SERVER['DOCUMENT_ROOT'] . '/chat/dsn.php';
$sql = "SELECT smile, path FROM smiles";
$s = $dsn->query($sql);
$ress = $s->fetchall();
foreach ($ress as $row) :
$smiles_key = $row['smile'];
$smile_path = $row['path']; ?>
<input type="submit" name="smile" title="<?= $smiles_key; ?>" value="<?= $smiles_key; ?>"
style="background:url(<?= $smile_path; ?> );
background-repeat: no-repeat;float:left;height:45px;border:none;
width:50px;font-size:0;" />
<?php
endforeach;
} catch (PDOException $e) {
echo $e->getMessage();
echo $e->getLine();
exit();
}
}
Смайлы сделаны в виде кнопок. В свойстве «background» кнопки идет картинка смайла. Нажатие кнопки вставляет смайл.
Внимание! Стили CSS для смайлов задаются непосредственно в скрипте в строке <input … style=””>
Для печати комментариев служит функция «print_comment.php»
Листинг 40. print_comment.php Путь: news/function/ print_comment.php
<?php
/* печать комментария со смайлами */
function comment_to_smile($comment)
{
try {
include $_SERVER['DOCUMENT_ROOT'] . '/chat/dsn.php';
$sql = "SELECT smile, path FROM smiles";
$s = $dsn->query($sql);
$ress = $s->fetchall();
foreach ($ress as $row) :
$smiles_key = $row['smile'];
$smile_path = $row['path'];
endforeach;
} catch (PDOException $e) {
echo $e->getMessage();
echo $e->getLine();
exit();
}
$smile_path = array_column($ress, 'path'); // Массив с кодами смайлов
$smiles_keys = array_column($ress, 'smile'); // Массив с соответствующими путями к изображениям смайлов
for ($i = 0; $i < count($smile_path); $i++) {
$smile_path[$i] = "<img src='" . $smile_path[$i] . "' alt='' />";//получаем изображение смайла
}
$comment = str_replace($smiles_keys, $smile_path, $comment); //Меняем в комментарии ключи смайлов на пути к смайлам
echo $comment; //печатаем комментарий со смайлами
}
Получаем из таблицы smiles массивы условных обозначений смайлов и путей к их изображениям. В цикле обрабатываем и выводим на печать комментарии со смайлами.
Страница separate_action.php получает данные из формы formaddsay.html.php и обрабатывает их. Введение этой страницы было необходимо для обнуления $_POST на странице обработки комментариев после их отправки. Если этого не сделать, то при размещении этого кода на странице с контроллером 3 при обычном обновлении страницы возникала бы проблема с его обработкой т.к. браузер обычно запоминает данные, которые отправляются с текущей страницы для того, чтобы отправить их снова при обновлении страницы и:
без обнуления переменной POST один и тот же комментарий будет добавляться до бесконечности при каждой перезагрузке страницы.
Если же мы уйдем со страницы на другую и отправим данные формы на следующую (в данном случае вернемся обратно) страницу, то браузер запомнит уже новые заголовки и при обновлении будет обрабатывать их, а при возврате они будут для страницы возврата пусты и соответственно при ее обновлении ничего не произойдет.
Листинг 41. separate_action.php Путь: news/chat/function/ print_comment.php
<?php
if(session_id() == '') {session_start();}
include_once $_SERVER['DOCUMENT_ROOT'].'./chat/admin/clean.php';
/* включаем/выключаем видимость блока смайлов */
if (isset($_POST['smileblock'])) {
$_SESSION['smileblock'] = 'display:block';
}
if (isset($_POST['smileblock_close'])) {
$_SESSION['smileblock'] = 'display:none';
}
/* Комментарии */
//если была нажата кнопка "Добавить" вставляем форму добавления комментариев,
//если была нажата кнопка "Ответить" вставляем форму ответа на комментарии,
if (isset($_POST['action']) and $_POST['action'] == 'Добавить') {
include_once $_SERVER['DOCUMENT_ROOT'].'/chat/say/makeformaddsay.php';
}
elseif (isset($_POST['action']) and $_POST['action'] == 'Ответить') {
include_once $_SERVER['DOCUMENT_ROOT'].'/chat/say/make_reply.php';
}
else {//Проверяем куда пойдет смайл в комментарии или в ответы
include_once $_SERVER['DOCUMENT_ROOT'].'/chat/say/smile_make.php';
}
Скрипт управляет отображением/скрытием блока смайлов, вставкой формы добавления комментариев и вставкой формы добавления ответов на комментарии.
Форма form_say.html.php служит для вывода комментариев
Листинг 42. form_say.html.php Путь: news/chat/say/ form_say.html.php
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="/chat/style.css" />
</head>
<div class="wrapsayform" style="<?= $display_say ?>">
<?php
include $_SERVER['DOCUMENT_ROOT'] . '/chat/say/list_reply.php';
if (!empty($say)) {
foreach ($say as $saylist) : ?>
<div class="sayform" id="">
<!– Выводим логин и дату –>
<div class="topprintcomment" id="">
<b><?php echo $saylist['login']; ?></b>
<?php $t = $saylist['saydate'];
echo '<span style="float:right;">' . date("d.m.Y", "$t") . '</span>'; ?>
</div>
<!– Выводим аватар и комментарии –>
<div class="printcomment" id="">
<p></p><img src="<?= '/chat/admin/users/' . $saylist['img'] ?>" class="sayavatar">
<?php
$comment = $saylist['saytext'];
comment_to_smile($comment); //печатаем комментарии
$post_id = $saylist['id'];
/* Активация кнопок */
if (userHasRole('admin')) {
$buttonactive = 'submit'; //если админ делаем активными все кнопки
} elseif ($saylist['userid'] == $userid) {
$buttonactive = 'submit'; //делаем активными кнопки для юзера
} else {
$buttonactive = 'hidden'; //отключаем кнопки
} ?></p>
</div><!– END printcomment –>
<!– Выводим блок кнопок –>
<div class="block_button_say" id="">
<div class="wrappersaybutton">
<div class="reply_button" id="">
<div class="postnumber" id=""><?php echo '#' . $saylist['id']; ?> </div>
<a href="?reply=<?php htmlout($post_id); ?>" class="areply">Ответить</a>
</div>
<div class="sayright">
<div class="button_say_edit">
<form name="" method="post" action="/chat/say/sayedit.php" class="logout">
<input type="hidden" name="pageid" id="" value=" <?php echo $pageid; ?>" />
<input type="hidden" name="textedit" value="<?php echo $saylist['id']; ?>">
<input type="hidden" name="saytext" id="" value="<?php echo $saylist['saytext']; ?>" />
<input type="<?= $buttonactive ?>" name="actionedit" value="Редактировать" />
</form>
</div>
<div class="button_say_delete">
<form name="sayform" method="post" action="/chat/say/reset.php" class="logout">
<input type="hidden" name="pageid" id="" value=" <?php echo $pageid; ?>" />
<input type="hidden" name="deleteid" id="" value=" <?php echo $saylist['id']; ?>" />
<input type="<?= $buttonactive ?>" name="delete" id="" value="Удалить" />
</form>
</div>
</div>
</div>
<!– Форма ответить на комментарий –>
<div class="add_reply" id="">
<?php
if (isset($_SESSION['login'])) {
if (isset($_GET['reply']) and $_GET['reply'] == $post_id) {
include_once $_SERVER['DOCUMENT_ROOT'] . '/chat/say/form_add_reply.html.php';
}
} ?>
</div>
</div><!– END block_button_say –>
</div><!– END sayform –>
<!– Выводим ответы на комментарии и кнопки –>
<?php
include $_SERVER['DOCUMENT_ROOT'] . '/chat/say/print_reply.html.php';
endforeach;
} ?>
</div><!– END wrapsayform –>
</html>
Здесь вставляется, подготовленный в list_reply.php массив ответов на комментарии $reply, затем в цикле foreach – endforeach обрабатываются комментарии, содержащиеся в массиве $say, созданном в контроллере 3, которые выводятся в соответствующих блоках div и происходит активация кнопок для каждого комментария, затем в этом же цикле подключается файл print_reply.html.php, который печатает ответы и выводит кнопки ответов.