简体   繁体   English

PHP-使用会话,cookie或数据库登录/注销/过期

[英]PHP - Login/Logout/expire with Session,cookie or database

Im trying to create a user class in php connected with database Here is my class i written so far! 我试图在与数据库连接的php中创建用户类这是我到目前为止编写的类!

class db {
    private function conn(){
        set_exception_handler(create_function('$e','db::db_error($e);'));
        return new PDO('mysql:host=localhost;dbname=mydb','admin','pass');  //Persistent connection without closing conn: ....$user, $pass, array(PDO::ATTR_PERSISTENT=>true));
    }
    public static function db_error($log){
        $mylog=$_SERVER['REMOTE_ADDR']." - ".$_SERVER['PHP_SELF']." - ".date("d/m/Y h:i:s")." - ".$log;
        $showlog=$_SERVER['REMOTE_ADDR']." - Internal Server Error!";
        // $mylog > error information log on db or file!
        exit($showlog);
    }
    public function dbconstruction(){
        $pdo=$this->conn();
        $pdo->query("CREATE TABLE IF NOT EXISTS `users` (
                `uid` text NOT NULL,
                `sid` text NOT NULL,
                `did` text NOT NULL,
                `username` text NOT NULL,
                `password` text NOT NULL,
                `fullname` text NOT NULL,
                `email` text NOT NULL,
                `birthday` text NOT NULL,
                `expire` text NOT NULL
            ) DEFAULT CHARSET=latin1;");
        $pdo->query("CREATE TABLE IF NOT EXISTS `unverified` (
                `uid` text NOT NULL,
                `token` text NOT NULL,
                `expire` text NOT NULL
            ) DEFAULT CHARSET=latin1;");
        $pdo->query("CREATE TABLE IF NOT EXISTS `sessions` (
                `uid` text NOT NULL,
                `session` text NOT NULL,
                `expire` text NOT NULL
            ) DEFAULT CHARSET=latin1;");
        $pdo=null;
        return true;
    }
    public function send($a,$t){ // usage:  $db->send(array('username'=>'boss'),'users');
        if(empty($a)||count($a)<1){return false;}
        $keys=array_keys($a);
        $keys2=array_keys($a);
        foreach($keys2 as &$k){$k=':'.$k;} // ":key"
        $params=array_combine($keys2,array_values($a));
        $st=$this->conn()->prepare("INSERT INTO `$t`(".(count($keys)>1?implode(",",$keys):$keys[0]).") VALUES (".(count($keys2)>1?implode(",",$keys2):$keys2[0]).")");
        $st->execute($params);
        if($st){$st=null;return true;}
        $st=null;
        return false;
    }
    public function receive($a,$t){ // usage:  $db->receive(array('username'=>'boss'),'users');
        if(empty($a)||count($a)<1){return false;}
        $keys=array_keys($a);
        $keys2=array_keys($a);
        foreach($keys as &$k){$k=$k.' = :'.$k;} // "key = :key"
        foreach($keys2 as &$k){$k=':'.$k;} // ":key"
        $params=array_combine($keys2,array_values($a));
        $st=$this->conn()->prepare("SELECT * FROM $t WHERE ".(count($keys)>1?implode(" AND ",$keys):$keys[0]));
        $st->execute($params);
        $result=$st->fetchAll();
        $st=null;
        return $result;
    }
    public function remove($a,$t){ // usage:  $db->remove(array('token'=>'boss'),'unverified');
        if(empty($a)||count($a)<1){return false;}
        $keys=array_keys($a);
        $keys2=array_keys($a);
        foreach($keys as &$k){$k=$k.' = :'.$k;} // "key = :key"
        foreach($keys2 as &$k){$k=':'.$k;} // ":key"
        $params=array_combine($keys2,array_values($a));
        $st=$this->conn()->prepare("DELETE FROM $t WHERE ".(count($keys)>1?implode(" AND ",$keys):$keys[0]));//DELETE FROM `unverified` WHERE token = 'asd'
        $st->execute($params);
        $c=$st->rowCount();
        if($c>0){$st=null;return true;}
        $st=null;
        return false;
    }
    public function update($a,$b,$t){ // usage:  $db->update(array('password'=>'boss'),array('uid'=>$uid),'users'); // update password where uid=$uid
        if(empty($a)||count($a)<1||empty($b)||count($b)<1){return false;}
        $a_keys=array_keys($a);
        foreach($a_keys as &$k){$k=$k.'=?';} // "key=?"
        $set_params=array_values($a);       
        $b_keys=array_keys($b);
        foreach($b_keys as &$k){$k=$k.'=?';} // "key=?"
        $where_params=array_values($b);
        $params=array_merge($set_params,$where_params);
        $set=(count($a_keys)>1?implode(", ",$a_keys):$a_keys[0]);
        $where=(count($b_keys)>1?implode(" AND ",$b_keys):$b_keys[0]);
        $st=$this->conn()->prepare("UPDATE $t SET $set WHERE $where");
        $st->execute($params);
        $c=$st->rowCount();
        if($c>0){$st=null;return true;}
        $st=null;
        return false;
    }
    public function check($a,$t){ // usage:  $db->check(array('username'=>'boss'),'users');
        if(empty($a)||empty($t)||count($a)<1){return false;}
        $keys=array_keys($a);
        $keys2=array_keys($a);
        foreach($keys as &$k){$k=$k.' = :'.$k;} // "key = :key"
        foreach($keys2 as &$k){$k=':'.$k;} // ":key"
        $params=array_combine($keys2,array_values($a));
        $st=$this->conn()->prepare("SELECT * FROM $t WHERE ".(count($keys)>1?implode(" AND ",$keys):$keys[0]));
        $st->execute($params);
        $c=$st->rowCount();
        if($c>0){$st=null;return true;}
        $st=null;
        return false;
    }
}

