23.6 通过会话控制实现身份验证
最后,我们将介绍使用会话控制的实际应用例子。
会话控制最常见的用法可能就是在用户通过一个登录机制验证后跟踪该用户的行为。在这个例子中,我们将结合MySQL身份验证功能和会话控制功能的使用来实现该功能。该功能将作为我们在第27章“建立用户身份验证机制和个性化设置”中实现的项目的基础,将在那个项目中再次使用。我们将再次使用在第17章“使用PHP和MySQL实现身份验证”中创建的身份验证数据库。可以查看程序清单17-3了解该数据库的详细信息。
本例包含3个简单的脚本。第一个是auth-main.php,它提供了一个登录表单,并且为站点成员提供了身份验证。第二个是members_only.php,只向成功登录的成员显示信息。第三个是logout.php,用户退出登录。
要了解这些是如何工作的,请查阅图23-4,它是由authmain.php显示的初始页面。
图 23-4 因为用户尚未登录,所以显示的是一个登录页面
该页给出了用户登录的地方。如果用户没有登录而访问成员区,将得到如图23-5所示的信息。
图 23-5 用户没有登录就不能看到网站内容;网站将显示警告信息
然而,如果用户先登录了(用户名:testuser;密码password。在第16章中,我们已经创建了这个用户)然后尝试浏览成员页面,看到的页面如图23-6所示。
图 23-6 用户已经登录,可以访问成员区的内容
下面,我们看一下该应用程序的代码。该程序的大部分代码在authmain.php中,该脚本如程序清单23-4所示。我们将详细介绍它。
程序清单23-4 authmain.php——身份验证应用程序的主体部分
<?php
session_start();
if(isset($_POST['userid'])&&isset($_POST['password']))
{
//if the user has just tried to log in
$userid=$_POST['userid'];
$password=$_POST['password'];
$db_conn=new mysqli('localhost",'webauth','webauth','auth');
if(mysqli_connect_errno()){
echo'Connection to database failed:'.mysqli_connect_error();
exit();
}
$query='select*from authorized_users'
."where name='$userid'"
."and password=sha1('$password')";
$result=$db_conn->query($query);
if($result->num_rows)
{
//if they are in the database register the user id
$_SESSION['valid_user']=$userid;
}
$db_conn->close();
}
?>
<html>
<body>
<h1>Home page</h1>
<?
if(isset($_SESSION['valid_user']))
{
echo'You are logged in as:'.$_SESSION['valid_user'].'<br/>';
echo'<a href="logout.php">Log out</a><br/>';
}
else
{
if(isset($userid))
{
//if they"ve tried and failed to log in
echo'Could not log you in.<br/>';
}
else
{
//they have not tried to log in yet or have logged out
echo'You are not logged in.<br/>';
}
//provide form to log in
echo'<form method="post"action="authmain.php">";
echo'<table>';
echo'<tr><td>Userid:</td>';
echo'<td><input type="text"name="userid"></td></tr>';
echo'<tr><td>Password:</td>';
echo'<td><input type="password"name="password"></td></tr>';
echo'<tr><td colspan="2"align="center">";
echo'<input type="submit"value="Log in"></td></tr>';
echo'</table></form>';
}
?>
<br/>
<a href="members_only.php">Members section</a>
</body>
</html>
因为它显示了登录表单,所以该脚本包含了一些比较复杂的逻辑;表单的行为也比较复杂,因为它包含了成功和失败登录操作的HTML代码。
脚本的执行是围绕会话变量valid_user展开的。其基本思想是如果某人成功登录,我们将注册一个$_SESSION['valid_user']的会话变量,该变量包含用户的ID。
在该脚本中,我们所做的第一件事就是调用session_start()函数。如果会话变量valid_user已经创建,这个函数调用将载入该变量。
在第一次执行脚本的时候,if条件均不成立,用户将直接进入脚本的末尾,脚本告诉用户尚未登录并提供一个表单以便登录。
echo'<form method="post"action="authmain.php">";
echo'<table>';
echo'<tr><td>Userid:</td>';
echo'<td><input type="text"name="userid"></td></tr>';
echo'<tr><td>Password:</td>';
echo'<td><input type="password"name="password"></td></tr>';
echo'<tr><td colspan="2"align="center">";
echo'<input type="submit"value="Log in"></td></tr>';
echo'</table></form>';
当用户点击表单上的提交按钮后,这个脚本将从顶端开始重新执行。这次,我们有了用以验证的用户名和密码,它们分别存储在$_POST['userid']和$_POST['password']中。如果用户设置了这些变量,我们就可以进入身份验证模块:
if(isset($_POST['userid'])&&isset($_POST['password']))
{
//if the user has just tried to log in
$userid=$_POST['userid'];
$password=$_POST['password'];
$db_conn=new mysqli('localhost",'webauth','webauth','auth');
if(mysqli_connect_errno()){
echo'Connection to database failed:'.mysqli_connect_error();
exit();
}
$query='select*from authorized_users'
."where name='$userid'"
."and password=sha1('$password')";
$result=$db_conn->query($query);
我们连接到一个MySQL数据库并检查用户ID和密码。如果它们与数据库中的数据匹配,将创建变量$_SESSION['valid_user'],它包含该用户的ID,因此我们就知道谁登录进来了,并对其进行跟踪。
if($result->num_rows>0)
{
//if they are in the database register the user id
$_SESSION['valid_user']=$userid;
}
$db_conn->close();
}
由于我们知道该用户是谁,就不必再向他显示登录表单。取而代之,告诉他我们知道他是谁,并提供退出的选项:
if(isset($_SESSION['valid_user']))
{
echo'You are logged in as:'.$_SESSION['valid_user'].'<br/>';
echo'<a href="logout.php">Log out</a><br/>';
}
如果试图让用户登录,但是由于某种原因失败了,我们将拥有一个用户ID而不是$_SESSION['valid_user']变量,因此我们为该用户提供一个错误信息。
if(isset($userid))
{
//if they"ve tried and failed to log in
echo'Could not log you in.<br/>';
}
以上就是主要的脚本逻辑。现在,我们来了解成员页面。成员页面的代码如程序清单23-5所示。
程序清单23-5 members_only.php——网站的有效用户检查部分,可以确定是否是有效成员
<?php
session_start();
echo'<h1>Members only</h1>';
//check session variable
if(isset($_SESSION['valid_user']))
{
echo'<p>You are logged in as'.$_SESSION['valid_user'].'</p>';
echo'<p>Members only content goes here</p>';
}
else
{
echo'<p>You are not logged in.</p>';
echo'<p>Only logged in members may see this page.</p>';
}
echo'<a href="authmain.php">Back to main page</a>';
?>
以上代码非常简单。它所做的只是启动一个会话,并且通过检查$_SESSION['valid_user']变量是否被设置来检查当前的会话是否包含一个注册的用户。如果用户登录进入我们的网站,我们显示成员内容;否则告诉他尚未通过身份验证。
最后,我们将讨论logout.php脚本,该脚本可以让用户退出登录。脚本代码如程序清单23-6所示。
程序清单23-6 logout.php——该脚本注销会话变量并销毁会话
<?php
session_start();
//store to test if theywerelogged in
$old_user=$_SESSION['valid_user'];
unset($_SESSION['valid_user']);
session_destroy();
?>
<html>
<body>
<h1>Log out</h1>
<?php
if(!empty($old_user))
{
echo'Logged out.<br/>';
}
else
{
//if they weren't logged in but came to this page somehow
echo'You were not logged in,and so have not been logged out.<br/>';
}
?>
<a href="authmain.php">Back to main page</a>
</body>
</html>
源代码十分简单,当然,它也只完成了一些简单的工作。在这里,我们启动了一个会话,保存用户的旧用户名,注销valid_user变量,销毁了会话。然后,我们给用户发送一个消息,该消息在用户退出或者尚未登录的情况下的具体内容是不同的。
以上简单的脚本是在后续章节中要完成的许多工作的基础。