Php ajax форма регистрация

Авторизация и регистрация на PHP и Ajax

Напишем систему авторизации и регистрации пользователей на PHP. Для работы скриптов потребуется интерпретатор PHP версии 5.3 и сервер MySQL 5.

Создание базы данных

Создадим новую базу данных с названием testdb, выполнив следующий запрос от привилегированного пользователя.

 // Создание базы данных testdb с кодировкой utf8 CREATE DATABASE testdb CHARACTER SET utf8 COLLATE utf8_general_ci; 

Для работы с базой, добавим отдельного пользователя testdb и предоставим ему необходимые права.

 // Создание пользователя testdb с паролем testdb CREATE USER testdb IDENTIFIED by 'testdb'; // Выделение прав на все таблицы базы testdb GRANT ALL PRIVILEGES ON testdb@localhost TO testdb WITH GRANT OPTION; 

Структура таблицы users

Для хранения пользователей создадим в базе данных таблицу users, выполнив следующий запрос.

 // Создание таблицы для хранения пользователей CREATE TABLE IF NOT EXISTS `users` ( `id` MEDIUMINT NOT NULL AUTO_INCREMENT PRIMARY KEY, `username` VARCHAR(255) NOT NULL UNIQUE, `password` VARCHAR(255) NOT NULL, `salt` VARCHAR(100) NOT NULL ) ENGINE=INNODB; 
  • id — уникальный идентификатор пользователя
  • username — логин
  • password — шифрованный пароль
  • salt — соль для шифрования пароля

Структура файлов и директорий

  • login.php — страница авторизации пользователя
  • register.php — страница регистрации
  • ajax.php — Файл для обработки Ajax-запросов
  • js — клиентские скрипты
  • ajax-form.js — скрипт для работы с Ajax-формами
  • css — стили CSS
  • style.css — основной файл стилей
  • reset.css — файл сброса кастомных стилей браузеров
  • vendor — сторонние third-party библиотеки
  • bootstrap — Twitter Bootstrap 2.3.2
  • AjaxRequest.class.php — обертка для работы с Ajax-запросами
  • Auth.class.php — класс для работы с пользователями

Регистрация пользователей

При регистрации, пользователю нужно ввести логин, пароль и подтверждения пароля. После отправки формы будем делать проверку на существование введенного логина. Если логин уже существует — уведомляем об этом посетителя.

Вся работа с базой данных будет происходить через расширение PDO для PHP. Оно включено в стандартную библиотеку PHP, начиная с версии 5.1.

