PHP Session 会话

时间:2018-11-15 15:06:29  来源:igfitidea点击:

在本教程中,我们将学习如何使用PHP session在会话期间跨页面保存web应用程序的状态。

PHP会话是如何工作的

会话允许您在与会话ID关联的web服务器上存储数据。一旦创建了会话,PHP就会向web浏览器发送包含会话ID的cookie。在随后的请求中,web浏览器将会话ID cookie发送回web服务器,以便PHP能够根据会话ID查询数据,并使数据在脚本中可用。

PHP在哪里存储会话数据

默认情况下,PHP将会话数据存储在web服务器上的临时文件中。您可以在PHP配置文件中使用指令session.save_path指定临时文件的位置。

如果你想在脚本中查看它的设置,可以使用ini_get()函数如下:

<?php
  echo ini_get('session.save_path');

获取会话数据存储文件位置的另一种方法是使用session_save_path()函数:

session_save_path()

通常,会话数据存储在web服务器的/tmp文件夹中。

如何创建会话

要创建一个会话,可以使用session_start()函数,如下所示:

<?php
  session_start();

第一次在脚本中调用session_start()时,PHP生成一个惟一的会话ID,并以名为PHPSESSID的cookie的形式将其发送到web浏览器。
如果会话已经存在,PHP将检查浏览器发送的PHPSESSID cookie, session_start()函数将使用现有的会话。

需要注意的是,PHP必须在HTTP头文件中发送PHPSESSID cookie,因此,必须在将内容输出到web浏览器的任何语句之前调用session_start()函数。
否则,您将收到一条警告消息说您不能修改header信息,因为它已经被发送了。

即在session_start()前面不能echo,print或者有html代码或空白字符。

如何访问会话中的数据

与cookie不同,您可以在会话中存储任何类型的数据。将数据作为键和值存储在$SESSION[]超全局数组中。

例如,在index.php文件中,您将用户字符串和角色数组存储在会话中,如下所示:

<?php
  session_start();
  // 存储一个标量值
  $_SESSION['user'] = 'admin';
 
  // 存储一个数组
  $roles = array('administrator','itroad','editor');
  $_SESSION['roles'] = $roles;
 
  session_write_close();
?>
 
<html>
<head>
 <title>PHP Session演示</title>
</head>
<body>
 <a href="profile.php">转到个人资料页面</a>
</body>
</html>

在profile.php文件中,可以用如下方式访问会话数据:

<?php
session_start();
 
if(isset($_SESSION['user'])){
 echo sprintf("欢迎 %s!",$_SESSION['user']);
}
 
if(isset($_SESSION['roles'])){
 echo sprintf('你的角色是: %s', implode($_SESSION['roles'],','));
}

在index.php文件中,您可以看到我们在将数据写入$_SESSION数组后使用session_write_close()函数。
它会强制将$_SESSION数组中的数据保存到web服务器上的会话数据文件中,并释放会话数据文件的锁。

通常,PHP在脚本结束时自动执行此操作。但是,当不再将数据写入$_SESSION[]数组时,最好调用session_write_close()函数。
原因是当您使用基于文件的会话时,每个请求都会锁定文件,直到它被终止。在随后的请求中,脚本需要等待锁被释放,以便再次访问会话数据。
锁用于防止会话数据损坏。但是,对于经常'假死'的脚本,脚本执行必须等待太长时间。session_write_close()函数帮助提前释放锁,并允许下一个脚本继续运行,而不必等待锁释放。

如何销毁会话

当用户关闭浏览器时,PHP会自动删除会话,因为PHPSESSID cookie的expires字段被设置为0。
然而,在某些情况下,我们想手工销毁会话,例如,当用户单击注销链接时。
要销毁会话,可以使用session_destroy()函数。

<?php
session_destroy();

session_destroy()将销毁与当前会话关联的所有数据。但是,它不会unset $_SESSION数组和cookie中的数据。

要完全销毁会话数据,取消$_SESSION数组中的变量设置并删除PHPSESSID cookie,您可以使用以下代码片段:

<?php
session_start();
 
// 删除cookie
if(isset($_COOKIE[session_name()])){
 setcookie(session_name,'',time() - 3600, '/');
}
 
// unset $_SESSION中的数据
$_SESSION[] = array();
 
// 销毁会话
session_destroy();

注意,我们使用session_name()来获取cookie名,而不是使用PHPSESSID。这是因为PHP允许您在同一个脚本上处理多个具有不同名称的会话。

简单的登录系统

我们将使用我们所介绍的技术来开发一个简单的登录系统。你可以自己尝试一下,分析一下它是如何工作的。

<?php
session_start();
 
define("SYSUSER",'admin');
define("SYSPASSWORD",'secret');
 
start();
 
/**
 *  开始处理登录表单
 */
function start(){
 if(isset($_POST['login'])){
    if(authenticate()){
    // 如果用户成功登录,则显示受保护的内容
        display_secured_content();
    }else{
        // 再次显示登录表单和消息
        display_login_form('无效的用户名或密码。');
    }
    }else if(isset($_GET['action']) && $_GET['action'] == 'logout'){
        logout();
    }else{
        display_login_form();
    }
}
 
/**
 * 显示登录表单。如果传递了$msg,则将其显示为错误消息
 * @param string $msg error message
 */
function display_login_form($msg=''){
 ?>
 <style>
 .error {
 color: #ff0000;
 }
 </style>
 <form action="login.php" method="post">
 <p class="error">
 <?php echo $msg; ?>
 </p>
 <fieldset name="logininfo">
 <legend>Login</legend>
 <label for="username">Username:</label> 
 <input type="text" name="username" id="username" /><br /> 
 <label for="password">Password:</label>
 <input type="password" name="password" id="password" /><br /> 
 <input type="submit" name="login" value="Login">
 </fieldset>
 </form>
 <?php 
}
 
/**
 *  向登录用户显示受保护的内容
 */
function display_secured_content(){
 ?>
 <h1>
 Welcome
 <?php echo $_SESSION['username'];?>
 </h1>
 <p>欢迎来到会员区!</p>
 <p>
 <a href="login.php?action=Logout">logout</a>
 </p>
 <?php 
}
 
/**
*   验证用户的输入
*   @return 如果用户身份验证成功,则返回true,否则返回false
*/
function authenticate(){
    if(isset($_POST['username']) && isset($_POST['password'])){
        $username = $_POST['username'];
        $password = $_POST['password'];
        
        if($username == SYSUSER  && $password == SYSPASSWORD){
            $_SESSION['username'] = SYSUSER;
            session_write_close();
            return true;
        }
        else{
            return false;
        }
    }
}
/**
* 退出logout
*/
function logout(){
    if(isset($_COOKIE[session_name()])){
        setcookie(session_name,'',time() - 3600, '/');
    }
    $_SESSION = array();
    session_destroy();
    
    header('location: login.php');
}