//$user = new user;
//echo $user->verifyemail('boss','2391cc263bdf0fcf6e69872608ee05fdde7dbdc4');
//echo $user->login('1234567','boss');
//echo $user->register('boss','ad min','1234567','waw1@law.bau','1955');
//$db = new db;
//echo $db->dbconstruction();
//print_r(  $db->update(array('username'=>'thoi'),array('username'=>'asd'),'users')  );


class user { // uid | sid | did | username | password | fullname | email | birthday
    public $settings=array(
                'expire_cookie'=>'4m', // cookie expire time
                'expire_account'=>'3M', // inactivity account expire time
                'expire_verification'=>'1d' // unverified email account expire time
            );
    public function register($username,$fullname,$password,$email,$birthday){  // to add : if is expired register it
        if(empty($username)||empty($fullname)||empty($password)||empty($email)||empty($birthday)
            ||!preg_match('/[a-z0-9\-_]{4,31}/i',$username)
            ||!preg_match('/[a-z\s]{5,64}/i',$fullname)
            ||!preg_match('/(.){7,25}/i',$password)
            ||!preg_match('/([\w\-\._]+)@((?:[\w]+\.)+)([a-zA-Z]{2,4})/i',$email)
            ||!preg_match('/(19|20)([0-9]{2})/i',$birthday)
          ){return false;}
        $username=strtolower($username);
        $email=strtolower($email);
        $db=new db;
        if($db->check(array('username'=>$username),'users')===true){return 'registered username!';}
        if($db->check(array('email'=>$email),'users')){return 'registered email!';}
        $shadow = $this->shadow($password);
        $id=$this->gen(md5($username.$fullname.$password.$email.$birthday.$shadow)); // $id['uid']  , $id['sid']  , $id['did']
        $register=$db->send(array('uid'=>$id['uid'],'sid'=>$id['sid'],'did'=>$id['did'],'username'=>$username,'password'=>$shadow,'fullname'=>$fullname,'email'=>$email,'birthday'=>$birthday,'expire'=>time_ahead($this->settings['expire_account'])),'users');
        if($register){
            $expire_verify=time_ahead($this->settings['expire_verification']);
            $db->send(array('uid'=>$id['uid'],'token'=>$id['token'],'expire'=>$expire_verify),'unverified');
            // SEND EMAIL WITH url http://site.com/?u=$uid&t=$token  OR  http://site.com/verify  to input manually token
            return 'Success registration! Time to verify is until '.date('d/M/Y H:i:s',$expire_verify);
        }
        return false;
    }
    public function login($password,$user){
        if(empty($password)||empty($user)){return false;}
        $user=strtolower($user);
        $db=new db;
        $user_check=$db->check(array('username'=>$user),'users');
        $email_check=$db->check(array('email'=>$user),'users');
        if(!$user_check&&!$email_check){return 'Invalid username/email';}
        $user_details=$db->receive(array(($user_check?'username':'email')=>$user),'users')[0];
        if($this->pass_verify($password,$user_details['password'])){  //**********   set some cookies with expire time_ahead('2h')
            $uid=$user_details['uid'];
            if($user_details['expire']<time()){
                if(!$this->remove_user($uid)){return 'int err!';}
                return 'Account has been expired on '.date('d M Y h:i',$user_details['expire']).'! Click HERE to register!';
            }else{
                $db->update(array('expire'=>time_ahead($this->settings['expire_account'])),array('uid'=>$uid),'users');
                $session=$this->gen(md5($uid.'18.1"8-18\'18'))['session'];  //$_SERVER["SSL_SESSION_ID"] if $ssl true
                $expire=time_ahead($this->settings['expire_cookie']);


                /*
                session_set_cookie_params ( $lifetime , $path , $domain , $secure , $httponly  );
                setcookie('auth','sdaasdasa',time()+'120',WWW,DOMAIN,$GLOBALS['ssl'],true);

                define('DOMAIN','example.com',true);
                define('WWW',$_SERVER['DOCUMENT_ROOT'],true);
                $ssl=((isset($_SERVER['HTTPS'])&&$_SERVER['HTTPS']=='on')?true:false);

                session_set_cookie_params ( 20 , WWW , DOMAIN , $GLOBALS['ssl'] , true  );
                session_name('auth');
                session_start();
                */
                //   setcookie('auth',$session,$expire);  <---- (-_-)!


                if($db->send(array('uid'=>$uid,'session'=>$session,'expire'=>$expire),'sessions')){
                    print 'session set!';
                }
            }
            $unverified=$db->check(array('uid'=>$uid),'unverified');//check if is in unverifided db
            if($unverified){
                $expire_verify=$db->receive(array('uid'=>$uid),'unverified')[0]['expire'];
                if($expire_verify<time()){ //expired verification via email!
                    if(!$this->remove_user($uid)){return 'int err!';}
                    return 'Verification has expired! Account has been deleted :(';
                }else{
                    //$rem=($expire_verify-time());
                    return 'success login! Unverified account! Remaining time to verify your account is until '.date('d/M/Y H:i:s',$expire_verify).' !!!';
                }
            }else{
                return 'success login! Verified account :)';
            }
            return false;
        }else{
            return 'invalid password!';
        }
        return false;
    }
    public function verifyemail($user,$token){
        if(empty($token)||empty($user)){return false;}
        $user=strtolower($user);
        $db=new db;
        $user_check=$db->check(array('username'=>$user),'users');
        $email_check=$db->check(array('email'=>$user),'users');
        if($user_check||$email_check){
            $uid=$db->receive(array(($user_check?'username':'email')=>$user),'users')[0]['uid'];
            if(!$db->check(array('uid'=>$uid),'unverified')){return 'Already verified!';}
            if($db->check(array('token'=>$token),'unverified')){
                $db->remove(array('token'=>$token),'unverified');
                return 'Verified successfully.';
            }else{return 'invalid token!';}
        }else{return 'invalid user!';}
        return false;
    }
    public function remove_user($uid){
        if(!empty($uid)){
            $db=new db;
            $db->remove(array('uid'=>$uid),'users');
            $db->remove(array('uid'=>$uid),'unverified');
            return true;
        }
        return false;
    }
    public function gen($params){ // generate ids ,  USAGE   gen('user123123123')['did']
        $a = $params.$_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_HOST'].$_SERVER['HTTP_USER_AGENT'];
        $r = array(
            'sid' => strtolower( sha1(uniqid(md5($a.time()))) ) , // secret id
            'uid' => strtolower( sha1(md5(uniqid($a.time()))) ) , // public id
            'did' => strtolower( sha1(md5(uniqid($a).time())) ) , // download id
            'token' => strtolower( sha1(md5(uniqid($a).(time()*29.06))) ) , // token id for unverified accounts
            'session' => strtolower( sha1(md5(uniqid($a).(time()*19.91))) ) // login session id
        );
        return $r;
    }
    private function shadow($i){ // usage  shadow('mypass')
        $s='';for($n=0;$n<16;$n++){$s.=chr(rand(1,128));}
        $s='$1$'.md5($s).'$';
        return crypt($i,$s);
    }
    private function pass_verify($pass,$hash){ // usage if($this->pass_verify('Zmypass',$s)){echo 'yes';}else{echo 'no';}
        return ((crypt($pass,$hash)==$hash)?true:false);
    }
}

