我正在使用PHP中的用户身份验证类,并遇到了会话处理方面的一些问题。
这是基础知识:
global.php
我有一个名为global.php
的文件,它包含在每个页面加载的开头。从这个文件中我还包括使用的其他类,例如我正在处理的class.uservalidation.php
。
我在global.php
文件中发起会话。
class.uservalidation.php
当在global.php
文件的开头实例化此类时,在构造函数中调用checkLogin
方法来检查会话变量{{1 }和email
如果匹配,则会将hash
属性设置为所选用户的级别。
auth
是登录页面(显然......),提交时会调用uservalidation类的login.php
方法。当成功登录时,此方法将设置两个会话变量login
和email
。
hash
是默认的目标网页,根据登录状态显示不同的内容
这是一个如何运作的例子:
我转到index.php
。会话启动,类加载实例化。 login.php
方法将首先报告checkLogin
。我提交表单,然后再次加载相同的页面。在实例化类时,auth=0
将首先再次报告checkLogin
。然后在auth=0
脚本中,我将调用login.php
方法并设置会话变量。
但是...
我只能从login
文件中print_r($_SESSION);
而不是login.php
或global.php
看到会话变量(即使这是我设置会话的地方)变量)。
这是一个问题,因为我需要在后续页面加载时检查class.uservalidation.php
方法中的email
和hash
会话变量。
由于loginCheck
是一个超全球,我认为它可以从任何地方访问,我无法弄清楚出了什么问题......
我有一种感觉我在这里缺少一些非常基本的东西...我对OOP很新,所以可能是因为我缺少一些关于如何声明变量或其他东西的知识,但因为它是一个超全局我认为没关系。
[编辑#1]
这里有一些代码(出于某种原因,我无法粘贴到此文本框中,因此我创建了指向pastebin的链接):
global.php:
$_SESSION
class.uservalidation.php
<?php
// Load configuration
require 'config.php';
// Start secure session
session_start();
// Include libraries
require 'class.uservalidation.php';
//Connect to database
// Initialize user validation
$USER=new Uservalidation();
?>
的login.php
<?php
/*
--------------------------------------------------------------------------------------
class.uservalidation.php
--------------------------------------------------------------------------------------
Based on example at http://www.wikihow.com/Create-a-Secure-Login-Script-in-PHP-and-MySQL
*/
class Uservalidation {
public function __construct() {
$this->data=FALSE;
$this->auth=0;
$this->loginCheck();
}
// login function is provided a hashed password directly from the browser (see uservalidation.js)
public function login($email,$hash) {
global $DB;
if($email=filter_var($email,FILTER_VALIDATE_EMAIL)) {
$email=$DB->real_escape_string($email);
$hash=$DB->real_escape_string($hash);
if($user=sql_fetch("SELECT * FROM users WHERE user_email='$email' AND user_hash='$hash' AND user_status>1 LIMIT 1")) {
// Successful login
$user_browser=$_SERVER['HTTP_USER_AGENT'];
$_SESSION['session_email']=$user['user_email'];
$_SESSION['session_hash']=hash('sha512',$user['hash'].$user_browser);
$this->data=$user;
$this->auth=$user['user_auth'];
return TRUE;
} else {
// Email and hash does not match
// Record attempt in login_attempts table
return FALSE;
}
} else {
// Not a valid email address
return FALSE;
}
}
public function logout() {
$this->destroySession();
$this->data=FALSE;
$this->auth=0;
}
// Validate user session
private function loginCheck() {
$user_browser=$_SERVER['HTTP_USER_AGENT'];
if($user=$this->getUser($_SESSION['session_email'])) {
$user_hash=hash('sha512',$user['user_hash'].$user_browser);
if(hash_equals($user_hash,$_SESSION['session_hash'])) {
// Successful match
$this->data=$user;
$this->auth=$user['user_auth'];
return TRUE;
} else {
// Hashes does not match
return FALSE;
}
} else {
// User doesn't exist
return FALSE;
}
}
// Get data for specific user (either by email, uid or hash)
public function getUser($string) {
global $DB;
//echo "User: $string";
if($email=filter_var($string,FILTER_VALIDATE_EMAIL)) {
$checkuser=sql_fetch("SELECT * FROM users WHERE user_email='$email' LIMIT 1");
} elseif($id=filter_var($string,FILTER_VALIDATE_INT)) {
$checkuser=sql_fetch("SELECT * FROM users WHERE uid='$id' LIMIT 1");
} else {
$hash=$DB->real_escape_string($string);
$checkuser=sql_fetch("SELECT * FROM users WHERE user_hash='$hash' LIMIT 1");
}
return $checkuser;
}
private function clearSession() {
// Unset all of the session variables.
$_SESSION=array();
}
private function destroySession() {
$this->clearSession();
// If it's desired to kill the session, also delete the session cookie.
// Note: This will destroy the session, and not just the session data!
if(ini_get("session.use_cookies")) {
$params=session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
}
// Finally, destroy the session.
session_destroy();
}
}
?>
答案 0 :(得分:0)
由于您在评论中停止回答问题,我将采用我的最新想法:
不要在仅php文件中使用关闭?>
个php标记。它们倾向于顶部引入被遗忘的空格,这是导致HTML正文在代码中意外发送的原因。
这些空格可能导致在开始会话之前发送标头,这意味着会话cookie变为FUBAR。
另一个可能的原因是,由于global.php
,您认为自己的require_once
文件未被包含在内。我建议删除_once
部分。
在这篇文章中有很多需要解压缩的内容,所以你得到的是代码评论的“争议流”。
你所拥有的是“包含面向编程”。我强烈建议您了解自动加载器。特别是PSR4自动加载器,附带Composer。
使用sha512哈希算法(特别是无盐),是一个非常糟糕的主意。您应该学会使用(相对)新的Password API。
用户电子邮件应该已经是唯一参数。在请求帐户详细信息时,没有必要考虑其他WHERE
和LIMIT
条件。
当用户登录时,无需在会话中存储登录凭据。您应该只存储帐户ID。
你的类在构造函数中不应该有任何业务逻辑,因为这使得测试所述类非常困难。
你在整个代码库中都有SQL注入。您不应该连接查询中的数据,原因与您在PHP代码中不使用eval()
的原因相同。