diff --git a/README.md b/README.md index 2cf12ab..fac47d0 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ composer require rancoud/session By default session is in read only (option read_and_close = 1). You can specify it using `Session::setReadWrite()` or `Session::setReadOnly()` -Session::start() is not needed, but: +Session::start() is not needed, but: * Session will automatically start in read only when using `get, has, hasKeyAndValue, getAll` * Session will automatically start in write mode when using `set, remove, getAndRemove, keepFlash, gc, regenerate` @@ -98,86 +98,88 @@ $value = Session::get('key'); ``` ## Session -### Static General Commands -* start([options: array = []]): void -* regenerate(): bool -* destroy(): bool -* commit(): void -* rollback(): bool -* unsaved(): bool -* hasStarted(): bool -* getId(): string -* setId(id: string): string -* gc(): void -* setReadOnly(): void -* setReadWrite(): void +### Static General Commands +* start([options: array = []]): void +* regenerate(): bool +* destroy(): bool +* commit(): void +* rollback(): bool +* unsaved(): bool +* hasStarted(): bool +* getId(): string +* setId(id: string): string +* gc(): void +* setReadOnly(): void +* setReadWrite(): void * isReadOnly(): bool ### Static Variables $_SESSION access -* set(key: string, value: mixed): void -* get(key: string): mixed -* getAll(): array -* getAndRemove(key: string): mixed -* has(key: string): bool -* hasKeyAndValue(key: string, value: mixed): bool -* remove(key: string): void +* set(key: string, value: mixed): void +* get(key: string): mixed +* getAll(): array +* getAndRemove(key: string): mixed +* has(key: string): bool +* hasKeyAndValue(key: string, value: mixed): bool +* remove(key: string): void ### Static Variables flash access Flash data are store in a separate variable. They will dissapear at the end of the script execution or after `commit()` `unsaved()`. You can use keepFlash for saving it in $_SESSION. -When flash data is restore, it will be delete in $_SESSION. +When flash data is restore, it will be delete in $_SESSION. -* setFlash(key: string, value: mixed): void -* getFlash(key: string): mixed -* getAllFlash(): array -* hasFlash(key: string): bool -* hasFlashKeyAndValue(key: string, value: mixed): bool -* keepFlash([keys: array = []]): void +* setFlash(key: string, value: mixed): void +* getFlash(key: string): mixed +* getAllFlash(): array +* hasFlash(key: string): bool +* hasFlashKeyAndValue(key: string, value: mixed): bool +* keepFlash([keys: array = []]): void -### Static Options -* setOption(key: string, value): void -* setOptions(options: array): void -* getOption(key: string): mixed +### Static Options +* setOption(key: string, value): void +* setOptions(options: array): void +* getOption(key: string): mixed ### Static Driver -* getDriver(): \SessionHandlerInterface +* getDriver(): \SessionHandlerInterface #### Static PHP Session Default Driver -* useDefaultDriver(): void -* useDefaultEncryptionDriver(key: string, [method: string|null = null]): void -* setLengthSessionID(length: int): void -* getLengthSessionID(): int +* useDefaultDriver(): void +* useDefaultEncryptionDriver(key: string, [method: string|null = null]): void +* setLengthSessionID(length: int): void +* getLengthSessionID(): int #### Static File Driver -* useFileDriver(): void -* useFileEncryptionDriver(key: string, [method: string|null = null]): void -* setPrefixForFile(prefix: string): void +* useFileDriver(): void +* useFileEncryptionDriver(key: string, [method: string|null = null]): void +* setPrefixForFile(prefix: string): void * setLengthSessionID(length: int): void * getLengthSessionID(): int #### Static Database Driver -* useNewDatabaseDriver(configuration: \Rancoud\Database\Configurator|array): void -* useCurrentDatabaseDriver(databaseInstance: \Rancoud\Database\Database): void -* useNewDatabaseEncryptionDriver(configuration: \Rancoud\Database\Configurator|array, key: string, [method: string = null]): void -* useCurrentDatabaseEncryptionDriver(databaseInstance: \Rancoud\Database\Database, key: string, [method: string = null]): void -* setUserIdForDatabase(userId: int): void +* useNewDatabaseDriver(configuration: \Rancoud\Database\Configurator|array): void +* useCurrentDatabaseDriver(databaseInstance: \Rancoud\Database\Database): void +* useNewDatabaseEncryptionDriver(configuration: \Rancoud\Database\Configurator|array, key: string, [method: string = null]): void +* useCurrentDatabaseEncryptionDriver(databaseInstance: \Rancoud\Database\Database, key: string, [method: string = null]): void +* setUserIdForDatabase(userId: int): void * setLengthSessionID(length: int): void * getLengthSessionID(): int +* deleteUserSessions(int $userID): void +* deleteAnonymousSessions(): int #### Static Redis Driver -* useNewRedisDriver(configuration: array|string): void -* useCurrentRedisDriver(redisInstance: \Predis\Client): void -* useNewRedisEncryptionDriver(configuration: array|string, key: string, [method: string = null]): void -* useCurrentRedisEncryptionDriver(redisInstance: \Predis\Client, key: string, [method: string = null]): void +* useNewRedisDriver(configuration: array|string): void +* useCurrentRedisDriver(redisInstance: \Predis\Client): void +* useNewRedisEncryptionDriver(configuration: array|string, key: string, [method: string = null]): void +* useCurrentRedisEncryptionDriver(redisInstance: \Predis\Client, key: string, [method: string = null]): void * setLengthSessionID(length: int): void -* getLengthSessionID(): int +* getLengthSessionID(): int #### Static Custom Driver -* useCustomDriver(customDriver: \SessionHandlerInterface): void +* useCustomDriver(customDriver: \SessionHandlerInterface): void ## Session options -List of session options you can change: +List of session options you can change: * save_path * name * save_handler diff --git a/src/Database.php b/src/Database.php index 1417e8e..59a3e54 100644 --- a/src/Database.php +++ b/src/Database.php @@ -57,6 +57,29 @@ public function getLengthSessionID(): int return $this->lengthSessionID; } + /** @throws SessionException */ + public function deleteUserSessions(int $userID): void + { + try { + $sql = 'DELETE FROM sessions WHERE id_user = :id_user'; + $params = ['id_user' => $userID]; + $this->db->delete($sql, $params); + } catch (DatabaseException $e) { + throw new SessionException('could not delete sessions: ' . $e->getMessage(), $e->getCode(), $e->getPrevious()); + } + } + + /** @throws SessionException */ + public function deleteAnonymousSessions(): void + { + try { + $sql = 'DELETE FROM sessions WHERE id_user IS NULL'; + $this->db->delete($sql); + } catch (DatabaseException $e) { + throw new SessionException('could not delete sessions: ' . $e->getMessage(), $e->getCode(), $e->getPrevious()); + } + } + public function open(string $path, string $name): bool { return true; diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index dbecd9b..223d3d0 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -450,4 +450,125 @@ public function testLengthSessionIDSessionException(): void $database = new Database(); $database->setLengthSessionID(1); } + + /** + * @throws DatabaseException + * @throws SessionException + */ + public function testDeleteUserSessions(): void + { + $database = new Database(); + $database->setCurrentDatabase(static::$db); + + $data = 'azerty'; + + $database->setUserId(10); + + static::assertTrue($database->write('session_id_10', $data)); + static::assertTrue($database->write('session_id_20', $data)); + static::assertTrue($database->write('session_id_30', $data)); + + $database->setUserId(20); + + static::assertTrue($database->write('session_id_40', $data)); + static::assertTrue($database->write('session_id_50', $data)); + static::assertTrue($database->write('session_id_60', $data)); + + $sql = 'SELECT id FROM sessions WHERE id_user = :id_user'; + $params = ['id_user' => 10]; + $sessionsFromDatabase = static::$db->selectCol($sql, $params); + static::assertSame(['session_id_10', 'session_id_20', 'session_id_30'], $sessionsFromDatabase); + + $sql = 'SELECT id FROM sessions WHERE id_user = :id_user'; + $params = ['id_user' => 20]; + $sessionsFromDatabase = static::$db->selectCol($sql, $params); + static::assertSame(['session_id_40', 'session_id_50', 'session_id_60'], $sessionsFromDatabase); + + $database->deleteUserSessions(10); + + $sql = 'SELECT id FROM sessions'; + $sessionsFromDatabase = static::$db->selectCol($sql); + static::assertSame(['session_id_40', 'session_id_50', 'session_id_60'], $sessionsFromDatabase); + } + + /** + * @throws DatabaseException + * @throws SessionException + */ + public function testDeleteUserSessionsSessionException(): void + { + $this->expectException(SessionException::class); + $this->expectExceptionMessage('could not delete sessions: Error Connecting Database'); + + $database = new Database(); + $database->setNewDatabase([ + 'driver' => 'mysql', + 'host' => 'mariadb', + 'user' => 'invalid', + 'password' => '', + 'database' => 'test_database' + ]); + + $database->deleteUserSessions(1); + } + + /** + * @throws DatabaseException + * @throws SessionException + */ + public function testDeleteAnonymousSessions(): void + { + $database = new Database(); + $database->setCurrentDatabase(static::$db); + + $data = 'azerty'; + + $database->setUserId(10); + + static::assertTrue($database->write('session_id_10', $data)); + static::assertTrue($database->write('session_id_20', $data)); + static::assertTrue($database->write('session_id_30', $data)); + + $database->setUserId(null); + + static::assertTrue($database->write('session_id_40', $data)); + static::assertTrue($database->write('session_id_50', $data)); + static::assertTrue($database->write('session_id_60', $data)); + + $sql = 'SELECT id FROM sessions WHERE id_user = :id_user'; + $params = ['id_user' => 10]; + $sessionsFromDatabase = static::$db->selectCol($sql, $params); + static::assertSame(['session_id_10', 'session_id_20', 'session_id_30'], $sessionsFromDatabase); + + $sql = 'SELECT id FROM sessions WHERE id_user IS NULL'; + $sessionsFromDatabase = static::$db->selectCol($sql); + static::assertSame(['session_id_40', 'session_id_50', 'session_id_60'], $sessionsFromDatabase); + + $database->deleteAnonymousSessions(10); + + $sql = 'SELECT id FROM sessions'; + $sessionsFromDatabase = static::$db->selectCol($sql); + static::assertSame(['session_id_10', 'session_id_20', 'session_id_30'], $sessionsFromDatabase); + } + + /** + * @throws DatabaseException + * @throws SessionException + */ + public function testDeleteAnonymousSessionsSessionException(): void + { + $this->expectException(SessionException::class); + $this->expectExceptionMessage('could not delete sessions: Error Connecting Database'); + + $database = new Database(); + $database->setNewDatabase([ + 'driver' => 'mysql', + 'host' => 'mariadb', + 'user' => 'invalid', + 'password' => '', + 'database' => 'test_database' + ]); + + $database->deleteAnonymousSessions(); + } }