默认情况下,即使会话中没有数据,PHP的会话处理机制也会设置会话cookie标头并存储会话。如果会话中未设置任何数据,那么我不希望在响应中将Set-Cookie
标头发送给客户端,并且我不希望在服务器上存储空的会话记录。如果将数据添加到$_SESSION
,则正常行为应继续。
我的目标是实现一种类似于Drupal 7和Pressflow的懒惰会话创建行为,除非在应用程序执行期间将数据添加到$_SESSION
数组中,否则该会话不会存储任何会话(或发送会话cookie标头)。此行为的重点是允许反向代理(如Varnish)缓存并提供匿名流量,同时让经过身份验证的请求传递到Apache / PHP。 Varnish(或另一个代理服务器)配置为通过任何不带cookie的请求,并正确假设如果存在cookie,则该请求针对特定客户端。
我已经从Pressflow移植了会话处理代码,该代码使用session_set_save_handler()
并覆盖了session_write()
的实现,以在保存之前检查$_SESSION
数组中的数据,并将其写为库并在此处添加答案。最佳/唯一路线。
我的问题:虽然我可以实现完全自定义的session_set_save_handler()
系统,但是否有一种更简单的方法以相对通用的方式获得这种惰性会话创建行为,而这对于大多数应用程序来说是透明的?
参考方案
好吧,一种选择是使用会话类在会话中启动/停止/存储数据。因此,您可以执行以下操作:
class Session implements ArrayAccess {
protected $closed = false;
protected $data = array();
protected $name = 'mySessionName';
protected $started = false;
protected function __construct() {
if (isset($_COOKIE[$this->name])) $this->start();
$this->data = $_SESSION;
}
public static function initialize() {
if (is_object($_SESSION)) return $_SESSION;
$_SESSION = new Session();
register_shutdown_function(array($_SESSION, 'close'));
return $_SESSION;
}
public function close() {
if ($this->closed) return false;
if (!$this->started) {
$_SESSION = array();
} else {
$_SESSION = $this->data;
}
session_write_close();
$this->started = false;
$this->closed = true;
}
public function offsetExists($offset) {
return isset($this->data[$offset]);
}
public function offsetGet($offset) {
if (!isset($this->data[$offset])) {
throw new OutOfBoundsException('Key does not exist');
}
return $this->data[$offset];
}
public function offsetSet($offset, $value) {
$this->set($offset, $value);
}
public function offsetUnset($offset) {
if (isset($this->data[$offset])) unset($this->data[$offset]);
}
public function set($key, $value) {
if (!$this->started) $this->start();
$this->data[$key] = $value;
}
public function start() {
session_name($this->name);
session_start();
$this->started = true;
}
}
若要使用,请在脚本开始时调用Session::initialize()
。它将用对象替换$ _SESSION,并设置延迟加载。之后,你可以做
$_SESSION['user_id'] = 1;
如果会话未启动,则它将启动,并且user_id键将设置为1。如果您要关闭(提交)会话,请随时调用$_SESSION->close()
。
您可能需要添加更多会话管理功能(例如destroy,regenerate_id,更改会话名称的功能等),但这应该实现您所需要的基本功能...
它不是save_handler,它只是管理会话的类。如果确实需要,可以在该类中实现ArrayAccess,并在构造时将$ _SESSION替换为该类(这样做的好处是,旧版代码仍然可以像以前一样使用会话,而无需调用$session->setData()
)。唯一的缺点是我不确定PHP使用的序列化例程是否可以正常工作(您有时需要将数组放回到$ _SESSION中……可能是register_shutdown_function()
...
这是我第一次尝试创建会话。另外,成功登录后,我使用header()函数重定向页面,但是在重定向的页面上,我不再有会话。有代码:建立工作阶段:function userLogin($user){ session_start(); $_SESSION['username'] = $user; header("Location: /~…
PHP Memcached会话突然失效 - phpsession.save_handler = memcached session.save_path = "127.0.0.1:11211" session.gc_maxlifetime = 86400 其余的标准。我希望自上次用户访问该页面以来,该会话至少可以保留86400秒,即,如果我在5分钟后启动了一个会话并访问了该页面,则该会话应…
php Singleton类实例将在多个会话中保留吗? - php举一个简单的例子,如果我想计算一个不使用磁盘存储的脚本的命中次数,我可以使用静态类成员来执行此操作吗?用户1:<?php $test = Example::singleton(); $test->visits++; ?> 用户2:<?php $test = Example::singleton(); $test->visits+…
PHP-将日期插入日期时间字段 - php我已在数据库中使用datetime字段存储日期,使用PHP将“今天的日期”插入该字段的正确方法是什么?干杯, 参考方案 我认为您可以使用php date()函数
PHP getallheaders替代 - php我正在尝试从服务器上的apache切换到nginx。唯一的问题是我在PHP脚本中使用的getallheaders()函数,该函数不适用于Nginx。我已经尝试过用户在getallheaders函数上的php站点上提供的注释,但这并不返回所有请求标头。请告诉我如何解决这个问题。我真的想切换到Nginx。 参考方案 您仍然可以使用它,但是您必须像这里一样重新定义…