diff --git a/composer.json b/composer.json index d4169af995e569c16014e6a95f02b4816150c1f7..9bb13dcfe93e6719852863c1854563d3627574c1 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "php": ">=7.1", "ahand/mobileesp": "dev-master", "cap60552/php-sip2": "1.0.0", + "colinmollenhour/credis": "1.10.1", "endroid/qr-code": "3.5.8", "ghislainf/zf2-whoops": "dev-master#2649cf7caf400409942ddc3f8fe15b89381fc74e", "jasig/phpcas": "1.3.7", diff --git a/config/vufind/config.ini b/config/vufind/config.ini index 93b31fcee24479db1d9ea5cf5cd9af595769075f..256e3d17577fde772b707e4a1df778fa0b809448 100644 --- a/config/vufind/config.ini +++ b/config/vufind/config.ini @@ -151,7 +151,7 @@ nonJavascriptSupportEnabled = false generator = "VuFind 6.0" ; This section allows you to configure the mechanism used for storing user -; sessions. Available types: File, Memcache, Database. +; sessions. Available types: File, Memcache, Database, Redis. ; Some of the settings below only apply to specific session handlers; ; such settings are named with an obvious prefix. Non-prefixed settings ; are global to all handlers. @@ -169,6 +169,15 @@ secure = false ;memcache_host = localhost ;memcache_port = 11211 ;memcache_connection_timeout = 1 +; +; Settings related to Redis-based sessions; default values are listed below +;redis_host = localhost +;redis_port = 6379 +;redis_connection_timeout = 0.5 +;redis_db = 0 +;redis_auth = some_secret_password +;redis_version = 3 +;redis_standalone = true ; This section controls how VuFind creates cookies (to store session IDs, bookbag ; contents, theme/language settings, etc.) diff --git a/module/VuFind/src/VuFind/Session/PluginManager.php b/module/VuFind/src/VuFind/Session/PluginManager.php index 456afc02709d1b3ea83ce37eec083f82aa5ae5be..6927865aa57f51412950e035a6fea0e604784f0d 100644 --- a/module/VuFind/src/VuFind/Session/PluginManager.php +++ b/module/VuFind/src/VuFind/Session/PluginManager.php @@ -52,6 +52,7 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager 'database' => Database::class, 'file' => File::class, 'memcache' => Memcache::class, + 'redis' => Redis::class, // for legacy 1.x compatibility 'filesession' => File::class, 'memcachesession' => Memcache::class, @@ -67,6 +68,7 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager Database::class => InvokableFactory::class, File::class => InvokableFactory::class, Memcache::class => InvokableFactory::class, + Redis::class => InvokableFactory::class, ]; /** @@ -78,6 +80,7 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager Database::class => [SecureDelegatorFactory::class], File::class => [SecureDelegatorFactory::class], Memcache::class => [SecureDelegatorFactory::class], + Redis::class => [SecureDelegatorFactory::class], ]; /** diff --git a/module/VuFind/src/VuFind/Session/Redis.php b/module/VuFind/src/VuFind/Session/Redis.php new file mode 100644 index 0000000000000000000000000000000000000000..3a1f36f37efb6a9751aed4e913abc799b69c7396 --- /dev/null +++ b/module/VuFind/src/VuFind/Session/Redis.php @@ -0,0 +1,138 @@ +<?php +/** + * Redis session handler + * + * Note: Using phpredis extension (see https://github.com/phpredis/phpredis) is + * optional, this class use Credis in standalone mode by default + * + * PHP version 7 + * + * Coypright (C) Moravian Library 2019. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind + * @package Session_Handlers + * @author Veros Kaplan <cpk-dev@mzk.cz> + * @author Josef Moravec <moravec@mzk.cz> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/vufind2:session_handlers Wiki + */ +namespace VuFind\Session; + +/** + * Redis session handler + * + * @category VuFind + * @package Session_Handlers + * @author Veros Kaplan <cpk-dev@mzk.cz> + * @author Josef Moravec <moravec@mzk.cz> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/vufind2:session_handlers Wiki + */ +class Redis extends AbstractBase +{ + /** + * Redis connection + * + * @var \Credis_Client + */ + protected $connection = false; + + /** + * Redis version + * + * @var int + */ + protected $redisVersion = 3; + + /** + * Get connection to Redis + * + * @throws \Exception + * @return \Credis_Client + */ + protected function getConnection() + { + if (!$this->connection) { + // Set defaults if nothing set in config file. + $host = $this->config->redis_host ?? 'localhost'; + $port = $this->config->redis_port ?? 6379; + $timeout = $this->config->redis_connection_timeout ?? 0.5; + $auth = $this->config->redis_auth ?? false; + $redis_db = $this->config->redis_db ?? 0; + $this->redisVersion = int($this->config->redis_version ?? 3); + $standalone = bool($this->config->redis_standalone ?? true); + + // Create Credis client, the connection is established lazily + $this->connection = new \Credis_Client( + $host, $port, $timeout, '', $redis_db, $auth + ); + if ($standalone) { + $this->connection->forceStandalone(); + } + } + return $this->connection; + } + + /** + * Read function must return string value always to make save handler work as + * expected. Return empty string if there is no data to read. + * + * @param string $sess_id The session ID to read + * + * @return string + */ + public function read($sess_id) + { + $session = $this->getConnection()->get("vufind_sessions/{$sess_id}"); + return $session !== false ? $session : ''; + } + + /** + * Write function that is called when session data is to be saved. + * + * @param string $sess_id The current session ID + * @param string $data The session data to write + * + * @return bool + */ + public function write($sess_id, $data) + { + return $this->getConnection()->setex( + "vufind_sessions/{$sess_id}", $this->lifetime, $data + ); + } + + /** + * The destroy handler, this is executed when a session is destroyed with + * session_destroy() and takes the session id as its only parameter. + * + * @param string $sess_id The session ID to destroy + * + * @return void + */ + public function destroy($sess_id) + { + // Perform standard actions required by all session methods: + parent::destroy($sess_id); + + // Perform Redis-specific cleanup + if ($this->redisVersion >= 4) { + $this->getConnection()->unlink("vufind_sessions/{$sess_id}"); + } else { + $this->getConnection()->del("vufind_sessions/{$sess_id}"); + } + } +}