Основная логика приложения находится в файле classes/Auth.class.php. Разберем подробнее его содержимое.

 username = $username; $this->connectDb($this->db_name, $this->db_user, $this->db_pass, $this->db_host); > public function __destruct() { $this->db = null; > public static function isAuthorized() { if (!empty($_SESSION["user_id"])) { return (bool) $_SESSION["user_id"]; > return false; > public function passwordHash($password, $salt = null, $iterations = 10) { $salt || $salt = uniqid(); $hash = md5(md5($password . md5(sha1($salt)))); for ($i = 0; $i < $iterations; ++$i) { $hash = md5(md5(sha1($hash))); >return array('hash' => $hash, 'salt' => $salt); > public function getSalt($username) { $query = "select salt from users where username = :username limit 1"; $sth = $this->db->prepare($query); $sth->execute( array( ":username" => $username ) ); $row = $sth->fetch(); if (!$row) { return false; > return $row["salt"]; > public function authorize($username, $password, $remember=false) { $query = "select id, username from users where username = :username and password = :password limit 1"; $sth = $this->db->prepare($query); $salt = $this->getSalt($username); if (!$salt) { return false; > $hashes = $this->passwordHash($password, $salt); $sth->execute( array( ":username" => $username, ":password" => $hashes['hash'], ) ); $this->user = $sth->fetch(); if (!$this->user) { $this->is_authorized = false; > else { $this->is_authorized = true; $this->user_id = $this->user['id']; $this->saveSession($remember); > return $this->is_authorized; > public function logout() { if (!empty($_SESSION["user_id"])) { unset($_SESSION["user_id"]); > > public function saveSession($remember = false, $http_only = true, $days = 7) { $_SESSION["user_id"] = $this->user_id; if ($remember) { // Save session id in cookies $sid = session_id(); $expire = time() + $days * 24 * 3600; $domain = ""; // default domain $secure = false; $path = "/"; $cookie = setcookie("sid", $sid, $expire, $path, $domain, $secure, $http_only); > > public function create($username, $password) { $user_exists = $this->getSalt($username); if ($user_exists) { throw new \Exception("User exists: " . $username, 1); > $query = "insert into users (username, password, salt) values (:username, :password, :salt)"; $hashes = $this->passwordHash($password); $sth = $this->db->prepare($query); try { $this->db->beginTransaction(); $result = $sth->execute( array( ':username' => $username, ':password' => $hashes['hash'], ':salt' => $hashes['salt'], ) ); $this->db->commit(); > catch (\PDOException $e) { $this->db->rollback(); echo "Database error: " . $e->getMessage(); die(); > if (!$result) { $info = $sth->errorInfo(); printf("Database error %d %s", $info[1], $info[2]); die(); > return $result; > public function connectdb($db_name, $db_user, $db_pass, $db_host = "localhost") { try { $this->db = new \pdo("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass); > catch (\pdoexception $e) { echo "database error: " . $e->getmessage(); die(); > $this->db->query('set names utf8'); return $this; > > 

Алгоритм регистрации

Для создания нового пользователя используется метод User::create(), который принимает логин и пароль в качестве аргументов.

Читайте также:  Python меню выбора файла

Первым делом, проверяем существование пользователя. Для этого используем метод User::getSalt(), который выбирает из базы «соль» пользователя по его логину. Соль нужна для усложнения подбора паролей пользователей в случае утечки базы.

Если пользователь существует — выбрасываем исключение. Иначе, генерируем новую соль и хешируем ей пароль. После этого выполняем запрос на добавление данных в базу. Если при выполнении запроса происходит ошибка, печатаем соответствуюее сообщение и завершаем работу скрипта. Такая ситуация может произойти при отключении сервера MySQL или его внутренней ошибки.

Если пользователь был усшешно создан, функция User::create() возвращает его уникальный идентификатор. Это обычное числовое поле, которое автоматически увеличивается при добавлении записей в таблицу.

Алгоритм аутентификации

Для того, чтобы проверить правильность ввода логина и пароля, используется метод User::authorize(). Первым делом, мы проверяем существование юзера, пытаясь выбрать его соль из базы. Если пользователь не найден, сразу возвращаем false. Иначе, хешируем принятый пароль этой солью через функцию User::passwordHash(). Затем, делаем выборку из базы по логину и хешу пароля.

Если результат запроса оказался непустым, то логин и пароль верные. Сохраняем пользотельские данные в объекте класса User. Записываем id пользователя в сессию через метод User::saveSession(). Если в качестве первого аргумента — $remember, передать ей true, то идентификатор сессии сохранится в куках. Это позволит не вводить пароль каждый раз при перезапуске браузера.

Работа с формами через Ajax

Для обработки Ajax-запросов создадим класс AjaxRequest. Сохраним его в файле classes/AjaxRequest.class.php.

 request = $request; $this->action = $this->getRequestParam("act"); if (!empty($this->actions[$this->action])) { $this->callback = $this->actions[$this->action]; call_user_func(array($this, $this->callback)); > else { header("HTTP/1.1 400 Bad Request"); $this->setFieldError("main", "Некорректный запрос"); > $this->response = $this->renderToString(); > public function getRequestParam($name) { if (array_key_exists($name, $this->request)) { return trim($this->request[$name]); > return null; > public function setResponse($key, $value) { $this->data[$key] = $value; > public function setFieldError($name, $message = "") { $this->status = "err"; $this->code = $name; $this->message = $message; > public function renderToString() { $this->json = array( "status" => $this->status, "code" => $this->code, "message" => $this->message, "data" => $this->data, ); return json_encode($this->json, ENT_NOQUOTES); > public function showResponse() { header("Content-Type: application/json; charset=UTF-8"); echo $this->response; > >

Этот класс облегчит нам обработку данных, отправленных пользователем из формы. В качестве конструктора, он принимает массив с данными запроса ($_GET или $_POST).

Читайте также:  Javascript node js postgresql

В запросе обязательно должно быть поле act, которое определяет текущее действие. Например, при регистрации значением $_POST[«act»] будет «register», а при авторизации — «login».

Метод getRequestParam() нужен для получения параметра из запроса. Он делает дополнительную проверку на существование ключа массива и возвращает null, если запрос не содержит нужных данных.

Функция setResponse() используется для формирования ответа. Метод setFieldError() нужен для передачи сообщения об ошибке в поле формы.

Для того, чтобы вернуть ответ пользователю, мы используем метод showResponse. Он генерирует строку в JSON-формате, задает нужные HTTP-заголовки и возвращает данные клиенту.

В файле ajax.php происходит непосредственная обработка запросов через класс AjaxRequest.

  session_start(); class AuthorizationAjaxRequest extends AjaxRequest { public $actions = array( "login" => "login", "logout" => "logout", "register" => "register", ); public function login() { if ($_SERVER["REQUEST_METHOD"] !== "POST") { // Method Not Allowed http_response_code(405); header("Allow: POST"); $this->setFieldError("main", "Method Not Allowed"); return; > setcookie("sid", ""); $username = $this->getRequestParam("username"); $password = $this->getRequestParam("password"); $remember = !!$this->getRequestParam("remember-me"); if (empty($username)) { $this->setFieldError("username", "Enter the username"); return; > if (empty($password)) { $this->setFieldError("password", "Enter the password"); return; > $user = new Auth\User(); $auth_result = $user->authorize($username, $password, $remember); if (!$auth_result) { $this->setFieldError("password", "Invalid username or password"); return; > $this->status = "ok"; $this->setResponse("redirect", "."); $this->message = sprintf("Hello, %s! Access granted.", $username); > public function logout() { if ($_SERVER["REQUEST_METHOD"] !== "POST") { // Method Not Allowed http_response_code(405); header("Allow: POST"); $this->setFieldError("main", "Method Not Allowed"); return; > setcookie("sid", ""); $user = new Auth\User(); $user->logout(); $this->setResponse("redirect", "."); $this->status = "ok"; > public function register() { if ($_SERVER["REQUEST_METHOD"] !== "POST") { // Method Not Allowed http_response_code(405); header("Allow: POST"); $this->setFieldError("main", "Method Not Allowed"); return; > setcookie("sid", ""); $username = $this->getRequestParam("username"); $password1 = $this->getRequestParam("password1"); $password2 = $this->getRequestParam("password2"); if (empty($username)) { $this->setFieldError("username", "Enter the username"); return; > if (empty($password1)) { $this->setFieldError("password1", "Enter the password"); return; > if (empty($password2)) { $this->setFieldError("password2", "Confirm the password"); return; > if ($password1 !== $password2) { $this->setFieldError("password2", "Confirm password is not match"); return; > $user = new Auth\User(); try { $new_user_id = $user->create($username, $password1); > catch (\Exception $e) { $this->setFieldError("username", $e->getMessage()); return; > $user->authorize($username, $password1); $this->message = sprintf("Hello, %s! Thank you for registration.", $username); $this->setResponse("redirect", "/"); $this->status = "ok"; > > $ajaxRequest = new AuthorizationAjaxRequest($_REQUEST); $ajaxRequest->showResponse(); 

Формат JSON-ответа

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

 { "status": "статус операции", // err или ok "code": "имя поля с ошибкой", "message": "сообщение об ошибке", "data": "другие произвольные данные" > 

Создадим файл js/ajax-form.js. Он будет перехватывать событие отправки всех форм с классом ajax и отправлять асинхронный запрос серверу. Исходный код ajax-form.js.

Читайте также:  Java check object is array

Для работы скрипта нужен jQuery версии 2.0.3 (лежит в архиве с исходниками).

Обработка ответов происходит в методах объекта script.ajaxForm.callbacks. Пример обработчика ответа для авторизации на сайте:

 login: function ($form, data) { if (data.status === 'ok') { // если авторизация успешна, делаем редирект на // нужную страницу if (data.data && data.data.redirect) { window.location.href = data.data.redirect; > > > 

Эти коллбеки вызываются только, если валидация ответа прошла успешно. Метод script.ajaxForm.validate проверяет наличие в ответе имени поля с ошибкой. Если такое поле существует, подствечивает его и отображает текст самой ошибки.

Источник

Оцените статью