Merged in feature/MAPG-131-store-session-is-database (pull request #106)
Feature/MAPG-131 store session is database
This commit is contained in:
commit
9e196ebf33
6
database/migrations/structure/20200613_1549_sessions.sql
Normal file
6
database/migrations/structure/20200613_1549_sessions.sql
Normal file
@ -0,0 +1,6 @@
|
||||
CREATE TABLE `sessions` (
|
||||
`id` varchar(64) NOT NULL,
|
||||
`data` text NOT NULL,
|
||||
`updated` timestamp NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
|
12
main.php
12
main.php
@ -10,21 +10,11 @@ const REVISION_DATE = '';
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(ROOT);
|
||||
$dotenv->load();
|
||||
|
||||
if (!empty($_ENV['DEV'])) {
|
||||
error_reporting(E_ALL);
|
||||
|
||||
ini_set('display_errors', '1');
|
||||
} else {
|
||||
ini_set('display_errors', '0');
|
||||
}
|
||||
|
||||
class Container
|
||||
{
|
||||
static MapGuesser\Interfaces\Database\IConnection $dbConnection;
|
||||
static MapGuesser\Routing\RouteCollection $routeCollection;
|
||||
static \SessionHandlerInterface $sessionHandler;
|
||||
}
|
||||
|
||||
Container::$dbConnection = new MapGuesser\Database\Mysql\Connection($_ENV['DB_HOST'], $_ENV['DB_USER'], $_ENV['DB_PASSWORD'], $_ENV['DB_NAME']);
|
||||
Container::$routeCollection = new MapGuesser\Routing\RouteCollection();
|
||||
|
||||
session_start();
|
||||
|
@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
require '../main.php';
|
||||
require '../web.php';
|
||||
|
||||
// very basic routing
|
||||
$host = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'];
|
||||
$method = strtolower($_SERVER['REQUEST_METHOD']);
|
||||
$url = substr($_SERVER['REQUEST_URI'], strlen('/'));
|
||||
@ -11,23 +10,6 @@ if (($pos = strpos($url, '?')) !== false) {
|
||||
}
|
||||
$url = rawurldecode($url);
|
||||
|
||||
Container::$routeCollection->get('index', '', [MapGuesser\Controller\HomeController::class, 'getIndex']);
|
||||
Container::$routeCollection->get('login', 'login', [MapGuesser\Controller\LoginController::class, 'getLoginForm']);
|
||||
Container::$routeCollection->post('login-action', 'login', [MapGuesser\Controller\LoginController::class, 'login']);
|
||||
Container::$routeCollection->get('logout', 'logout', [MapGuesser\Controller\LoginController::class, 'logout']);
|
||||
Container::$routeCollection->get('maps', 'maps', [MapGuesser\Controller\MapsController::class, 'getMaps']);
|
||||
Container::$routeCollection->group('game', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
||||
$routeCollection->get('game', '{mapId}', [MapGuesser\Controller\GameController::class, 'getGame']);
|
||||
$routeCollection->get('game-json', '{mapId}/json', [MapGuesser\Controller\GameController::class, 'getGameJson']);
|
||||
$routeCollection->get('newPlace-json', '{mapId}/newPlace.json', [MapGuesser\Controller\GameFlowController::class, 'getNewPlace']);
|
||||
$routeCollection->post('guess-json', '{mapId}/guess.json', [MapGuesser\Controller\GameFlowController::class, 'evaluateGuess']);
|
||||
});
|
||||
Container::$routeCollection->group('admin', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
||||
$routeCollection->get('admin.mapEditor', 'mapEditor/{mapId?}', [MapGuesser\Controller\MapAdminController::class, 'getMapEditor']);
|
||||
$routeCollection->get('admin.place', 'place.json/{placeId}', [MapGuesser\Controller\MapAdminController::class, 'getPlace']);
|
||||
$routeCollection->post('admin.saveMap', 'saveMap/{mapId}/json', [MapGuesser\Controller\MapAdminController::class, 'saveMap']);
|
||||
});
|
||||
|
||||
$match = Container::$routeCollection->match($method, explode('/', $url));
|
||||
|
||||
if ($match !== null) {
|
||||
|
@ -16,6 +16,8 @@ class Modify
|
||||
|
||||
private array $original = [];
|
||||
|
||||
private ?string $externalId = null;
|
||||
|
||||
private bool $autoIncrement = true;
|
||||
|
||||
public function __construct(IConnection $connection, string $table)
|
||||
@ -31,6 +33,13 @@ class Modify
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setExternalId($id): Modify
|
||||
{
|
||||
$this->externalId = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAutoIncrement(bool $autoIncrement = true): Modify
|
||||
{
|
||||
$this->autoIncrement = $autoIncrement;
|
||||
@ -87,7 +96,9 @@ class Modify
|
||||
|
||||
private function insert(): void
|
||||
{
|
||||
if (!$this->autoIncrement) {
|
||||
if ($this->externalId !== null) {
|
||||
$this->attributes[$this->idName] = $this->externalId;
|
||||
} elseif (!$this->autoIncrement) {
|
||||
$this->attributes[$this->idName] = $this->generateKey();
|
||||
}
|
||||
|
||||
|
113
src/Session/DatabaseSessionHandler.php
Normal file
113
src/Session/DatabaseSessionHandler.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php namespace MapGuesser\Session;
|
||||
|
||||
use DateTime;
|
||||
use MapGuesser\Database\Query\Modify;
|
||||
use MapGuesser\Database\Query\Select;
|
||||
use MapGuesser\Interfaces\Database\IResultSet;
|
||||
use SessionHandlerInterface;
|
||||
use SessionIdInterface;
|
||||
use SessionUpdateTimestampHandlerInterface;
|
||||
|
||||
class DatabaseSessionHandler implements SessionHandlerInterface, SessionIdInterface, SessionUpdateTimestampHandlerInterface
|
||||
{
|
||||
private bool $exists = false;
|
||||
|
||||
private bool $written = false;
|
||||
|
||||
public function open($savePath, $sessionName): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function close(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function read($id): string
|
||||
{
|
||||
$select = new Select(\Container::$dbConnection, 'sessions');
|
||||
$select->columns(['data']);
|
||||
$select->whereId($id);
|
||||
|
||||
$result = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
|
||||
|
||||
if ($result === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$this->exists = true;
|
||||
|
||||
return $result['data'];
|
||||
}
|
||||
|
||||
public function write($id, $data): bool
|
||||
{
|
||||
$modify = new Modify(\Container::$dbConnection, 'sessions');
|
||||
|
||||
if ($this->exists) {
|
||||
$modify->setId($id);
|
||||
} else {
|
||||
$modify->setExternalId($id);
|
||||
}
|
||||
|
||||
$modify->set('data', $data);
|
||||
$modify->set('updated', (new DateTime())->format('Y-m-d H:i:s'));
|
||||
$modify->save();
|
||||
|
||||
$written = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function destroy($id): bool
|
||||
{
|
||||
$modify = new Modify(\Container::$dbConnection, 'sessions');
|
||||
$modify->setId($id);
|
||||
$modify->delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function gc($maxlifetime): int
|
||||
{
|
||||
$select = new Select(\Container::$dbConnection, 'sessions');
|
||||
$select->columns(['id']);
|
||||
$select->where('updated', '<', (new DateTime('-' . $maxlifetime . ' seconds'))->format('Y-m-d H:i:s'));
|
||||
|
||||
$result = $select->execute();
|
||||
|
||||
while ($session = $result->fetch(IResultSet::FETCH_ASSOC)) {
|
||||
$modify = new Modify(\Container::$dbConnection, 'sessions');
|
||||
$modify->setId($session['id']);
|
||||
$modify->delete();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function create_sid(): string
|
||||
{
|
||||
return hash('sha256', random_bytes(10) . microtime());
|
||||
}
|
||||
|
||||
public function validateId($id): bool
|
||||
{
|
||||
return preg_match('/^[a-f0-9]{64}$/', $id);
|
||||
}
|
||||
|
||||
public function updateTimestamp($id, $data): bool
|
||||
{
|
||||
if ($this->written) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$modify = new Modify(\Container::$dbConnection, 'sessions');
|
||||
|
||||
$modify->setId($id);
|
||||
$modify->set('updated', (new DateTime())->format('Y-m-d H:i:s'));
|
||||
$modify->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
40
web.php
Normal file
40
web.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
require 'main.php';
|
||||
|
||||
if (!empty($_ENV['DEV'])) {
|
||||
error_reporting(E_ALL);
|
||||
|
||||
ini_set('display_errors', '1');
|
||||
} else {
|
||||
ini_set('display_errors', '0');
|
||||
}
|
||||
|
||||
Container::$routeCollection = new MapGuesser\Routing\RouteCollection();
|
||||
|
||||
Container::$routeCollection->get('index', '', [MapGuesser\Controller\HomeController::class, 'getIndex']);
|
||||
Container::$routeCollection->get('login', 'login', [MapGuesser\Controller\LoginController::class, 'getLoginForm']);
|
||||
Container::$routeCollection->post('login-action', 'login', [MapGuesser\Controller\LoginController::class, 'login']);
|
||||
Container::$routeCollection->get('logout', 'logout', [MapGuesser\Controller\LoginController::class, 'logout']);
|
||||
Container::$routeCollection->get('maps', 'maps', [MapGuesser\Controller\MapsController::class, 'getMaps']);
|
||||
Container::$routeCollection->group('game', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
||||
$routeCollection->get('game', '{mapId}', [MapGuesser\Controller\GameController::class, 'getGame']);
|
||||
$routeCollection->get('game-json', '{mapId}/json', [MapGuesser\Controller\GameController::class, 'getGameJson']);
|
||||
$routeCollection->get('newPlace-json', '{mapId}/newPlace.json', [MapGuesser\Controller\GameFlowController::class, 'getNewPlace']);
|
||||
$routeCollection->post('guess-json', '{mapId}/guess.json', [MapGuesser\Controller\GameFlowController::class, 'evaluateGuess']);
|
||||
});
|
||||
Container::$routeCollection->group('admin', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
||||
$routeCollection->get('admin.mapEditor', 'mapEditor/{mapId?}', [MapGuesser\Controller\MapAdminController::class, 'getMapEditor']);
|
||||
$routeCollection->get('admin.place', 'place.json/{placeId}', [MapGuesser\Controller\MapAdminController::class, 'getPlace']);
|
||||
$routeCollection->post('admin.saveMap', 'saveMap/{mapId}/json', [MapGuesser\Controller\MapAdminController::class, 'saveMap']);
|
||||
});
|
||||
|
||||
Container::$sessionHandler = new MapGuesser\Session\DatabaseSessionHandler();
|
||||
|
||||
session_set_save_handler(Container::$sessionHandler, true);
|
||||
session_start([
|
||||
'gc_maxlifetime' => 604800,
|
||||
'cookie_lifetime' => 604800,
|
||||
'cookie_httponly' => true,
|
||||
'cookie_samesite' => 'Lax'
|
||||
]);
|
Loading…
Reference in New Issue
Block a user