Session.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\mongodb;
  8. use Yii;
  9. use yii\base\ErrorHandler;
  10. use yii\base\InvalidConfigException;
  11. use yii\di\Instance;
  12. use yii\web\MultiFieldSession;
  13. /**
  14. * Session extends [[\yii\web\Session]] by using MongoDB as session data storage.
  15. *
  16. * By default, Session stores session data in a collection named 'session' inside the default database.
  17. * This collection is better to be pre-created with fields 'id' and 'expire' indexed.
  18. * The collection name can be changed by setting [[sessionCollection]].
  19. *
  20. * The following example shows how you can configure the application to use Session:
  21. * Add the following to your application config under `components`:
  22. *
  23. * ```php
  24. * 'session' => [
  25. * 'class' => 'yii\mongodb\Session',
  26. * // 'db' => 'mymongodb',
  27. * // 'sessionCollection' => 'my_session',
  28. * ]
  29. * ```
  30. *
  31. * Session extends [[MultiFieldSession]], thus it allows saving extra fields into the [[sessionCollection]].
  32. * Refer to [[MultiFieldSession]] for more details.
  33. *
  34. * Tip: you can use MongoDB [TTL index](https://docs.mongodb.com/manual/tutorial/expire-data/) for the session garbage
  35. * collection for performance saving, in this case you should set [[Session::gCProbability]] to `0`.
  36. *
  37. * @author Paul Klimov <klimov.paul@gmail.com>
  38. * @since 2.0
  39. */
  40. class Session extends MultiFieldSession
  41. {
  42. /**
  43. * @var Connection|array|string the MongoDB connection object or the application component ID of the MongoDB connection.
  44. * After the Session object is created, if you want to change this property, you should only assign it
  45. * with a MongoDB connection object.
  46. * Starting from version 2.0.2, this can also be a configuration array for creating the object.
  47. */
  48. public $db = 'mongodb';
  49. /**
  50. * @var string|array the name of the MongoDB collection that stores the session data.
  51. * Please refer to [[Connection::getCollection()]] on how to specify this parameter.
  52. * This collection is better to be pre-created with fields 'id' and 'expire' indexed.
  53. */
  54. public $sessionCollection = 'session';
  55. /**
  56. * Initializes the Session component.
  57. * This method will initialize the [[db]] property to make sure it refers to a valid MongoDB connection.
  58. * @throws InvalidConfigException if [[db]] is invalid.
  59. */
  60. public function init()
  61. {
  62. parent::init();
  63. $this->db = Instance::ensure($this->db, Connection::className());
  64. }
  65. /**
  66. * Updates the current session ID with a newly generated one.
  67. * Please refer to <http://php.net/session_regenerate_id> for more details.
  68. * @param bool $deleteOldSession Whether to delete the old associated session file or not.
  69. */
  70. public function regenerateID($deleteOldSession = false)
  71. {
  72. $oldID = session_id();
  73. // if no session is started, there is nothing to regenerate
  74. if (empty($oldID)) {
  75. return;
  76. }
  77. parent::regenerateID(false);
  78. $newID = session_id();
  79. $collection = $this->db->getCollection($this->sessionCollection);
  80. $row = $collection->findOne(['id' => $oldID]);
  81. if ($row !== null) {
  82. if ($deleteOldSession) {
  83. $collection->update(['id' => $oldID], ['id' => $newID]);
  84. } else {
  85. unset($row['_id']);
  86. $row['id'] = $newID;
  87. $collection->insert($row);
  88. }
  89. } else {
  90. // shouldn't reach here normally
  91. $collection->insert($this->composeFields($newID, ''));
  92. }
  93. }
  94. /**
  95. * Session read handler.
  96. * Do not call this method directly.
  97. * @param string $id session ID
  98. * @return string the session data
  99. */
  100. public function readSession($id)
  101. {
  102. $collection = $this->db->getCollection($this->sessionCollection);
  103. $condition = [
  104. 'id' => $id,
  105. 'expire' => ['$gt' => time()],
  106. ];
  107. if (isset($this->readCallback)) {
  108. $doc = $collection->findOne($condition);
  109. return $doc === null ? '' : $this->extractData($doc);
  110. }
  111. $doc = $collection->findOne(
  112. $condition,
  113. ['data' => 1, '_id' => 0]
  114. );
  115. return isset($doc['data']) ? $doc['data'] : '';
  116. }
  117. /**
  118. * Session write handler.
  119. * Do not call this method directly.
  120. * @param string $id session ID
  121. * @param string $data session data
  122. * @return bool whether session write is successful
  123. */
  124. public function writeSession($id, $data)
  125. {
  126. // exception must be caught in session write handler
  127. // http://us.php.net/manual/en/function.session-set-save-handler.php
  128. try {
  129. $this->db->getCollection($this->sessionCollection)->update(
  130. ['id' => $id],
  131. $this->composeFields($id, $data),
  132. ['upsert' => true]
  133. );
  134. } catch (\Exception $e) {
  135. Yii::$app->errorHandler->handleException($e);
  136. return false;
  137. }
  138. return true;
  139. }
  140. /**
  141. * Session destroy handler.
  142. * Do not call this method directly.
  143. * @param string $id session ID
  144. * @return bool whether session is destroyed successfully
  145. */
  146. public function destroySession($id)
  147. {
  148. $this->db->getCollection($this->sessionCollection)->remove(
  149. ['id' => $id],
  150. ['justOne' => true]
  151. );
  152. return true;
  153. }
  154. /**
  155. * Session GC (garbage collection) handler.
  156. * Do not call this method directly.
  157. * @param int $maxLifetime the number of seconds after which data will be seen as 'garbage' and cleaned up.
  158. * @return bool whether session is GCed successfully
  159. */
  160. public function gcSession($maxLifetime)
  161. {
  162. $this->db->getCollection($this->sessionCollection)
  163. ->remove(['expire' => ['$lt' => time()]]);
  164. return true;
  165. }
  166. }