编辑 我试着用xdebug和netbeans进行调试。如果我输入了一些断点,那么在调试会话期间出口将工作是很奇怪的。但是,没有断点,更加现实的环境,出口不起作用。PHP Redis Session not saving
我已经尝试在代码的某些部分添加睡眠。
我想也许PHP在Redis提交完成之前就已经结束了。也许Redis连接是异步完成的,但我检查了PRedis,默认是同步连接。
我正在使用报告工具。
这是基本问题。
我们将一个报告存储到会话对象中,但是在稍后的请求中,当我们试图去到会话对象中的报告消失时。
这是一个更详细的版本。
我储存“报告”对象到会话中,像这样
$_SESSION['report_name_unixtimestamp'] = gzcompress(serialize($reportObject));
用户可以看到在一些表格形式的报告,然后,如果他们想,他们可以将其导出。报告可能会发生变化,所以将其存储在会话中的想法是,当用户将其导出到PDF,Excel等时,他们将得到与他们正在查看的报告相同的报告。
用户点击一个导出按钮,在PHP端它将进入会话,通过作为get参数提供的键(取消压缩和反序列化)获取报告,创建导出并将其发送给用户下载。
直到我们试图引入Redis缓存服务器作为更好的会话管理工具时,它才运行良好。
现在会发生什么情况如下:
我们第一次运行它会被存储到缓存中,出口将成功的工作报告。
我们将再次运行该报告,并在同一个会话中使用相同的用户帐户。这会更改unixtimestamp,因此$_SESSION
中应该有两个条目。 ($_SESSION['report_name_oldertimetamp']
和$_SESSION['report_name_newertimestamp']
)。当我们再次点击导出按钮时,我们得到一个错误,说文件不存在(因为它没有被服务器发送)。
如果我们检查redis服务器是否有较新版本的报告,它不在那里,但旧的时间戳仍然存在。
现在,这可以在文件会话管理中使用,但不能与Redis一起使用。我们已经尝试了用于php的redis模块以及纯php客户端Predis。
有没有人有任何想法?
这里有一些更多的细节:
- Redis的还没有用完的内存。我们已经检查了很多次。
- 我们已经知道,要反序列化会话中的报表对象,报表类必须已包含在内。 (请记住,第一次导出可以正常工作,但之后的任何操作都会失败)
- 如果我们在运行报表的请求期间检查php会话对象,它将包含较新的报表,但它从未将其报告给Redis。
下面是与Predis一起使用的保存处理程序。 redis_session_init是我在session_start()之前调用的函数,以便它被注册。我不确定redis_session_write函数是如何工作的,但也许有人可以帮助我。
<?php
namespace RedisSession
{
$redisTargetPrefix = "PHPREDIS_SESSION:";
$unpackItems = array();
$redisServer = "tcp://cache.emcweb.com";
function redis_session_init($unpack = null, $server = null, $prefix = null)
{
global $unpackItems, $redisServer, $redisTargetPrefix;
if($unpack !== null)
{
$unpackItems = $unpack;
}
if($server !== null)
{
$redisServer = $server;
}
if($prefix !== null)
{
$redisTargetPrefix = $prefix;
}
session_set_save_handler('RedisSession\redis_session_open', 'RedisSession\redis_session_close', 'RedisSession\redis_session_read', 'RedisSession\redis_session_write', 'RedisSession\redis_session_destroy', 'RedisSession\redis_session_gc');
}
function redis_session_read($id)
{
global $redisServer, $redisTargetPrefix;
$redisConnection = new \Predis\Client($redisServer);
return base64_decode($redisConnection->get($redisTargetPrefix . $id));
}
function redis_session_write($id, $data)
{
global $unpackItems, $redisServer, $redisTargetPrefix;
$redisConnection = new \Predis\Client($redisServer);
$ttl = ini_get("session.gc_maxlifetime");
$redisConnection->pipeline(function ($r) use (&$id, &$data, &$redisTargetPrefix, &$ttl, &$unpackItems)
{
$r->setex($redisTargetPrefix . $id, $ttl, base64_encode($data));
foreach($unpackItems as $item)
{
$keyname = $redisTargetPrefix . $id . ":" . $item;
if(isset($_SESSION[ $item ]))
{
$r->setex($keyname, $ttl, $_SESSION[ $item ]);
}
else
{
$r->del($keyname);
}
}
});
}
function redis_session_destroy($id)
{
global $redisServer, $redisTargetPrefix;
$redisConnection = new \Predis\Client($redisServer);
$redisConnection->del($redisTargetPrefix . $id);
$unpacked = $redisConnection->keys($redisTargetPrefix . $id . ":*");
foreach($unpacked as $unp)
{
$redisConnection->del($unp);
}
}
// These functions are all noops for various reasons... opening has no practical meaning in
// terms of non-shared Redis connections, the same for closing. Garbage collection is handled by
// Redis anyway.
function redis_session_open($path, $name)
{
}
function redis_session_close()
{
}
function redis_session_gc($age)
{
}
}
您可以请(仅用于诊断)使用会话变量的不同密钥?如md5('report_name_unixtimestamp')或'timestamp-reportname'? 背景:我怀疑被截断的钥匙somwhere – 2011-12-23 19:13:30
@EugenRieck,你的意思是像这样$ _SESSION [md5('report_name_1234')]?也许,但这并不能解释为什么第一次报告导出工作。报告的关键字长度是相同的,因为它只是不同的时间戳。我会尽力,谢谢。 – 2011-12-23 19:34:44
@EugenRieck,它没有工作。我试着按照你的建议去做md5散列,但它也不起作用。 – 2011-12-23 19:49:13