PHP SESSION 的工作原理
在客户端(如浏览器)登录网站时,被访问的 PHP 页面可以使用 session_start() 打开 SESSION,这样就会产生客户端的唯一标识 SESSION ID(此 ID 可通过函数 session_id() 获取/设置)。
SESSION ID 可以通过两种方式保留在客户端,使得请求不同的页面时,PHP 程序可以获知客户端的 SESSION ID;一种是将 SESSION ID 自动加入到 GET 的 URL 中(这个只能在unix系统下能实现,windows系统不能实现自动加入url中),或者 POST 的表单中,默认情况下,变量名为 PHPSESSID;另一种是通过 COOKIE,将 SESSION ID 保存在 COOKIE 中,默认情况下,这个 COOKIE 的名字为 PHPSESSID。不管哪一种方式,这个标识符是唯一的,php就凭着这个标识符来读写SESSION数据。
SESSION 的数据保存在服务器端,但不是保存在内存中,而是保存在文件或数据库中。默认情况下,php.ini 中设置的 SESSION 保存方式是files(session.save_handler = files)。这是可以更改的,是用数据库,redis,memcache都可以。
更改存储方式
- 修改php.ini的设置(修改后重启)
session.save_handler = redis
- ini_set
ini_set(“session.save_handler”,”redis”);
- session_module_name
session_module_name("files"); // ASCII files session_module_name("mm"); // Shared memory session_module_name("user"); // Custom session backend
- 更改方式
session_module_name("user");
- 建立数据库表
id就是唯一标识符,data就是数据,还可以自定义其他的内容例如过期日期等
CREATE TABLE 'session'( 'id' CHAR(30) NOT NULL,'data' CHAR(3000), PARMIRY BY ('id') );
- 读写代码
实际读写代码,并用session_set_save_handler注册
session_set_save_handler ( callable $open , callable $close , callable $read , callable $write , callable $destroy , callable $gc [, callable $create_sid ] );
如果用对象的方式,还需要注意处理
在脚本执行完毕之后,PHP 内部会清除对象, 所以有可能不调用
write
和close
回调函数。 这样可能会引发非预期的行为,所以当使用对象作为会话保存管理器时, 需要通过注册 shutdown 回调函数来规避风险。 通常,你可以通过调用 register_shutdown_function() 函数 来注册'session_write_close'
回调函数。在 PHP 5.4.0 中,可以调用 session_register_shutdown() 函数来注册 shutdown 回调函数。 如果你使用session_set_save_handler() 的 OOP 原型, 那么仅需设置 “register shutdown” 为
TRUE
即可。
简单例子
<?php $con =mysql_connection("127.0.0.1","user" , "pass"); mysql_select_db("session"); function open($save_path, $session_name) { return(true); } function close() { return(true); } function read($id) { if($result = mysql_query("SELECT * FROM session WHERE id='$id'")) { if($row = mysql_felth_row($result )) { return $row["data"]; } } else { return ""; } } function write($id, $sess_data) { if($result = mysql_query("UPDATE session SET data='$sess_data' WHERE id='$id'")) { return true; } else { return false; } } function destroy($id) { if($result = mysql_query("DELETE * FROM session WHERE id='$id'")) { return true; } else { return false; } } /********************************************* * WARNING - You will need to implement some * * sort of garbage collection routine here. * *********************************************/ function gc($maxlifetime) { return true; } session_set_save_handler("open", "close", "read", "write", "destroy", "gc"); session_start();
对象的方式
<?php class FileSessionHandler { private $savePath; function open($savePath, $sessionName) { $this->savePath = $savePath; if (!is_dir($this->savePath)) { mkdir($this->savePath, 0777); } return true; } function close() { return true; } function read($id) { return (string)@file_get_contents("$this->savePath/sess_$id"); } function write($id, $data) { return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true; } function destroy($id) { $file = "$this->savePath/sess_$id"; if (file_exists($file)) { unlink($file); } return true; } function gc($maxlifetime) { foreach (glob("$this->savePath/sess_*") as $file) { if (filemtime($file) + $maxlifetime < time() && file_exists($file)) { unlink($file); } } return true; } } $handler = new FileSessionHandler(); session_set_save_handler( array($handler, 'open'), array($handler, 'close'), array($handler, 'read'), array($handler, 'write'), array($handler, 'destroy'), array($handler, 'gc') ); // 下面这行代码可以防止使用对象作为会话保存管理器时可能引发的非预期行为 register_shutdown_function('session_write_close'); session_start();
新接口( PHP 5.4 开始)
<?php class MySessionHandler implements SessionHandlerInterface { private $savePath; public function open($savePath, $sessionName) { $this->savePath = $savePath; if (!is_dir($this->savePath)) { mkdir($this->savePath, 0777); } return true; } public function close() { return true; } public function read($id) { return (string)@file_get_contents("$this->savePath/sess_$id"); } public function write($id, $data) { return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true; } public function destroy($id) { $file = "$this->savePath/sess_$id"; if (file_exists($file)) { unlink($file); } return true; } public function gc($maxlifetime) { foreach (glob("$this->savePath/sess_*") as $file) { if (filemtime($file) + $maxlifetime < time() && file_exists($file)) { unlink($file); } } return true; } } $handler = new MySessionHandler(); session_set_save_handler($handler, true); session_start();