function time_ahead($t,$c=true){
    if(preg_match('/(\d+)([y|M|d|h|m|s])/',$t,$ti)){
        switch($ti[2]){//1year=365.242144days <-maya says so
            case'y':$r=60*60*24*30.43684991666667*12*$ti[1];break;
            case'M':$r=60*60*24*30.43684991666667*$ti[1];break;
            case'd':$r=60*60*24*$ti[1];break;
            case'h':$r=60*60*$ti[1];break;
            case'm':$r=60*$ti[1];break;
            case's':$r=$ti[1];break;
        }
        return ($c?time()+$r:$r);
    }
    return false;
}

You can see db structure inside code at dbconstruct func. 您可以在dbconstruct函数中查看代码内部的db结构。

My question is should i use for login/logout: 我的问题是我应该用于登录/注销:

  • session and cookie 会话和cookie

  • mysql with table:sessions[uid|session|expire] and with pcntl_fork for cleaning up expired sessions inside session table called everytime page reloads or something like that! 带有table:sessions [uid | session | expire]和pcntl_fork的mysql,用于清理每次重新加载页面之类的会话表内的过期会话!

Im thinking making logins with ajax with refresh 我正在考虑使用Ajax刷新登录

Any other suggestion are welcome too. 也欢迎任何其他建议。
Thanks in advance... 提前致谢...

