1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
13:
14: 15: 16: 17: 18:
19: class MongoDbSessionHandler implements \SessionHandlerInterface
20: {
21: 22: 23:
24: private $mongo;
25:
26: 27: 28:
29: private $collection;
30:
31: 32: 33:
34: private $options;
35:
36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69:
70: public function __construct($mongo, array $options)
71: {
72: if (!($mongo instanceof \MongoDB\Client || $mongo instanceof \MongoClient || $mongo instanceof \Mongo)) {
73: throw new \InvalidArgumentException('MongoClient or Mongo instance required');
74: }
75:
76: if (!isset($options['database']) || !isset($options['collection'])) {
77: throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler');
78: }
79:
80: $this->mongo = $mongo;
81:
82: $this->options = array_merge(array(
83: 'id_field' => '_id',
84: 'data_field' => 'data',
85: 'time_field' => 'time',
86: 'expiry_field' => 'expires_at',
87: ), $options);
88: }
89:
90: 91: 92:
93: public function open($savePath, $sessionName)
94: {
95: return true;
96: }
97:
98: 99: 100:
101: public function close()
102: {
103: return true;
104: }
105:
106: 107: 108:
109: public function destroy($sessionId)
110: {
111: $methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteOne' : 'remove';
112:
113: $this->getCollection()->$methodName(array(
114: $this->options['id_field'] => $sessionId,
115: ));
116:
117: return true;
118: }
119:
120: 121: 122:
123: public function gc($maxlifetime)
124: {
125: $methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteOne' : 'remove';
126:
127: $this->getCollection()->$methodName(array(
128: $this->options['expiry_field'] => array('$lt' => $this->createDateTime()),
129: ));
130:
131: return true;
132: }
133:
134: 135: 136:
137: public function write($sessionId, $data)
138: {
139: $expiry = $this->createDateTime(time() + (int) ini_get('session.gc_maxlifetime'));
140:
141: $fields = array(
142: $this->options['time_field'] => $this->createDateTime(),
143: $this->options['expiry_field'] => $expiry,
144: );
145:
146: $options = array('upsert' => true);
147:
148: if ($this->mongo instanceof \MongoDB\Client) {
149: $fields[$this->options['data_field']] = new \MongoDB\BSON\Binary($data, \MongoDB\BSON\Binary::TYPE_OLD_BINARY);
150: } else {
151: $fields[$this->options['data_field']] = new \MongoBinData($data, \MongoBinData::BYTE_ARRAY);
152: $options['multiple'] = false;
153: }
154:
155: $methodName = $this->mongo instanceof \MongoDB\Client ? 'updateOne' : 'update';
156:
157: $this->getCollection()->$methodName(
158: array($this->options['id_field'] => $sessionId),
159: array('$set' => $fields),
160: $options
161: );
162:
163: return true;
164: }
165:
166: 167: 168:
169: public function read($sessionId)
170: {
171: $dbData = $this->getCollection()->findOne(array(
172: $this->options['id_field'] => $sessionId,
173: $this->options['expiry_field'] => array('$gte' => $this->createDateTime()),
174: ));
175:
176: if (null === $dbData) {
177: return '';
178: }
179:
180: if ($dbData[$this->options['data_field']] instanceof \MongoDB\BSON\Binary) {
181: return $dbData[$this->options['data_field']]->getData();
182: }
183:
184: return $dbData[$this->options['data_field']]->bin;
185: }
186:
187: 188: 189: 190: 191:
192: private function getCollection()
193: {
194: if (null === $this->collection) {
195: $this->collection = $this->mongo->selectCollection($this->options['database'], $this->options['collection']);
196: }
197:
198: return $this->collection;
199: }
200:
201: 202: 203: 204: 205:
206: protected function getMongo()
207: {
208: return $this->mongo;
209: }
210:
211: 212: 213: 214: 215: 216: 217: 218: 219:
220: private function createDateTime($seconds = null)
221: {
222: if (null === $seconds) {
223: $seconds = time();
224: }
225:
226: if ($this->mongo instanceof \MongoDB\Client) {
227: return new \MongoDB\BSON\UTCDateTime($seconds * 1000);
228: }
229:
230: return new \MongoDate($seconds);
231: }
232: }
233: