整理一下用php实现登陆功能的四种技术,这里我们需要构建一个login.php页面,以下是四种实现方法
一. 利用HTTP认证窗口
HTTP认证可以作为一个简单的用户登陆系统,我们可以利用HTTP认证窗口作为面向用户的登陆窗口,php通过超级全局变量$_SERVER['PHP_AUTH_USER']
和$_SERVER['PHP_AUTH_PW']
得到用户输入的用户名和口令,然后执行SQL查询验证身份。
代码模板如下
<?php
$connect=mysqli_connect('localhost','root','***','datebasename');
if(!isset($_SERVER['PHP_AUTH_USER'])||!isset($_SERVER['PHP_AUTH_PW'])){
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate:Basic realm="WDL"');
exit('sorry');
}
$name=mysqli_real_escape_string(connect,trim($_SERVER['PHP_AUTH_USER]));
$pw=mysqli_real_escape_string($connect,trim($_SERVER['PHP_AUTH_PW]));
if(empty($name)||empty($pw)){
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate:Basic realm="WDL"');
exit('sorry');
}
$str="select * from tablename where name='$name' and pw=SHA('$pw')";
$re=mysqli_query($connect,$str);
if(mysqli_num_rows($re)==0){
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate:Basic realm="WDL"');
exit('sorry');
}
echo 'ok';
?>
这种方法有一个致命缺陷,就是无法正常注销!HTTP认证是通过以上两个超级全局变量实现同一基本域跨页面识别用户身份,也就是说,只有当这两个超级全局变量销毁后用户才能注销,这往往需要用户关闭浏览器窗口或者手动清除HTTP认证的会话。(关闭浏览器会销毁一个会话里的数据变量以及HTTP认证)
二. 使用cookie在客户端存储用户信息
利用php内置函数setcookie()
存储用户信息以及过期日期,利用超级全局变量$_COOKIE
取出当前用户信息。
工作原理:服务器生成带有登陆用户信息的cookie,通过响应头发送给浏览器,浏览器把这个cookie存储起来,第二次向服务器发出请求时把这个cookie打包到请求头中发送给服务器,服务器接收到这个信息,识别出用户已经登陆以及登陆用户的信息从而返回相应HTML页面。
代码模板如下
<?php
$message='';
if(!isset($_COOKIE['username'])){
if(isset($_POST['submit'])){
$name=mysqli_real_escape_string(connect,trim($_POST['username']));
$pw=mysqli_real_escape_string($connect,trim($_POST['pw']));
if(empty($name)||empty($pw)){
$message='error';
}
else{
$str="select * from tablename where name='$name' and pw=SHA('$pw')";
$re=mysqli_query($connect,$str);
if(mysqli_num_rows($re)==0){
$message='error';
}
else{
setcookie('username','WDL',time()+3600);
header('Location:http://www.WDL.com/index.php');
exit(0);
}
}
}
echo $message;
?>
<form>
<label for='username'>
<input type='text' name='username' value='<?php echo $name?>'>
<br>
<label for='pw'>
<input type='password' name='pw'>
<br>
<input type='submit' name='submit' value='登录'>
</form>
<?php
}
else{
echo 'ok';
}
?>
利用cookie存储当前用户信息有几点好处
- 高“持久性”。cookie可以设定过期日期,在过期日期到来之前除非用户手动清除cookie。否则即使浏览器关闭cookie依然存在,这使得跨会话记住用户成为了可能。
- 适合存储少量数据。cookie非常适合做为少量数据的存储地,存取都非常方便,记住,cookie中的键/值对都是已文本串的方式存储,即使你在生成一个cookie时给他赋值一个整型变量。
使用cookie存储信息也有明显的缺陷
- cookie安全性低。一些重要的保密的数据不适合存储在cookie中。由于客户端是面向用户的,这就意味着,把数据存储在客户端,数据是直接暴露给用户的,一旦用户通过客户端把cookie清除,那么服务端将毫无办法进行干涉。还有一点就是,有些用户的浏览器禁用了cookie,这就使得这部分用户将无法实现登陆这一功能,这是非常糟糕的!
- cookie存储数据的能力有限。cookie只能临时存储少量的数据,大量的永久性的数据还是需要存储在数据库
三. 会话session
会话session是有别于cookie的另一种临时存储数据的手段,只不过它是存储在服务端。在操作会话变量$_SESSION
之前必须调用php函数session_start()开启会话session。
工作原理: 浏览器向服务器发出请求,服务器接收到后调用session_start()函数开始一个会话,首先检测浏览器的请求地址中是否包含会话ID信息或者请求头中cookie是否存储了会话ID,若没有,则开启一个新的会话,这会产生一个会话ID和一个对应以ID命名的会话文件,这个文件存储在服务器中,将用来存储会话变量。若浏览器开启了cookie,则服务器会向浏览器发送这个会话ID,浏览器存储这个ID。若没开启cookie,也不影响session工作,它将ID通过一个URL从一个脚本传递到下一个脚本,cookie只是一种跨多个脚本保留会话ID的优化方法。这样当浏览器发出第二次请求时脚本会通过以上两种途径识别到包含会话ID,并判断该ID是否过期,是否被清除,若否,此时将不会新建会话,而是会从服务器找到一个对应的会话文件,此时就可以开始对里面存储的会话变量进行操作。
模板代码如下
<?php
if(!session_id()){
session_start();
}
$message='';
if(!isset($_SESSION['username'])){
if(isset($_POST['submit'])){
$name=mysqli_real_escape_string(connect,trim($_POST['username']));
$pw=mysqli_real_escape_string($connect,trim($_POST['pw']));
if(empty($name)||empty($pw)){
$message='error';
}
else{
$str="select * from tablename where name='$name' and pw=SHA('$pw')";
$re=mysqli_query($connect,$str);
if(mysqli_num_rows($re)==0){
$message='error';
}
else{
$_SESSION['username']='WDL';
header('Location:http://www.WDL.com/index.php');
exit(0);
}
}
}
echo $message;
?>
<form>
<label for='username'>
<input type='text' name='username' value='<?php echo $name?>'>
<br>
<label for='pw'>
<input type='password' name='pw'>
<br>
<input type='submit' name='submit' value='登录'>
</form>
<?php
}
else{
echo 'ok';
}
?>
利用会话session的优点
- 安全性高。会话变量是存储在服务器端的,这使得它具有更高的安全性,用户不能够随意删除或者修改这些重要的数据,所以许多重要的数据相对于cookie,存储在session更合适。
- 不依赖浏览器。当用户禁用浏览器cookie时并不会影响到登陆功能,因为会话ID还可以通过脚本URL传递给下一个脚本,当然前提是必须确保配置文件php.ini中的session.use_trans_id被设置为1(true),否则必须手动在每个URL后面加上保存有ID信息的参数,如
<a href='index.php?<?php echo SID?>'>click me</a>
- 存储空间较大。session可以存储的空间较cookie大。
会话session也有它的不足
- “持久性”差。session会话没有设置过期日期的概念,一旦会话结束,所有相关的会话变量以及会话ID都会被删除,而关闭浏览器可以让一个会话结束。注意,调用
session_destroy()
函数只会删除ID而不会删除会话变量。 - 注销过程较cookie复杂。如下
$_SESSION=array();//注销所有相关的会话变量
if(isset($_COOKIE[session_name()])){
setcookie(session_name(),'',time()-1);//若用户开启了cookie,不要忘了即使清除会话ID信息
}
session_destroy();//清除存储在服务器的会话ID,结束会话
出于安全性等原因,我们常采用会话session存储登陆用户信息,但是这种方法不能在多个会话之间使用,为此,我们可以利用cookie的“持久性”结合session构造更完美的登陆模块
四. cookie加session共同开发
接下的一切都建立在用户浏览器开启cookie的基础上,这时我们可以在用户登陆成功时同时把用户信息存储在cookie和session里,当浏览器关闭后,session里的信息删除了,但是只要还没过期cookie里的信息就还在,可以在再次打开浏览器时用存储在cookie中的登陆数据重置会话变量
模板代码如下
修改登陆代码
if(!session_id()){
session_start();
}
if(isset($_COOKIE['username'])){
$_SESSION['username']=$_COOKIE['userame'];
}
$message='';
if(!isset($_SESSION['username'])){
if(isset($_POST['submit'])){
$name=mysqli_real_escape_string(connect,trim($_POST['username']));
$pw=mysqli_real_escape_string($connect,trim($_POST['pw']));
if(empty($name)||empty($pw)){
$message='error';
}
else{
$str="select * from tablename where name='$name' and pw=SHA('$pw')";
$re=mysqli_query($connect,$str);
if(mysqli_num_rows($re)==0){
$message='error';
}
else{
$_SESSION['username']='WDL';
setcookie('username','WDL',time()+3600);
header('Location:http://www.WDL.com/index.php');
exit(0);
}
}
}
echo $message;
?>
<form>
<label for='username'>
<input type='text' name='username' value='<?php echo $name?>'>
<br>
<label for='pw'>
<input type='password' name='pw'>
<br>
<input type='submit' name='submit' value='登录'>
</form>
<?php
}
else{
echo 'ok';
}
?>
在每个页面加上以下代码
if(session_id()){
session_start();
}
if(isset($_COOKIE['username'])){
$_SESSION['username']=$_COOKIE['username'];
}