My recommendation would be: use sessions. 我的建议是:使用会话。

A session uses only 1 cookie: PHPSESSID . 会话仅使用1个cookie: PHPSESSID All the session data is stored server-side (so no tampering is possible). 所有会话数据都存储在服务器端(因此无法进行篡改)。

Use session_set_save_handler to override where PHP stores it's session data. 使用session_set_save_handler覆盖PHP存储其会话数据的位置。 Have it store it's data in a MySQL table. 将其数据存储在MySQL表中。

Don't have the uid as a field in the sessions table. 在会话表中不要将uid用作字段。 Even unauthenticated guests can have a session. 甚至未经身份验证的来宾也可以进行会话。 uid is part of the session data. uid是会话数据的一部分。 Instead of uid you'll want sess_id , ie. 您将需要sess_id而不是uid ,即。 the id of the session. 会话的ID。 Another reason is that one user could have two sessions, you don't want those to interfere because this can break assumptions you make about how sessions work. 另一个原因是,一个用户可能有两个会话,您不希望这些用户干预,因为这可能会破坏您对会话如何工作的假设。

expire is fine, use it to implement the garbage collecting callback. expire很好,用它来实现垃圾回收回调。

Minor: consider using utf8_general_ci instead of latin1 . 次要:考虑使用utf8_general_ci代替latin1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM