annotate vendor/symfony/http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
Chris@0 13
Chris@0 14 /**
Chris@0 15 * MongoDB session handler.
Chris@0 16 *
Chris@0 17 * @author Markus Bachmann <markus.bachmann@bachi.biz>
Chris@0 18 */
Chris@0 19 class MongoDbSessionHandler implements \SessionHandlerInterface
Chris@0 20 {
Chris@0 21 /**
Chris@0 22 * @var \Mongo|\MongoClient|\MongoDB\Client
Chris@0 23 */
Chris@0 24 private $mongo;
Chris@0 25
Chris@0 26 /**
Chris@0 27 * @var \MongoCollection
Chris@0 28 */
Chris@0 29 private $collection;
Chris@0 30
Chris@0 31 /**
Chris@0 32 * @var array
Chris@0 33 */
Chris@0 34 private $options;
Chris@0 35
Chris@0 36 /**
Chris@0 37 * Constructor.
Chris@0 38 *
Chris@0 39 * List of available options:
Chris@0 40 * * database: The name of the database [required]
Chris@0 41 * * collection: The name of the collection [required]
Chris@0 42 * * id_field: The field name for storing the session id [default: _id]
Chris@0 43 * * data_field: The field name for storing the session data [default: data]
Chris@0 44 * * time_field: The field name for storing the timestamp [default: time]
Chris@0 45 * * expiry_field: The field name for storing the expiry-timestamp [default: expires_at]
Chris@0 46 *
Chris@0 47 * It is strongly recommended to put an index on the `expiry_field` for
Chris@0 48 * garbage-collection. Alternatively it's possible to automatically expire
Chris@0 49 * the sessions in the database as described below:
Chris@0 50 *
Chris@0 51 * A TTL collections can be used on MongoDB 2.2+ to cleanup expired sessions
Chris@0 52 * automatically. Such an index can for example look like this:
Chris@0 53 *
Chris@0 54 * db.<session-collection>.ensureIndex(
Chris@0 55 * { "<expiry-field>": 1 },
Chris@0 56 * { "expireAfterSeconds": 0 }
Chris@0 57 * )
Chris@0 58 *
Chris@0 59 * More details on: http://docs.mongodb.org/manual/tutorial/expire-data/
Chris@0 60 *
Chris@0 61 * If you use such an index, you can drop `gc_probability` to 0 since
Chris@0 62 * no garbage-collection is required.
Chris@0 63 *
Chris@0 64 * @param \Mongo|\MongoClient|\MongoDB\Client $mongo A MongoDB\Client, MongoClient or Mongo instance
Chris@0 65 * @param array $options An associative array of field options
Chris@0 66 *
Chris@0 67 * @throws \InvalidArgumentException When MongoClient or Mongo instance not provided
Chris@0 68 * @throws \InvalidArgumentException When "database" or "collection" not provided
Chris@0 69 */
Chris@0 70 public function __construct($mongo, array $options)
Chris@0 71 {
Chris@0 72 if (!($mongo instanceof \MongoDB\Client || $mongo instanceof \MongoClient || $mongo instanceof \Mongo)) {
Chris@0 73 throw new \InvalidArgumentException('MongoClient or Mongo instance required');
Chris@0 74 }
Chris@0 75
Chris@0 76 if (!isset($options['database']) || !isset($options['collection'])) {
Chris@0 77 throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler');
Chris@0 78 }
Chris@0 79
Chris@0 80 $this->mongo = $mongo;
Chris@0 81
Chris@0 82 $this->options = array_merge(array(
Chris@0 83 'id_field' => '_id',
Chris@0 84 'data_field' => 'data',
Chris@0 85 'time_field' => 'time',
Chris@0 86 'expiry_field' => 'expires_at',
Chris@0 87 ), $options);
Chris@0 88 }
Chris@0 89
Chris@0 90 /**
Chris@0 91 * {@inheritdoc}
Chris@0 92 */
Chris@0 93 public function open($savePath, $sessionName)
Chris@0 94 {
Chris@0 95 return true;
Chris@0 96 }
Chris@0 97
Chris@0 98 /**
Chris@0 99 * {@inheritdoc}
Chris@0 100 */
Chris@0 101 public function close()
Chris@0 102 {
Chris@0 103 return true;
Chris@0 104 }
Chris@0 105
Chris@0 106 /**
Chris@0 107 * {@inheritdoc}
Chris@0 108 */
Chris@0 109 public function destroy($sessionId)
Chris@0 110 {
Chris@0 111 $methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteOne' : 'remove';
Chris@0 112
Chris@0 113 $this->getCollection()->$methodName(array(
Chris@0 114 $this->options['id_field'] => $sessionId,
Chris@0 115 ));
Chris@0 116
Chris@0 117 return true;
Chris@0 118 }
Chris@0 119
Chris@0 120 /**
Chris@0 121 * {@inheritdoc}
Chris@0 122 */
Chris@0 123 public function gc($maxlifetime)
Chris@0 124 {
Chris@0 125 $methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteOne' : 'remove';
Chris@0 126
Chris@0 127 $this->getCollection()->$methodName(array(
Chris@0 128 $this->options['expiry_field'] => array('$lt' => $this->createDateTime()),
Chris@0 129 ));
Chris@0 130
Chris@0 131 return true;
Chris@0 132 }
Chris@0 133
Chris@0 134 /**
Chris@0 135 * {@inheritdoc}
Chris@0 136 */
Chris@0 137 public function write($sessionId, $data)
Chris@0 138 {
Chris@0 139 $expiry = $this->createDateTime(time() + (int) ini_get('session.gc_maxlifetime'));
Chris@0 140
Chris@0 141 $fields = array(
Chris@0 142 $this->options['time_field'] => $this->createDateTime(),
Chris@0 143 $this->options['expiry_field'] => $expiry,
Chris@0 144 );
Chris@0 145
Chris@0 146 $options = array('upsert' => true);
Chris@0 147
Chris@0 148 if ($this->mongo instanceof \MongoDB\Client) {
Chris@0 149 $fields[$this->options['data_field']] = new \MongoDB\BSON\Binary($data, \MongoDB\BSON\Binary::TYPE_OLD_BINARY);
Chris@0 150 } else {
Chris@0 151 $fields[$this->options['data_field']] = new \MongoBinData($data, \MongoBinData::BYTE_ARRAY);
Chris@0 152 $options['multiple'] = false;
Chris@0 153 }
Chris@0 154
Chris@0 155 $methodName = $this->mongo instanceof \MongoDB\Client ? 'updateOne' : 'update';
Chris@0 156
Chris@0 157 $this->getCollection()->$methodName(
Chris@0 158 array($this->options['id_field'] => $sessionId),
Chris@0 159 array('$set' => $fields),
Chris@0 160 $options
Chris@0 161 );
Chris@0 162
Chris@0 163 return true;
Chris@0 164 }
Chris@0 165
Chris@0 166 /**
Chris@0 167 * {@inheritdoc}
Chris@0 168 */
Chris@0 169 public function read($sessionId)
Chris@0 170 {
Chris@0 171 $dbData = $this->getCollection()->findOne(array(
Chris@0 172 $this->options['id_field'] => $sessionId,
Chris@0 173 $this->options['expiry_field'] => array('$gte' => $this->createDateTime()),
Chris@0 174 ));
Chris@0 175
Chris@0 176 if (null === $dbData) {
Chris@0 177 return '';
Chris@0 178 }
Chris@0 179
Chris@0 180 if ($dbData[$this->options['data_field']] instanceof \MongoDB\BSON\Binary) {
Chris@0 181 return $dbData[$this->options['data_field']]->getData();
Chris@0 182 }
Chris@0 183
Chris@0 184 return $dbData[$this->options['data_field']]->bin;
Chris@0 185 }
Chris@0 186
Chris@0 187 /**
Chris@0 188 * Return a "MongoCollection" instance.
Chris@0 189 *
Chris@0 190 * @return \MongoCollection
Chris@0 191 */
Chris@0 192 private function getCollection()
Chris@0 193 {
Chris@0 194 if (null === $this->collection) {
Chris@0 195 $this->collection = $this->mongo->selectCollection($this->options['database'], $this->options['collection']);
Chris@0 196 }
Chris@0 197
Chris@0 198 return $this->collection;
Chris@0 199 }
Chris@0 200
Chris@0 201 /**
Chris@0 202 * Return a Mongo instance.
Chris@0 203 *
Chris@0 204 * @return \Mongo|\MongoClient|\MongoDB\Client
Chris@0 205 */
Chris@0 206 protected function getMongo()
Chris@0 207 {
Chris@0 208 return $this->mongo;
Chris@0 209 }
Chris@0 210
Chris@0 211 /**
Chris@0 212 * Create a date object using the class appropriate for the current mongo connection.
Chris@0 213 *
Chris@0 214 * Return an instance of a MongoDate or \MongoDB\BSON\UTCDateTime
Chris@0 215 *
Chris@0 216 * @param int $seconds An integer representing UTC seconds since Jan 1 1970. Defaults to now.
Chris@0 217 *
Chris@0 218 * @return \MongoDate|\MongoDB\BSON\UTCDateTime
Chris@0 219 */
Chris@0 220 private function createDateTime($seconds = null)
Chris@0 221 {
Chris@0 222 if (null === $seconds) {
Chris@0 223 $seconds = time();
Chris@0 224 }
Chris@0 225
Chris@0 226 if ($this->mongo instanceof \MongoDB\Client) {
Chris@0 227 return new \MongoDB\BSON\UTCDateTime($seconds * 1000);
Chris@0 228 }
Chris@0 229
Chris@0 230 return new \MongoDate($seconds);
Chris@0 231 }
Chris@0 232 }