PHP Session 会话
在本教程中,我们将学习如何使用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'); }