2014-10-04 163 views
0

我有以下php函数处理用户登录。这些函数是类User的一部分。登录功能只能工作一次

/* 
* detail() function to get a detail from a database 
* exists() function to check if something exists in a database 
*/ 

private function generate($password, $username = null) { 
    if(is_null($username)) { 
     $date = '0000-00-00'; 
    } else { 
     $date = $this->_db->detail('last_active', 'users', 'username', $username); 
    } 

    // This is not the real thing but it will do as an example 
    $salt = md5(strrev($password.$date)); 
    $password = md5($salt.$password.$date).strrev($password); 

    return $password; 
} 

public function login($data = array()) { 
    // Check if the user exists 
    $username = $data['username']; 
    if($this->_db->exists('username', 'users', 'username', $username)) { 
     $password = $this->generate($data['password'], $username); 

     // If the account is active 
     if ($this->_db->detail('active', 'users', 'username', $username) === 1) { 
      $stmt = $this->_db->mysqli->prepare("SELECT `username`, `password` FROM `users` WHERE `username` = ? AND `password` = ? AND `active` = 1"); 
      $stmt->bind_param('ss', $username, $password); 
      $stmt->execute(); 
      $stmt->store_result(); 

      if($stmt->num_rows >= 1) { 
       // Function to update last_active 
       if($this->updateLastActive($username)) { 
        // Function to update password 
        if($this->updatePassword($username, $this->generate($password, $username))) { 
         // Set the session 
         $this->_session->set('user', $this->_db->detail('id', 'users', 'username', $username)); 

         if($this->_session->exists('user')) { 
          return true; 
         } else { 
          echo 'Logging in went wrong'; 
          return false; 
         } 
        } else { 
         echo 'Editing the password went wrong'; 
         return false; 
        } 
       } else { 
        echo 'Editing last active date went wrong'; 
        return false; 
       } 
      } else { 
       echo 'Wrong username and password combination'; 
       return false; 
      } 
     } else { 
      echo 'Account not active'; 
      return false; 
     } 
    } else { 
     echo 'Username doesn\'t exists'; 
     return false; 
    } 
} 

private function updateLastActive($username) { 
    $date = date('Y-m-d'); 

    $stmt = $this->_db->mysqli->prepare("UPDATE `users` SET `last_active` = ? WHERE `username` = ?"); 
    $stmt->bind_param('ss', $date, $username); 
    $stmt->execute(); 

    if($stmt->affected_rows >= 1) { 
     return true; 
    } else { 
     return false; 
    } 
} 

private function updatePassword($username, $password) { 
    $stmt = $this->_db->mysqli->prepare("UPDATE `users` SET `password` = ? WHERE `username` = ?"); 
    $stmt->bind_param('ss', $password, $username); 
    $stmt->execute(); 

    if($stmt->affected_rows >= 1) { 
     return true; 
    } else { 
     return false; 
    } 
} 

用户刚刚注册时可以登录,没有问题。但是,当用户注销并尝试再次登录时,它将失败。我得到一个错误的部分是:

$stmt = $this->_db->mysqli->prepare("SELECT `username`, `password` FROM `users` WHERE `username` = ? AND `password` = ? AND `active` = 1"); 

我试图找出脚本失败,其中有echo在功能不同的地方,但我无法找出错误。 generate()函数具有$username = null的原因是因为使用相同的函数进行注册。

所以所有功能都在工作,但它们只能工作一次,所以这使我在generate()函数中有些错误。我总是收到消息,说明用户名/密码组合有问题

如果有人能指出我朝着正确的方向,我会非常高兴。

预先感谢

UPDATEdetail()exists()功能是一类数据库的一部分。

