From ae68196e8d24f859a691774c027cbd8aacdfc463 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 3 Feb 2018 00:42:00 -0500 Subject: [PATCH 1/5] Add new Session classes in src/ --- src/Core/Session.php | 57 +++++++++++ src/Core/Session/DatabaseSessionHandler.php | 95 ++++++++++++++++++ src/Core/Session/MemcacheSessionHandler.php | 102 ++++++++++++++++++++ 3 files changed, 254 insertions(+) create mode 100644 src/Core/Session.php create mode 100644 src/Core/Session/DatabaseSessionHandler.php create mode 100644 src/Core/Session/MemcacheSessionHandler.php diff --git a/src/Core/Session.php b/src/Core/Session.php new file mode 100644 index 0000000000..b5c09f745b --- /dev/null +++ b/src/Core/Session.php @@ -0,0 +1,57 @@ + + */ +class Session +{ + public static $exists = false; + public static $expire = 180000; + + public static function init() + { + ini_set('session.gc_probability', 50); + ini_set('session.use_only_cookies', 1); + ini_set('session.cookie_httponly', 1); + + if (Config::get('system', 'ssl_policy') == SSL_POLICY_FULL) { + ini_set('session.cookie_secure', 1); + } + + if (!Config::get('system', 'disable_database_session')) { + $memcache = Cache::memcache(); + if (is_object($memcache)) { + $SessionHandler = new MemcacheSessionHandler($memcache); + } else { + $SessionHandler = new DatabaseSessionHandler(); + } + + session_set_save_handler($SessionHandler); + } + } + + public static function exists($name) + { + return isset($_SESSION[$name]); + } + + public static function get($name) + { + return defaults($_SESSION, $name, null); + } + + public static function set($name, $value) + { + $_SESSION[$name] = $value; + } +} diff --git a/src/Core/Session/DatabaseSessionHandler.php b/src/Core/Session/DatabaseSessionHandler.php new file mode 100644 index 0000000000..d017e2edd2 --- /dev/null +++ b/src/Core/Session/DatabaseSessionHandler.php @@ -0,0 +1,95 @@ + + */ +class DatabaseSessionHandler extends BaseObject implements SessionHandlerInterface +{ + public function open($save_path, $session_name) + { + return true; + } + + public function read($session_id) + { + if (!x($session_id)) { + return ''; + } + + $session = dba::selectFirst('session', ['data'], ['sid' => $session_id]); + if (DBM::is_result($session)) { + Session::$exists = true; + return $session['data']; + } + logger("no data for session $session_id", LOGGER_TRACE); + + return ''; + } + + /** + * @brief Standard PHP session write callback + * + * This callback updates the DB-stored session data and/or the expiration depending + * on the case. Uses the Session::expire global for existing session, 5 minutes + * for newly created session. + * + * @param string $session_id Session ID with format: [a-z0-9]{26} + * @param string $session_data Serialized session data + * @return boolean Returns false if parameters are missing, true otherwise + */ + public function write($session_id, $session_data) + { + if (!$session_id) { + return false; + } + + if (!$session_data) { + return true; + } + + $expire = time() + Session::$expire; + $default_expire = time() + 300; + + if (Session::$exists) { + $fields = ['data' => $session_data, 'expire' => $expire]; + $condition = ["`sid` = ? AND (`data` != ? OR `expire` != ?)", $session_id, $session_data, $expire]; + dba::update('session', $fields, $condition); + } else { + $fields = ['sid' => $session_id, 'expire' => $default_expire, 'data' => $session_data]; + dba::insert('session', $fields); + } + + return true; + } + + public function close() + { + return true; + } + + public function destroy($id) + { + dba::delete('session', ['sid' => $id]); + return true; + } + + public function gc($maxlifetime) + { + dba::delete('session', ["`expire` < ?", time()]); + return true; + } +} diff --git a/src/Core/Session/MemcacheSessionHandler.php b/src/Core/Session/MemcacheSessionHandler.php new file mode 100644 index 0000000000..dce206e64c --- /dev/null +++ b/src/Core/Session/MemcacheSessionHandler.php @@ -0,0 +1,102 @@ + + */ +class MemcacheSessionHandler extends BaseObject implements SessionHandlerInterface +{ + /** + * @var Memcache + */ + private $memcache = null; + + /** + * + * @param Memcache $memcache + */ + public function __construct(Memcache $memcache) + { + $this->memcache = $memcache; + } + + public function open($save_path, $session_name) + { + return true; + } + + public function read($session_id) + { + if (!x($session_id)) { + return ''; + } + + $data = $this->memcache->get(self::getApp()->get_hostname() . ":session:" . $session_id); + if (!is_bool($data)) { + Session::$exists = true; + return $data; + } + logger("no data for session $session_id", LOGGER_TRACE); + return ''; + } + + /** + * @brief Standard PHP session write callback + * + * This callback updates the stored session data and/or the expiration depending + * on the case. Uses the Session::expire for existing session, 5 minutes + * for newly created session. + * + * @param string $session_id Session ID with format: [a-z0-9]{26} + * @param string $session_data Serialized session data + * @return boolean Returns false if parameters are missing, true otherwise + */ + public function write($session_id, $session_data) + { + if (!$session_id) { + return false; + } + + if (!$session_data) { + return true; + } + + $expire = time() + Session::$expire; + + $this->memcache->set( + self::getApp()->get_hostname() . ":session:" . $session_id, + $session_data, + MEMCACHE_COMPRESSED, + $expire + ); + + return true; + } + + public function close() + { + return true; + } + + public function destroy($id) + { + $this->memcache->delete(self::getApp()->get_hostname() . ":session:" . $id); + return true; + } + + public function gc($maxlifetime) + { + return true; + } +} From 55c63949c43597beca2d2ff92b43e518bf765a2d Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 3 Feb 2018 00:43:57 -0500 Subject: [PATCH 2/5] Clean up Core\Cache file - Remove unused use statement - Use explicit types for Memcache object --- src/Core/Cache.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Core/Cache.php b/src/Core/Cache.php index 05ccdd4fec..1f3c9e82f0 100644 --- a/src/Core/Cache.php +++ b/src/Core/Cache.php @@ -5,7 +5,6 @@ namespace Friendica\Core; use Friendica\Core\Config; -use Friendica\Core\PConfig; use Friendica\Database\DBM; use dba; @@ -17,13 +16,13 @@ require_once 'include/dba.php'; class Cache { /** - * @brief Check for memcache and open a connection if configured + * @brief Check for Memcache and open a connection if configured * - * @return object|boolean The memcache object - or "false" if not successful + * @return Memcache|boolean The Memcache object - or "false" if not successful */ public static function memcache() { - if (!function_exists('memcache_connect')) { + if (!class_exists('\Memcache', false)) { return false; } @@ -34,7 +33,7 @@ class Cache $memcache_host = Config::get('system', 'memcache_host', '127.0.0.1'); $memcache_port = Config::get('system', 'memcache_port', 11211); - $memcache = new \Memcache; + $memcache = new \Memcache(); if (!$memcache->connect($memcache_host, $memcache_port)) { return false; From d5753b21aed828648e8edf05c78a5253ecca8436 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 3 Feb 2018 00:46:05 -0500 Subject: [PATCH 3/5] Switch to Core\Session - Remove reference to include/session - Use new Session::init() - Prevent variable re-assignation if they're just empty - Deprecate killme() function - Correct DOMXPath class spelling --- boot.php | 5 +---- index.php | 15 ++++++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/boot.php b/boot.php index 732816d1b9..779a41f400 100644 --- a/boot.php +++ b/boot.php @@ -873,13 +873,10 @@ function get_guid($size = 16, $prefix = "") /** * @brief Used to end the current process, after saving session state. + * @deprecated */ function killme() { - if (!get_app()->is_backend()) { - session_write_close(); - } - exit(); } diff --git a/index.php b/index.php index 2f07fa9af9..af493f2016 100644 --- a/index.php +++ b/index.php @@ -12,10 +12,11 @@ use Friendica\App; use Friendica\BaseObject; use Friendica\Content\Nav; use Friendica\Core\Addon; -use Friendica\Core\System; -use Friendica\Core\Theme; use Friendica\Core\Config; use Friendica\Core\L10n; +use Friendica\Core\Session; +use Friendica\Core\System; +use Friendica\Core\Theme; use Friendica\Core\Worker; use Friendica\Database\DBM; use Friendica\Model\Profile; @@ -77,7 +78,7 @@ if (!$install) { exit(); } - require_once 'include/session.php'; + Session::init(); Addon::loadHooks(); Addon::callHooks('init_1'); @@ -166,16 +167,16 @@ $a->page['htmlhead'] = ''; $a->page['end'] = ''; -if (! x($_SESSION, 'sysmsg')) { +if (x($_SESSION, 'sysmsg') === false) { $_SESSION['sysmsg'] = []; } -if (! x($_SESSION, 'sysmsg_info')) { +if (x($_SESSION, 'sysmsg_info') === false) { $_SESSION['sysmsg_info'] = []; } // Array for informations about last received items -if (! x($_SESSION, 'last_updated')) { +if (x($_SESSION, 'last_updated') === false) { $_SESSION['last_updated'] = []; } /* @@ -474,7 +475,7 @@ if (isset($_GET["mode"]) && (($_GET["mode"] == "raw") || ($_GET["mode"] == "mini /// @TODO one day, kill those error-surpressing @ stuff, or PHP should ban it @$doc->loadHTML($content); - $xpath = new DomXPath($doc); + $xpath = new DOMXPath($doc); $list = $xpath->query("//*[contains(@id,'tread-wrapper-')]"); /* */ From 87b19dd9ac670057dcde2c5bc6aae50d51e2c4d7 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 3 Feb 2018 00:46:39 -0500 Subject: [PATCH 4/5] Remove include/session file --- include/session.php | 134 -------------------------------------------- 1 file changed, 134 deletions(-) delete mode 100644 include/session.php diff --git a/include/session.php b/include/session.php deleted file mode 100644 index 0e8fe836f3..0000000000 --- a/include/session.php +++ /dev/null @@ -1,134 +0,0 @@ -get(get_app()->get_hostname().":session:".$id); - if (!is_bool($data)) { - $session_exists = true; - return $data; - } - logger("no data for session $id", LOGGER_TRACE); - return ''; - } - - $session = dba::selectFirst('session', ['data'], ['sid' => $id]); - if (DBM::is_result($session)) { - $session_exists = true; - return $session['data']; - } else { - logger("no data for session $id", LOGGER_TRACE); - } - - return ''; -} - -/** - * @brief Standard PHP session write callback - * - * This callback updates the DB-stored session data and/or the expiration depending - * on the case. Uses the $session_expire global for existing session, 5 minutes - * for newly created session. - * - * @global bool $session_exists Whether a session with the given id already exists - * @global int $session_expire Session expiration delay in seconds - * @param string $id Session ID with format: [a-z0-9]{26} - * @param string $data Serialized session data - * @return boolean Returns false if parameters are missing, true otherwise - */ -function ref_session_write($id, $data) -{ - global $session_exists, $session_expire; - - if (!$id) { - return false; - } - - if (!$data) { - return true; - } - - $expire = time() + $session_expire; - $default_expire = time() + 300; - - $memcache = Cache::memcache(); - $a = get_app(); - if (is_object($memcache) && is_object($a)) { - $memcache->set($a->get_hostname().":session:".$id, $data, MEMCACHE_COMPRESSED, $expire); - return true; - } - - if ($session_exists) { - $fields = ['data' => $data, 'expire' => $expire]; - $condition = ["`sid` = ? AND (`data` != ? OR `expire` != ?)", $id, $data, $expire]; - dba::update('session', $fields, $condition); - } else { - $fields = ['sid' => $id, 'expire' => $default_expire, 'data' => $data]; - dba::insert('session', $fields); - } - - return true; -} - -function ref_session_close() -{ - return true; -} - -function ref_session_destroy($id) -{ - $memcache = Cache::memcache(); - - if (is_object($memcache)) { - $memcache->delete(get_app()->get_hostname().":session:".$id); - return true; - } - - dba::delete('session', ['sid' => $id]); - return true; -} - -function ref_session_gc() -{ - dba::delete('session', ["`expire` < ?", time()]); - return true; -} - -$gc_probability = 50; - -ini_set('session.gc_probability', $gc_probability); -ini_set('session.use_only_cookies', 1); -ini_set('session.cookie_httponly', 1); - -if (Config::get('system', 'ssl_policy') == SSL_POLICY_FULL) { - ini_set('session.cookie_secure', 1); -} - -if (!Config::get('system', 'disable_database_session')) { - session_set_save_handler( - 'ref_session_open', 'ref_session_close', - 'ref_session_read', 'ref_session_write', - 'ref_session_destroy', 'ref_session_gc' - ); -} From 3df7502dcf8dfe888e54fdf5ac9d4c13ef204bcd Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 3 Feb 2018 08:42:12 -0500 Subject: [PATCH 5/5] Use defaults for setting session variables in index.php --- index.php | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/index.php b/index.php index af493f2016..ef84400990 100644 --- a/index.php +++ b/index.php @@ -166,19 +166,10 @@ if (! x($_SESSION, 'authenticated')) { $a->page['htmlhead'] = ''; $a->page['end'] = ''; +$_SESSION['sysmsg'] = defaults($_SESSION, 'sysmsg' , []); +$_SESSION['sysmsg_info'] = defaults($_SESSION, 'sysmsg_info' , []); +$_SESSION['last_updated'] = defaults($_SESSION, 'last_updated', []); -if (x($_SESSION, 'sysmsg') === false) { - $_SESSION['sysmsg'] = []; -} - -if (x($_SESSION, 'sysmsg_info') === false) { - $_SESSION['sysmsg_info'] = []; -} - -// Array for informations about last received items -if (x($_SESSION, 'last_updated') === false) { - $_SESSION['last_updated'] = []; -} /* * check_config() is responsible for running update scripts. These automatically * update the DB schema whenever we push a new one out. It also checks to see if