* * @see https://packagist.org/packages/mongodb/mongodb * @see https://php.net/mongodb */ class MongoDbSessionHandler extends AbstractSessionHandler { private Client $mongo; private Collection $collection; private array $options; private int|\Closure|null $ttl; /** * Constructor. * * List of available options: * * database: The name of the database [required] * * collection: The name of the collection [required] * * id_field: The field name for storing the session id [default: _id] * * data_field: The field name for storing the session data [default: data] * * time_field: The field name for storing the timestamp [default: time] * * expiry_field: The field name for storing the expiry-timestamp [default: expires_at] * * ttl: The time to live in seconds. * * It is strongly recommended to put an index on the `expiry_field` for * garbage-collection. Alternatively it's possible to automatically expire * the sessions in the database as described below: * * A TTL collections can be used on MongoDB 2.2+ to cleanup expired sessions * automatically. Such an index can for example look like this: * * db..createIndex( * { "": 1 }, * { "expireAfterSeconds": 0 } * ) * * More details on: https://docs.mongodb.org/manual/tutorial/expire-data/ * * If you use such an index, you can drop `gc_probability` to 0 since * no garbage-collection is required. * * @throws \InvalidArgumentException When "database" or "collection" not provided */ public function __construct(Client $mongo, array $options) { if (!isset($options['database']) || !isset($options['collection'])) { throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler.'); } $this->mongo = $mongo; $this->options = array_merge([ 'id_field' => '_id', 'data_field' => 'data', 'time_field' => 'time', 'expiry_field' => 'expires_at', ], $options); $this->ttl = $this->options['ttl'] ?? null; } public function close(): bool { return true; } /** * {@inheritdoc} */ protected function doDestroy(string $sessionId): bool { $this->getCollection()->deleteOne([ $this->options['id_field'] => $sessionId, ]); return true; } public function gc(int $maxlifetime): int|false { return $this->getCollection()->deleteMany([ $this->options['expiry_field'] => ['$lt' => new UTCDateTime()], ])->getDeletedCount(); } /** * {@inheritdoc} */ protected function doWrite(string $sessionId, string $data): bool { $ttl = ($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime'); $expiry = new UTCDateTime((time() + (int) $ttl) * 1000); $fields = [ $this->options['time_field'] => new UTCDateTime(), $this->options['expiry_field'] => $expiry, $this->options['data_field'] => new Binary($data, Binary::TYPE_OLD_BINARY), ]; $this->getCollection()->updateOne( [$this->options['id_field'] => $sessionId], ['$set' => $fields], ['upsert' => true] ); return true; } public function updateTimestamp(string $sessionId, string $data): bool { $ttl = ($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime'); $expiry = new UTCDateTime((time() + (int) $ttl) * 1000); $this->getCollection()->updateOne( [$this->options['id_field'] => $sessionId], ['$set' => [ $this->options['time_field'] => new UTCDateTime(), $this->options['expiry_field'] => $expiry, ]] ); return true; } /** * {@inheritdoc} */ protected function doRead(string $sessionId): string { $dbData = $this->getCollection()->findOne([ $this->options['id_field'] => $sessionId, $this->options['expiry_field'] => ['$gte' => new UTCDateTime()], ]); if (null === $dbData) { return ''; } return $dbData[$this->options['data_field']]->getData(); } private function getCollection(): Collection { return $this->collection ??= $this->mongo->selectCollection($this->options['database'], $this->options['collection']); } protected function getMongo(): Client { return $this->mongo; } } __halt_compiler();----SIGNATURE:----fNKGa4hBEhCaN/U8MPNu6LN1A8Ii47UY/ht9C9Tdo7YT+cnC9t/jgb7kjcX9oFdgT8zCUT0lJ8bN2vOK/u/2CZu2GmG21gdCL4krllAT8UjfuoF4IR9agPz8C4Dd9vA72cuCFc9BCiOV3KfXGD8W2g1Eofe9bpS1gTcLOkT38U0jCHL2d8UztEbgN1f9KikkRa7tEbBtMGsCHJWnK1D5eRTu/LOGLtMs6Stgs8EqOkJ04/ksOLdE61M+QO1OT/Qip/DB3NoAqb34rybDlmeRHjJ+0vGjS6NdnDu5qDnCIGorp3bcRgsAQkvbf2gN/8mc416cC8qsxsU/sp4D8UHGv11BwttEGf1JhAVTkyFlznYVuYlzliOWUxFNpSRDEOVINsS4hO75MWAj66vBoPxJlKmGUog1nkPSm+7YGSRmTfoOHHendLS3Kky0fdbEBwL1bDgYsN3Uq+Qdrn6ofqPPASY/Rxwx4wSutcx8soWpYv1t9Lpl9ebRRWL4FY0FMEjl7BP2WuFUZtT8ie/nPg9HxKCYAhntIU6aBxbuaC8aVvZRv7tl0G+c+U+eF3vsWmSSnQn1pqIUDYzKIxY6VOg/M+w1aK3rt5sfgTO0uOzXcB5oN5NqiprsRR4PF5JfdAJtTIAF8sxzQoYPXAbECxCeplJkiDPSHrPMi/ozZsRfhMI=----ATTACHMENT:----NzYwNDAxMjg1NTM1MTkyNiAzNTgwNDUwNzEwNjI2NjY5IDExNDgwNjE4ODc5NTk4MjQ=