From: Andrey Kutejko Date: Sat, 16 Aug 2014 08:08:09 +0000 (+0300) Subject: rewrite session app. no orm, two backends X-Git-Tag: 0.6~199 X-Git-Url: https://git.andy128k.dev/?a=commitdiff_plain;h=8826747bea9b329f1fed62cc92f9dae6b3bcfe4e;p=ipf.git rewrite session app. no orm, two backends --- diff --git a/composer.json b/composer.json index 21b9160..3a7dd33 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,7 @@ "require": { "pear/archive_tar": "1.3.*", "mustangostang/spyc": "0.5.*", + "lichtner/fluentpdo": "dev-master", "andy128k/missing-tools": "0.2.*@dev", "andy128k/migrations": "dev-master", "andy128k/pegp": "0.1.*@dev", diff --git a/composer.lock b/composer.lock index 4bb3d9a..be8ca0d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "85f0406cc02d8f1f4650eb652d1cc65b", + "hash": "7132f66df1bb9071ac21329f579f6132", "packages": [ { "name": "andy128k/ipf-template", @@ -164,6 +164,46 @@ "description": "Route expression", "time": "2013-08-02 19:17:54" }, + { + "name": "lichtner/fluentpdo", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/lichtner/fluentpdo.git", + "reference": "26d6a5b9dda8a94d14b2ac037caf10362f92b487" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lichtner/fluentpdo/zipball/26d6a5b9dda8a94d14b2ac037caf10362f92b487", + "reference": "26d6a5b9dda8a94d14b2ac037caf10362f92b487", + "shasum": "" + }, + "type": "library", + "autoload": { + "files": [ + "FluentPDO/FluentPDO.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0", + "GPL-2.0+" + ], + "authors": [ + { + "name": "Marek Lichtner", + "homepage": "http://licht.sk/" + } + ], + "description": "FluentPDO is small PHP library for rapid query building. Killer feature is smart join builder which generates joins automatically.", + "homepage": "http://fluentpdo.com/", + "keywords": [ + "database", + "dbal", + "pdo" + ], + "time": "2014-01-09 20:25:56" + }, { "name": "mustangostang/spyc", "version": "0.5.1", @@ -680,6 +720,7 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { + "lichtner/fluentpdo": 20, "andy128k/missing-tools": 20, "andy128k/migrations": 20, "andy128k/pegp": 20, diff --git a/ipf/auth/app.php b/ipf/auth/app.php index a727b07..e0f5034 100644 --- a/ipf/auth/app.php +++ b/ipf/auth/app.php @@ -23,8 +23,9 @@ class IPF_Auth_App extends IPF_Application static function login($request, $user) { $request->user = $user; - $request->session->clear(); - $request->session->setData('login_time', gmdate('Y-m-d H:i:s')); + $request->session->data = array( + 'login_time' => gmdate('Y-m-d H:i:s') + ); $user->save(); } @@ -35,9 +36,10 @@ class IPF_Auth_App extends IPF_Application static function logout($request) { - $request->user = new User(); - $request->session->clear(); - $request->session->setData('logout_time', gmdate('Y-m-d H:i:s')); + $request->user = new User; + $request->session->data = array( + 'login_time' => gmdate('Y-m-d H:i:s') + ); } static function createPermissionsFromModels() diff --git a/ipf/auth/middleware.php b/ipf/auth/middleware.php new file mode 100644 index 0000000..6f6f676 --- /dev/null +++ b/ipf/auth/middleware.php @@ -0,0 +1,32 @@ +user = null; + + $user_id = \PFF\Arr::get($request->session->data, self::SessionKey, 0); + if ($user_id > 0) { + $request->user = User::table()->find($user_id); + if ($request->user && 43200 < IPF_Utils::dateCompare($request->user->last_login)) { + $request->user->last_login = gmdate('Y-m-d H:i:s'); + $request->user->save(); + } + } + + if (!$request->user) + $request->user = new User; + + return false; + } + + function processResponse($request, $response) + { + $request->session->data[self::SessionKey] = $request->user->id; + return $response; + } +} + diff --git a/ipf/auth/models/User.php b/ipf/auth/models/User.php index 461ba31..e8151e3 100644 --- a/ipf/auth/models/User.php +++ b/ipf/auth/models/User.php @@ -206,7 +206,6 @@ class AdminUser extends IPF_Admin_Model class User extends BaseUser { const UNUSABLE_PASSWORD = '!'; - public $session_key = 'IPF_User_auth'; private $profile = null; public function __toString() diff --git a/ipf/crypto.php b/ipf/crypto.php new file mode 100644 index 0000000..6b150a9 --- /dev/null +++ b/ipf/crypto.php @@ -0,0 +1,46 @@ +expired()) { + $session->delete(); + return null; + } + + return $session; + } + + private static function detectBackend($key) + { + foreach (self::$backends as $backend) { + $data = $backend::getData($key); + if ($data) + return array($backend, $data); + } + return null; + } + + public static function create() + { + $backend = self::$backends[0]; + return new $backend; + } + + + protected $key = null; + public $data = array(); + + public function __construct($key, $data) + { + $this->key = $key; + $this->data = $data; + } + + public function delete() + { + } + + public function cookie() + { + $this->data['updated_at'] = time(); + $this->save(); + return $this->key; + } + + protected abstract function save(); + + public function updatedAt() + { + return $this->data['updated_at']; + } + + public function expired() + { + return time() - $this->updatedAt() > 60 * 60 * 24 * 7; + } +} + + +class CookieSession extends Session +{ + public static function getData($key) + { + $key = explode('|', $key, 2); + if (count($key) !== 2) + return null; + list($data, $sign) = $key; + if (IPF_Crypto::sign($data) !== $sign) + return null; + + return unserialize(base64_decode($data)); + } + + protected function save() + { + $data = base64_encode(serialize($this->data)); + $this->key = $data.'|'.IPF_Crypto::sign($data); + } +} + + +class DBSession extends Session +{ + private static function query() + { + $connection = \PFF\Container::databaseConnection(); + return new FluentPDO($connection); + } + + public static function getData($key) + { + $data = self::query() + ->from('session') + ->where('session_key', $key) + ->fetch('data'); + if ($data) + return unserialize($data); + else + return null; + } + + public function delete() + { + self::query() + ->deleteFrom('session') + ->where('session_key', $key) + ->execute(); + + $this->key = null; + } + + protected function save() + { + $params = array( + 'data' => serialize($this->data), + 'updated_at' => gmdate('Y-m-d H:i:s', $this->updatedAt()), + ); + + if ($this->key) { + self::query() + ->update('session') + ->where('session_key', $this->key) + ->set($params) + ->execute(); + } else { + $params['session_key'] = $this->key = self::getNewSessionKey(); + self::query() + ->insertInto('session', $params) + ->execute(); + } + } + + private static function getNewSessionKey($secret_key=null) { - parent::__construct(array( - 'models' => array('Session') - )); + if (!$secret_key) + $secret_key = IPF::get('secret_key'); + return md5(microtime().rand(0, 123456789).rand(0, 123456789).$secret_key); } } diff --git a/ipf/session/middleware.php b/ipf/session/middleware.php index 65840ed..8c5497b 100644 --- a/ipf/session/middleware.php +++ b/ipf/session/middleware.php @@ -4,93 +4,20 @@ class IPF_Session_Middleware { function processRequest(&$request) { - $session = new Session(); - $user = new User(); - if (!isset($request->COOKIE[IPF::get('session_cookie_id')])) { - $request->user = $user; - $request->session = $session; - return false; - } - try { - $data = $this->_decodeData($request->COOKIE[IPF::get('session_cookie_id')]); - } catch (Exception $e) { - $request->user = $user; - $request->session = $session; - return false; - } - if (isset($data[$user->session_key])) { - $found_user = $user->getTable()->find($data[$user->session_key]); - if ($found_user) { - $request->user = $found_user; - if (43200 < IPF_Utils::dateCompare($request->user->last_login)) { - $request->user->last_login = gmdate('Y-m-d H:i:s'); - $request->user->save(); - } - } else - $request->user = $user; - } else - $request->user = $user; + $session_cookie = \PFF\Arr::get($request->COOKIE, IPF::get('session_cookie_id')); + + $request->session = Session::get($session_cookie); + if (!$request->session) + $request->session = Session::create(); - if (isset($data['IPF_SESSION_KEY'])) { - $found_session = $session->getTable()->findOneBySession_key($data['IPF_SESSION_KEY']); - if ($found_session) - $request->session = $found_session; - else - $request->session = $session; - } else { - $request->session = $session; - } return false; } function processResponse($request, $response) { - if ($request->session->touched) { - $request->session->save(); - $data = array(); - if ($request->user->id > 0) { - $data[$request->user->session_key] = $request->user->id; - } - $data['IPF_SESSION_KEY'] = $request->session->session_key; - $response->cookies[IPF::get('session_cookie_id')] = $this->_encodeData($data); - } + $session_cookie = $request->session->cookie(); + $response->cookies[IPF::get('session_cookie_id')] = $session_cookie; return $response; } - - protected function _encodeData($data) - { - if ('' == ($key = IPF::get('secret_key'))) { - throw new IPF_Exception('Security error: "secret_key" is not set in the configuration file.'); - } - $data = serialize($data); - return base64_encode($data).md5(base64_encode($data).$key); - } - - protected function _decodeData($encoded_data) - { - $check = substr($encoded_data, -32); - $base64_data = substr($encoded_data, 0, strlen($encoded_data)-32); - if (md5($base64_data.IPF::get('secret_key')) != $check) { - throw new IPF_Exception('The session data may have been tampered.'); - } - return unserialize(base64_decode($base64_data)); - } - - /* - public static function processContext($signal, &$params) - { - $params['context'] = array_merge($params['context'], - IPF_Session_Middleware_ContextPreProcessor($params['request'])); - } - */ -} - -/* -function IPF_Session_Middleware_ContextPreProcessor($request) -{ - return array('user' => $request->user); } -Pluf_Signal::connect('Pluf_Template_Context_Request::construct', - array('Pluf_Middleware_Session', 'processContext')); -*/ diff --git a/ipf/session/migrations/20140101000000_create_sessions.php b/ipf/session/migrations/20140101000000_create_sessions.php new file mode 100644 index 0000000..9d59e5c --- /dev/null +++ b/ipf/session/migrations/20140101000000_create_sessions.php @@ -0,0 +1,10 @@ +connection->exec('CREATE TABLE session (session_key VARCHAR(40), data TEXT, updated_at TIMESTAMP, PRIMARY KEY(session_key)) ENGINE = INNODB'); + } +} + diff --git a/ipf/session/models.yml b/ipf/session/models.yml deleted file mode 100644 index 7574c05..0000000 --- a/ipf/session/models.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -Session: - columns: - session_key: - primary: true - type: string(40) - session_data: string - expire_data: timestamp - diff --git a/ipf/session/models/Session.php b/ipf/session/models/Session.php deleted file mode 100644 index 5054e42..0000000 --- a/ipf/session/models/Session.php +++ /dev/null @@ -1,64 +0,0 @@ -data = array(); - $this->touched = true; - } - - function getSessionData() - { - return unserialize($this->session_data); - } - - private function unserializeData() - { - if (!$this->data) - $this->data = $this->getSessionData(); - } - - function setData($key, $value=null) - { - $this->unserializeData(); - if (is_null($value)) { - unset($this->data[$key]); - } else { - $this->data[$key] = $value; - } - $this->touched = true; - } - - function getData($key=null, $default='') - { - if (is_null($key)) - return parent::getData(); - - $this->unserializeData(); - if (isset($this->data[$key])) { - return $this->data[$key]; - } else { - return $default; - } - } - - function getNewSessionKey() - { - $key = md5(microtime().rand(0, 123456789).rand(0, 123456789).IPF::get('secret_key')); - return $key; - } - - function preSave($event) - { - $this->session_data = serialize($this->data); - if ($this->session_key == '') { - $this->session_key = $this->getNewSessionKey(); - } - $this->expire_data = gmdate('Y-m-d H:i:s', time()+31536000); - } -} - diff --git a/ipf/session/models/_generated/BaseSession.php b/ipf/session/models/_generated/BaseSession.php deleted file mode 100644 index 98eb6e4..0000000 --- a/ipf/session/models/_generated/BaseSession.php +++ /dev/null @@ -1,29 +0,0 @@ -setTableName('session'); - $table->setColumn('session_key', 'string', 40, array('primary' => true, 'type' => 'string', 'length' => '40')); - $table->setColumn('session_data', 'string', null, array('type' => 'string')); - $table->setColumn('expire_data', 'timestamp', null, array('type' => 'timestamp')); - } - - - public static function table() - { - return IPF_ORM::getTable('Session'); - } - - public static function query($alias='') - { - return IPF_ORM::getTable('Session')->createQuery($alias); - } -} \ No newline at end of file