Session.php 5.95 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\mongodb;

use Yii;
11
use yii\base\ErrorHandler;
12
use yii\base\InvalidConfigException;
13
use yii\di\Instance;
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

/**
 * Session extends [[\yii\web\Session]] by using MongoDB as session data storage.
 *
 * By default, Session stores session data in a collection named 'session' inside the default database.
 * This collection is better to be pre-created with fields 'id' and 'expire' indexed.
 * The collection name can be changed by setting [[sessionCollection]].
 *
 * The following example shows how you can configure the application to use Session:
 * Add the following to your application config under `components`:
 *
 * ~~~
 * 'session' => [
 *     'class' => 'yii\mongodb\Session',
 *     // 'db' => 'mymongodb',
 *     // 'sessionCollection' => 'my_session',
 * ]
 * ~~~
 *
33 34
 * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only.
 *
35 36 37 38 39
 * @author Paul Klimov <klimov.paul@gmail.com>
 * @since 2.0
 */
class Session extends \yii\web\Session
{
40 41 42 43 44 45 46 47 48 49 50 51 52
    /**
     * @var Connection|string the MongoDB connection object or the application component ID of the MongoDB connection.
     * After the Session object is created, if you want to change this property, you should only assign it
     * with a MongoDB connection object.
     */
    public $db = 'mongodb';
    /**
     * @var string|array the name of the MongoDB collection that stores the session data.
     * Please refer to [[Connection::getCollection()]] on how to specify this parameter.
     * This collection is better to be pre-created with fields 'id' and 'expire' indexed.
     */
    public $sessionCollection = 'session';

53

54 55 56 57 58 59 60 61
    /**
     * Initializes the Session component.
     * This method will initialize the [[db]] property to make sure it refers to a valid MongoDB connection.
     * @throws InvalidConfigException if [[db]] is invalid.
     */
    public function init()
    {
        parent::init();
62
        $this->db = Instance::ensure($this->db, Connection::className());
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    }

    /**
     * Returns a value indicating whether to use custom session storage.
     * This method overrides the parent implementation and always returns true.
     * @return boolean whether to use custom storage.
     */
    public function getUseCustomStorage()
    {
        return true;
    }

    /**
     * Updates the current session ID with a newly generated one.
     * Please refer to <http://php.net/session_regenerate_id> for more details.
     * @param boolean $deleteOldSession Whether to delete the old associated session file or not.
     */
    public function regenerateID($deleteOldSession = false)
    {
        $oldID = session_id();

        // if no session is started, there is nothing to regenerate
        if (empty($oldID)) {
            return;
        }

        parent::regenerateID(false);
        $newID = session_id();

        $collection = $this->db->getCollection($this->sessionCollection);
        $row = $collection->findOne(['id' => $oldID]);
        if ($row !== null) {
            if ($deleteOldSession) {
                $collection->update(['id' => $oldID], ['id' => $newID]);
            } else {
                unset($row['_id']);
                $row['id'] = $newID;
                $collection->insert($row);
            }
        } else {
            // shouldn't reach here normally
            $collection->insert([
                'id' => $newID,
                'expire' => time() + $this->getTimeout()
            ]);
        }
    }

    /**
     * Session read handler.
     * Do not call this method directly.
     * @param  string $id session ID
     * @return string the session data
     */
    public function readSession($id)
    {
        $collection = $this->db->getCollection($this->sessionCollection);
        $doc = $collection->findOne(
            [
                'id' => $id,
                'expire' => ['$gt' => time()],
            ],
            ['data' => 1, '_id' => 0]
        );

        return isset($doc['data']) ? $doc['data'] : '';
    }

    /**
     * Session write handler.
     * Do not call this method directly.
     * @param  string  $id   session ID
     * @param  string  $data session data
     * @return boolean whether session write is successful
     */
    public function writeSession($id, $data)
    {
        // exception must be caught in session write handler
        // http://us.php.net/manual/en/function.session-set-save-handler.php
        try {
            $this->db->getCollection($this->sessionCollection)->update(
                ['id' => $id],
                [
                    'id' => $id,
                    'data' => $data,
                    'expire' => time() + $this->getTimeout(),
                ],
                ['upsert' => true]
            );
        } catch (\Exception $e) {
153 154 155 156 157
            $exception = ErrorHandler::convertExceptionToString($e);
            // its too late to use Yii logging here
            error_log($exception);
            echo $exception;

158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
            return false;
        }

        return true;
    }

    /**
     * Session destroy handler.
     * Do not call this method directly.
     * @param  string  $id session ID
     * @return boolean whether session is destroyed successfully
     */
    public function destroySession($id)
    {
        $this->db->getCollection($this->sessionCollection)->remove(
            ['id' => $id],
            ['justOne' => true]
        );

        return true;
    }

    /**
     * Session GC (garbage collection) handler.
     * Do not call this method directly.
     * @param  integer $maxLifetime the number of seconds after which data will be seen as 'garbage' and cleaned up.
     * @return boolean whether session is GCed successfully
     */
    public function gcSession($maxLifetime)
    {
        $this->db->getCollection($this->sessionCollection)
            ->remove(['expire' => ['$lt' => time()]]);

        return true;
    }
AlexGx committed
193
}