PHP:无法访问包含的文件内的 $_SESSION



我正在用PHP开发一个用户身份验证类,并且在会话处理方面遇到了一些问题。

这是基础知识:

  1. global.php我有一个名为global.php的文件,它包含在每个页面加载的开头。从这个文件中,我还包括使用的其他类,例如我正在处理的class.uservalidation.php。 我在global.php文件中启动会话。

  2. class.uservalidation.php当在global.php文件的开头实例化此类时,构造函数中会调用一个checkLogin方法,该方法检查会话变量emailhash,如果它们匹配,则会将auth属性设置为所选用户的级别。

  3. login.php是登录页面(显然...),提交时,这将调用用户验证类的login方法。此方法将设置两个会话变量,email和成功登录时的hash

  4. index.php是默认登录页面,将根据登录状态显示不同的内容

这是它如何工作的一个例子:

我去login.php.会话启动,类加载实例化。checkLogin方法将首先报告auth=0。我提交了表单,然后再次加载了同一页面。checkLogin将在类实例化时再次报告auth=0。然后在login.php脚本中,我将调用login方法并设置会话变量。

但。。。

当我只从login.php文件中而不是从global.phpORclass.uservalidation.phpprint_r($_SESSION);时,我可以看到会话变量(即使这是我设置会话变量的地方)。

这是一个问题,因为我需要在后续页面加载时检查loginCheck方法的emailhash会话变量。

由于$_SESSION是一个超级全球性的,我认为它可以从任何地方访问,但我无法弄清楚出了什么问题......

我有一种感觉,我在这里错过了一些非常基本的东西......我对 OOP 很陌生,所以可能是我缺少一些关于如何声明变量或其他东西的知识,但由于它是一个超全局,我认为这无关紧要。

[编辑 #1]

这里有一些代码(由于某种原因我无法粘贴到这个文本框中,所以我创建了指向 pastebin 的链接):

全球.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();
?>

class.uservalidation.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();
}
}
?>

登录.php

<?php
require_once 'global.php';
// Process login (field "p" is created in uservalidation.js and contain the SHA512 hash of the password so raw password will never be sent to server)
if(isset($_POST['user_email']) && isset($_POST['p'])) {
if($USER->login($_POST['user_email'],$_POST['p'])) {
//header('location:index.php');
$html.="<pre>";
$html.=print_r($_SESSION,TRUE);
$html.=print_r($USER,TRUE);
$html.="</pre>";
$html.="<a href='index.php'>Go on!</a>";
} else {
$html="<p>Could not log in...</p>";
}
} else {
$theform=new htmlForm('login.php');
$theform->addInput('Username',array('type' => 'email', 'name' => 'user_email', 'required' => '', 'autocomplete' => 'off'));
$theform->addInput('Password',array('type' => 'password', 'name' => 'password', 'required' => ''));
$theform->addInput(FALSE,array('type' => 'button', 'value' => 'Login', 'class' => 'button', 'onclick' => 'formhash(this.form);'));
$html=$theform->render();
}
// Render Page
//=================================================================================================
?>
<!doctype html>
<html class="no-js" lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NGI Skunkworks</title>
<link rel="stylesheet" href="css/foundation.css">
<link rel="stylesheet" href="css/app.css">
<link rel="stylesheet" href="css/icons/foundation-icons.css" />
</head>
<body>
<?php require '_menu.php'; ?>
<div class="row">
<br>
<div class="large-12 columns">
<?php echo $html; ?>
</div>
</div>
<script src="js/vendor/jquery.js"></script>
<script src="js/vendor/what-input.js"></script>
<script src="js/vendor/foundation.js"></script>
<script src="js/app.js"></script>
<script src="js/sha512.js"></script>
<script src="js/uservalidation.js"></script>
</body>
</html>

由于您停止在评论中回答问题,我将采用我的最新想法:

不要在仅限 php 的文件中使用结束?>php 标记。它们往往会在顶部引入被遗忘的空格,这会导致 HTML 正文在代码中发送意外点。

这些空格可能会导致在开始会话之前发送标头,这意味着会话 cookie 被 FUBARed。

另一个可能的原因是,由于require_once,当您认为包含时,您的global.php文件未包含在内。我建议删除_once部分。


不相关的部分

这篇文章中有很多东西需要解开,所以你得到的是一种"争议流"风格的代码审查。

你那里有的是"包含面向编程"。我强烈建议您了解自动加载机。尤其是 Composer 附带的 PSR4 自动加载器。

使用 sha512 哈希算法(尤其是无盐)是一个非常糟糕的主意。您应该学习使用(相对)新的密码 API。

用户电子邮件应该已经是唯一参数。在请求帐户详细信息时,没有必要有额外的WHERELIMIT条件。

用户登录后,无需在会话中存储登录凭据。相反,您应该只存储帐户 ID。

您的类在构造函数中不应有任何业务逻辑,因为这使得测试该类变得非常困难。

而且在整个代码库中都有SQL注入。您不应该连接查询中的数据,原因与您在 PHP 代码中不使用eval()的原因相同。

最新更新