我在Zend中有一个应用程序,我需要在那里实现将用户工作时间记录到数据库的系统。有id_worktime、id_user、login_time和logout_time。登录和注销很容易,但当用户不做任何超过gc_maxlifetime的事情时就会出现问题。我编写了扩展Zend_Session_SaveHandler_DbTable的类,其中我覆盖了gc()方法:
class Vao_Session extends Zend_Session_SaveHandler_DbTable
{
public function gc($maxlifetime)
{
$garbage = $this->fetchAll($this->select()->from('session')->where('`modified` + `lifetime` < ?', time()));
foreach ($garbage as $session)
{
$variables = array();
$a = preg_split("/('w+)'|/", $session['data'], -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
for($i = 0; $i < count($a); $i = $i + 2){
$variables[$a[$i]] = unserialize($a[$i + 1]);
}
if (isset($variables['worktime']))
{
$worktime = $variables['worktime'];
$idWorktime = $worktime['id_worktime'];
if ($idWorktime)
{
$date = new Zend_Date($session['modified']);
$data['logout_time'] = $date->toString(Zend_Date::ISO_8601);
$worktimeTable = new Application_Model_DbTable_Worktime();
$worktimeTable->update($data, 'id_worktime = '.$idWorktime);
}
}
}
parent::gc($maxlifetime);
}
}
当我从其他web浏览器点击刷新时,它可以正常工作——会话表中的旧行被删除,注销时间在工作时间表中被更新。但当我在用户登录的web浏览器中点击刷新时(当然,会话现在已经过期),工作时间中没有任何内容,会话中的行也会更新——"修改"列设置为当前时间,"数据"等于:
SessionPreferencesFlag|a:1:{s:16:"sessionSavedInDb";b:1;}
(之前有Zend_Auth对象和更多,还有我需要的id_worktime)。
现在的问题是,Zend框架的哪一部分清除了会话争议?我想这是Zend_Session中的东西,但我真的找不到。请帮忙,好吗?
Zend_Session
构建在内置的PHP会话功能上,因此垃圾收集方法在适当的时候由PHP自己调用。
如果你看一下Zend_Session_SaveHandler_DbTable
的源代码,我认为你的问题是在那里的read()
方法中,如果它成功地从DB中加载了一个会话,但发现它已经过期,它就会调用destroy()
,删除会话数据。这"绕过"了通过删除会话时必须更新工作时间的代码。垃圾收集。我建议将您的大部分代码转移到另一个方法,您可以从gc()
调用该方法。然后,您还可以扩展destroy()
方法,使其也可以调用新方法。
多亏了Tim Fountain,我才解决了这个问题。工作代码:
class Vao_Session extends Zend_Session_SaveHandler_DbTable
{
public function read($id)
{
$return = '';
$rows = call_user_func_array(array(&$this, 'find'), $this->_getPrimary($id));
if (count($rows)) {
if ($this->_getExpirationTime($row = $rows->current()) > time()) {
$return = $row->{$this->_dataColumn};
} else {
$this->_saveLogoutTime($row);
$this->destroy($id);
}
}
return $return;
}
public function gc($maxlifetime)
{
$garbage = $this->fetchAll($this->select()->from('session')->where('`modified` + `lifetime` < ?', time()));
foreach ($garbage as $session)
{
$this->_saveLogoutTime($session);
}
parent::gc($maxlifetime);
}
private function _saveLogoutTime($sessionRow)
{
$variables = array();
$a = preg_split("/('w+)'|/", $sessionRow[$this->_dataColumn], -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
for($i = 0; $i < count($a); $i = $i + 2){
$variables[$a[$i]] = unserialize($a[$i + 1]);
}
if (isset($variables['worktime']))
{
$worktime = $variables['worktime'];
$idWorktime = $worktime['id_worktime'];
if ($idWorktime)
{
$data = array();
$date = new Zend_Date($sessionRow[$this->_modifiedColumn]);
$data['logout_time'] = $date->toString(Zend_Date::ISO_8601);
$worktimeTable = new Application_Model_DbTable_Worktime();
$worktimeTable->update($data, 'id_worktime = '.$idWorktime);
}
}
}
}