public function detail($detail, $table, $column, $value) { 
     if(is_array($detail)) { 
      $data = array(); 

      foreach($detail as $key) { 
       $stmt = $this->mysqli->prepare("SELECT `$key` FROM `$table` WHERE `$column` = ?"); 
       if(is_numeric($value)) { 
        $stmt->bind_param('i', $value); 
       } else { 
        $stmt->bind_param('s', $value); 
       } 
       $stmt->execute(); 
       $stmt->bind_result($detail); 
       $stmt->fetch(); 
       $data[] = $detail; 
       $stmt = null; 
      } 

      return $data; 
     } else { 
      $stmt = $this->mysqli->prepare("SELECT `$detail` FROM `$table` WHERE `$column` = ?"); 

      if(is_numeric($value)) { 
       $stmt->bind_param('i', $value); 
      } else { 
       $stmt->bind_param('s', $value); 
      } 
      $stmt->execute(); 
      $stmt->bind_result($detail); 
      $stmt->fetch(); 

      return $detail; 
     } 
    } 

    public function exists($detail, $table, $column, $value) { 
     $stmt = $this->mysqli->prepare("SELECT `$detail` FROM `$table` WHERE `$column` = ?"); 
     switch(is_numeric($value)) { 
      case true: 
       $stmt->bind_param('i', $value); 
       break; 
      case false: 
       $stmt->bind_param('s', $value); 
       break; 
     } 
     $stmt->execute(); 
     $stmt->store_result(); 

     if($stmt->num_rows >= 1) { 
      return true; 
     } else { 
      return false; 
     } 
    } 
+0

你说你有错误,请问你能发布错误信息吗? – lxg 2014-10-04 14:19:35

+0

@lxg以及错误消息在返回错误之上。如果我有一个PHP错误消息,我可能已经解决了它。 – SuperDJ 2014-10-04 14:25:31

+1

@SuperDJ所以你的解决方案是让错误显示 – meda 2014-10-04 14:26:28

回答

1

在表中创建一个散列字段,使其足够长以避免长度问题。

md5()现在是不能接受的,你应该使用更好的哈希函数如password_hash()

注册:

private function register($username, $password) { 
    //safer than md5() anyway 
    $hash = password_hash($password, PASSWORD_DEFAULT); 
    $sql = 'INSERT INTO table_name (`username`, `hash`) VALUES (?, ?);' 
    $stmt = $this->_db->mysqli->prepare($sql); 
    $stmt->bind_param('ss', $username, $hash); 
    $stmt->execute(); 

    if($stmt->affected_rows >= 1) { 
     return true; 
    } else { 
     return false; 
    } 
} 

登录:

public function login($username, $password) { 
    // Check if the user exists 
    if($this->_db->exists('username', 'users', 'username', $username)) { 
     // If the account is active 
     if ($this->_db->detail('active', 'users', 'username', $username) === 1) { 
      $sql = 'SELECT `username`, `hash` FROM `users` WHERE `username` = ? AND `active` = 1'; 
      $stmt = $this->_db->mysqli->prepare(); 
      $stmt->bind_param('ss', $username, $hash); 
      $stmt->execute(); 
      $stmt->store_result(); 

      if($stmt->num_rows === 1) { 
       if (password_verify($password, $hash)) { 
        // Function to update last_active 
        if($this->updateLastActive($username)) { 
         echo 'last active updated, Login successful'; 
         return true; 
        } else { 
         echo 'Editing last active date went wrong'; 
         return false; 
        } 
       } else { 
        echo 'Wrong username and password combination'; 
        return false; 
       } 
      } else { 
       echo 'Account not active'; 
       return false; 
      } 
     } else { 
      echo 'Username doesn\'t exists'; 
      return false; 
     } 
    } 
} 

当然,你可以仍然使用自定义盐,例如

$hash = password_hash($password 
        ,PASSWORD_DEFAULT 
        ,array('salt' =>generate()));//generate() returns the salt 
+0

感谢您的建议,但我想我找出了问题所在。在'login()'函数的开始处,我说'$ password'是用户输入的密码生成的哈希密码。 (我真的不使用'md5()'来散列我的密码。)但是当我用'$ password'使用'updatePassword()'函数时,它实际上是已经散列过的密码。然后插入到数据库中,并且只能使用一次。 – SuperDJ 2014-10-04 17:07:12

+0

是的,这就是我在[先前的评论]中指出的(http://stackoverflow.com/questions/26193663/login-function-only-works-once/26194356?noredirect=1#comment41073328_26193663),但它很棒解决了,祝你好运 – meda 2014-10-04 17:09:21