2

我正在使用一个 PHP 会话管理器类来处理 MongoDB 中的用户会话,但它不起作用,我终生无法弄清楚原因。会话变量设置成功,但不会持续到其他页面。与 MongoDB 的连接不是问题。我已经确定这个问题与 . session_set_save_handler,因为如果我注释掉这个函数,原生 PHP 会话处理工作正常。

在此先感谢您的帮助。

...
require('database.class.php');

class SessionManager {

const COLLECTION = 'sessions';
const SESSION_TIMEOUT = 600;
const SESSION_LIFESPAN = 3600;
const SESSION_NAME = 'mongosessid';
const SESSION_COOKIE_PATH = '/';
const SESSION_COOKIE_DOMAIN = '';

private $_mongo;
private $_collection;
private $_currentSession;

public function __construct() {
    $this->_mongo = DBConnection::instantiate();
    $this->_collection = $this->_mongo->getCollection(SessionManager::COLLECTION);

    register_shutdown_function('session_write_close'); 

    session_set_save_handler(
        array(&$this, 'open'),
        array(&$this, 'close'),
        array(&$this, 'read'),
        array(&$this, 'write'),
        array(&$this, 'destroy'),
        array(&$this, 'gc')
    );

    //Set session garbage collection period
    ini_set('session.gc_maxlifetime', SessionManager::SESSION_LIFESPAN);

    //Set session cookie config
    session_set_cookie_params(
        SessionManager::SESSION_LIFESPAN,
        SessionManager::SESSION_COOKIE_PATH,
        SessionManager::SESSION_COOKIE_DOMAIN
    );

    //Replace 'PHPSESSID' with 'mongosessid' as the session name
    session_name(SessionManager::SESSION_NAME);
    session_cache_limiter('nocache');

    session_start();

}   

public function open($path, $name) {
    return true;
}

public function close() {
    return true;
}

public function read($sessionId) {
    $query = array('session_id' => $sessionId,
                    'timedout_at' => array('$gte' => time()),
                    'expired_at' => array('$gte' => time() - SessionManager::SESSION_LIFESPAN)
                    );

    $result = $this->_collection->findOne($query);
    $this->_currentSession = $result;

    if (!isset($result['data'])) {
        return '';
    }

    return $result['data'];
}

public function write($sessionId, $data) {
    $expired_at = time() + self::SESSION_TIMEOUT;
    $new_obj = array('data' => $data,
                    'timedout_at' => time() + SessionManager::SESSION_TIMEOUT,
                    'expired_at' => (empty($this->_currentSession)) ? time() + SessionManager::SESSION_LIFESPAN : $this->_currentSession['expired_at']
                    );
    $query = array('session_id' => $sessionId);

    $this->_collection->update($query,
                                array('$set' => $new_obj),
                                array('$upsert' => TRUE)
                                );
}

public function destroy($sessionId) {
    $this->_collection->remove(array('session_id' => $sessionId));
    return TRUE;
}

public function gc() {
    $query = array('expired_at' => array('$lt' => time()));
    $this->_collection->remove($query);
    return TRUE;
}

}

$session = new SessionManager();

?>
4

1 回答 1

2

write在对象销毁后调用。当您使用它时,您的$_mongo对象已经被销毁。

使用session_write_close()withregister_shutdown_function()来解决这个问题。

register_shutdown_function('session_write_close');

In addition to this (because this was almost certainly happening), the options for the update query do not begin with a $ (a mistake I've made myself numerous times), you need upsert not $upsert

于 2012-06-06T13:34:40.697 回答