Advertisement
VitaliyKuznetsov

Auth class example (Part of TTOE lab)

Nov 19th, 2017
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 10.16 KB | None | 0 0
  1. <?php
  2. /**
  3.  * Created by PhpStorm.
  4.  * User: vitaliy
  5.  * Date: 10.11.17
  6.  * Time: 16:39
  7.  */
  8.  
  9.  
  10. class Auth
  11. {
  12.     private $db;
  13.     public function __construct()
  14.     {
  15.         $this->db = new \PDO("sqlite:".dirname(__FILE__)."/db/ttoeDB.db");
  16.     }
  17.  
  18.     /** Проверка, занят ли логин
  19.      * @param string $username
  20.      * @return bool TRUE - если да, FALSE - если нет
  21.      */
  22.     public function userExists(string $username)
  23.     {
  24.         $query = $this->db->prepare("SELECT COUNT(id) FROM accounts WHERE username = ?");
  25.         $query->execute([$username]);
  26.         return (bool)$query->fetchColumn();
  27.     }
  28.     private function genRandomString(){
  29.         $string = "";
  30.         $chars = 'qwertyuiopasdfghjklzxcvbnm12347890';
  31.         $len = rand(12,24);
  32.         for ($i = 0; $i < $len; $i++){
  33.             $string .= substr($chars, rand(0, strlen($chars)-1), 1);
  34.         }
  35.         return $string;
  36.     }
  37.  
  38.     /** Подтверждение почты (не заверщено!)
  39.      * @param string $email
  40.      * @return bool
  41.      */
  42.     private function sendVerificationMail(string $email){
  43.         $code = $this->genRandomString();
  44.         $query = $this->db->prepare("UPDATE accounts SET verify_code = '?' WHERE email = '?'");
  45.         return $query->execute();
  46.         //TODO: реализовать отправку письма
  47.     }
  48.  
  49.     /** Регистрация
  50.      * @param $email - эл почта
  51.      * @param $username - имя пользователя(логин/ник)
  52.      * @param $password - пароль
  53.      * @return array $result - результат выполнения
  54.      * <p>
  55.      * Если $result['result'] == false, то коды ошибок представлены в массиве $result['err']
  56.      *
  57.      * <ul style="list-style-type:none"><b>Доступные коды ошибок:</b>
  58.      *  <li><b>0</b> - Неизвестная ошибка (БД?)</li>
  59.      *  <li><b>1</b> - Пользователь уже существует</li>
  60.      * </ul>
  61.      * </p>
  62.      */
  63.     public function register($email, $username, $password)
  64.     {
  65.         $result = [
  66.             'result' => true,
  67.             'err' => [],
  68.         ];
  69.         if ($this->userExists($username)) {
  70.             $result['result'] = false;
  71.             $result['err'][] = '1';
  72.         }
  73.         $userdata = [
  74.             'username' => strtolower($username),
  75.             'email' => $email,
  76.             'password' => password_hash($password, PASSWORD_DEFAULT),
  77.         ];
  78.         if ($result['result']) {
  79.             if (!$this->db->prepare("INSERT INTO ACCOUNTS (username, email, password) VALUES (?,?, ?);")->execute(
  80.                 [
  81.                     $userdata['username'],
  82.                     $userdata['email'],
  83.                     $userdata['password']
  84.                 ]
  85.             )) {
  86.                 $result['result'] = false;
  87.                 $result['err'][] = '0';
  88.             }else{
  89.                 $this->sendVerificationMail($userdata['email']);
  90.             }
  91.         }
  92.         return $result;
  93.     }
  94.  
  95.     /** Получение массива пользовательских данных
  96.      * @param $username
  97.      * @return bool|mixed FALSE - если пользователь не существует, в ином случае массив с данными пользователя
  98.      */
  99.     public function getUserData($username)
  100.     {
  101.         if($this->userExists($username)){
  102.             $query = $this->db->prepare("SELECT * FROM accounts WHERE username = ?");
  103.             $query->execute([$username]);
  104.             return $query->fetch(PDO::FETCH_ASSOC);
  105.         }else{
  106.             return FALSE;
  107.         }
  108.     }
  109.  
  110.     /** Добавление нового токена
  111.      * @param int $userid ID пользователя
  112.      * @return bool|string FALSE - если ошибка в бд или пользователь не существует, иначе строка с токеном
  113.      */
  114.     public function addToken(int $userid)
  115.     {
  116.         $userExists = (bool)$this->db->query("SELECT COUNT(id) FROM accounts WHERE id = $userid")->fetchColumn();
  117.         if(!$userExists){
  118.             return false;
  119.         }
  120.         $token = $this->genRandomString();
  121.         $token_exp = time()+(60*60*24*7);
  122.         if($this->db->prepare("INSERT INTO tokens (token, token_exp, user_id) VALUES (?, ?, ?)")->execute([$token, $token_exp, $userid])){
  123.             return $token;
  124.         }else{
  125.             return false;
  126.         }
  127.     }
  128.  
  129.     /** Удаление устаревших токенов и таблицы токенов
  130.      * @param int $userid ID пользователя
  131.      * @return bool TRUE - если успешно, FALSE - если ошибка бд
  132.      */
  133.     private function destroyExpiredTokens(int $userid){
  134.         return ($this->db->query("DELETE FROM tokens WHERE token_exp < ".time()." AND user_id = $userid") !==FALSE)?true:false;
  135.     }
  136.  
  137.     /** Закрытие остальных сессий
  138.      * Отождествляет кнопку "закрыть все остальные сессии"
  139.      * @param string $curr_token текущий токен
  140.      * @param bool $destroy Если TRUE - уничтожает остальные сесси, ставит время истечения равное текущему
  141.      *  т.е они просто истекают
  142.      * @return bool
  143.      */
  144.     public function closeOtherSess(string $curr_token, bool $destroy = false)
  145.     {
  146.         if(!$this->isTokenValid($curr_token)){
  147.             return false;
  148.         }
  149.         $curr_token = $this->db->quote($curr_token);
  150.         $userID = $this->db->query("SELECT user_id FROM tokens WHERE token = $curr_token");
  151.         if($userID !== false){
  152.             $userID = $userID->fetchColumn();
  153.             $allTokens = $this->db->query("SELECT * FROM tokens WHERE user_id = $userID AND token != $curr_token");
  154.             if($allTokens !==false){
  155.                 foreach ($allTokens->fetchAll(PDO::FETCH_ASSOC) as $item) {
  156.                     $this->expireToken($item['token']);
  157.                 }
  158.                 if($destroy){
  159.                     $this->destroyExpiredTokens($userID);
  160.                 }
  161.                 return true;
  162.             }
  163.         }
  164.         return false;
  165.     }
  166.  
  167.     /** Проверка валидности токена
  168.      * @param $token строка токена
  169.      * @return bool
  170.      */
  171.     public function isTokenValid($token)
  172.     {
  173.         $token = $this->db->quote($token);
  174.         $tokendata = $this->db->query("SELECT * FROM tokens WHERE token = $token");
  175.         if($tokendata !== false){
  176.             $tokendata = $tokendata->fetch(PDO::FETCH_ASSOC);
  177.             if($tokendata['token_exp'] < time()){
  178.                 return false;
  179.             }else{
  180.                 return true;
  181.             }
  182.         }else{
  183.             return false;
  184.         }
  185.     }
  186.  
  187.     /** Форсирование окончания действия токена
  188.      * @param $token строка токена
  189.      * @return bool FALSE - если токен не существует, или ошибка бд
  190.      */
  191.     private function expireToken($token){
  192.         $token = $this->db->quote($token);
  193.         $tokenExists = (bool)$this->db->query("SELECT COUNT(token) FROM tokens WHERE token = $token")->fetchColumn();
  194.         if(!$tokenExists){
  195.             return false;
  196.         }
  197.         return ($this->db->query("UPDATE tokens SET token_exp = ".(time()-1)." WHERE token = $token") !== FALSE)?true:false;
  198.     }
  199.  
  200.     /** Проверка, залогинен ли юзер
  201.      * @return bool
  202.      */
  203.     public function isLogged()
  204.     {
  205.         $result = false;
  206.         if(isset($_COOKIE['token'])){
  207.             if($this->isTokenValid($_COOKIE['token'])){
  208.                 $result = true;
  209.             }
  210.         }
  211.         return $result;
  212.     }
  213.  
  214.     /** Авторизация
  215.      * @param $username - имя пользователя
  216.      * @param $password - пароль
  217.      * @return array
  218.      * <p>
  219.      * Если $result['result'] == false, то коды ошибок представлены в массиве $result['err']
  220.      *
  221.      * <ul style="list-style-type:none"><b>Доступные коды ошибок:</b>
  222.      *  <li><b>0</b> - неверная пара (логин, пароль)</li>
  223.      *  <li><b>1</b> - уже авторизован</li>
  224.      * </ul>
  225.      * </p>
  226.      */
  227.     public function auth($username, $password)
  228.     {
  229.         $username = strtolower($username);
  230.         $result = [
  231.             'result' => true,
  232.             'err' => [],
  233.         ];
  234.         if(!$this->userExists($username)){
  235.             $result['result'] = false;
  236.             $result['err'][] = '0';
  237.         }else{
  238.             if(!$this->isLogged()){
  239.                 $userdata = $this->getUserData($username);
  240.                 if(password_verify($password, $userdata['password'])){
  241.                     $this->destroyExpiredTokens($userdata['id']);
  242.                     setcookie('token', $this->addToken($userdata['id']));
  243.                 }else{
  244.                     $result['result'] = false;
  245.                     $result['err'][] = '0';
  246.                 }
  247.             }else{
  248.                 $result['result'] = false;
  249.                 $result['err'][] = '1';
  250.             }
  251.         }
  252.         return $result;
  253.     }
  254.  
  255.     /** Выход
  256.      * @return array
  257.      * <p>
  258.      * Если $result['result'] == false, то коды ошибок представлены в массиве $result['err']
  259.      *
  260.      * <ul style="list-style-type:none"><b>Доступные коды ошибок:</b>
  261.      *  <li><b>0</b> - пользователь не залогинен</li>
  262.      * </ul>
  263.      * </p>
  264.      */
  265.     public function logout()
  266.     {
  267.         $result = [
  268.             'result' => false,
  269.             'err' => [],
  270.         ];
  271.         if(!$this->isLogged()){
  272.             $result['err'][] = 0;
  273.             return $result;
  274.         }
  275.         if(isset($_COOKIE['token'])){
  276.             $this->expireToken($_COOKIE['token']);
  277.         }
  278.         setcookie("token", "");
  279.         $result['result'] = true;
  280.         return $result;
  281.     }
  282. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement