From 78452f3429a64db43e068146bf91c030bab2ca5d Mon Sep 17 00:00:00 2001 From: nao-pon Date: Thu, 25 Feb 2016 17:39:14 +0900 Subject: [PATCH] [php] session handling wrapper replaceable --- php/elFinder.class.php | 96 +++++++--- php/elFinderConnector.class.php | 2 +- php/elFinderSession.php | 199 ++++++++++++++++++++ php/elFinderSessionInterface.php | 59 ++++++ php/elFinderVolumeDriver.class.php | 57 ++++-- php/elFinderVolumeDropbox.class.php | 22 +-- php/elFinderVolumeLocalFileSystem.class.php | 8 +- 7 files changed, 378 insertions(+), 65 deletions(-) create mode 100644 php/elFinderSession.php create mode 100644 php/elFinderSessionInterface.php diff --git a/php/elFinder.class.php b/php/elFinder.class.php index 14f6e4ab7..72c3e6f73 100644 --- a/php/elFinder.class.php +++ b/php/elFinder.class.php @@ -39,9 +39,17 @@ class elFinder { */ public static $locale = ''; + /** + * elFinder session wrapper object + * + * @var elFinderSessionInterface + */ + protected $session; + /** * elFinder global sessionCacheKey * + * @deprecated * @var string */ public static $sessionCacheKey = ''; @@ -49,6 +57,7 @@ class elFinder { /** * Is session closed * + * @deprecated * @var bool */ private static $sessionClosed = false; @@ -72,6 +81,8 @@ class elFinder { /** * Session key of net mount volumes + * + * @deprecated * @var string */ protected $netVolumesSessionKey = ''; @@ -289,8 +300,28 @@ class elFinder { * @author Dmitry (dio) Levashov **/ public function __construct($opts) { + if (! interface_exists('elFinderSessionAbstarct')) { + include_once dirname(__FILE__).'/elFinderSessionInterface.php'; + } + + // session handler + if (!empty($opts['session']) && $opts['session'] instanceof elFinderSessionInterface) { + $this->session = $opts['session']; + } else { + $sessionOpts = array( + 'base64encode' => !empty($opts['base64encodeSessionData']), + 'keys' => array( + 'default' => !empty($opts['sessionCacheKey']) ? $opts['sessionCacheKey'] : 'elFinderCaches', + 'netvolume' => !empty($opts['netVolumesSessionKey'])? $opts['netVolumesSessionKey'] : 'elFinderNetVolumes' + ) + ); + if (! class_exists('elFinderSession')) { + include_once dirname(__FILE__) . '/elFinderSession.php'; + } + $this->session = new elFinderSession($sessionOpts); + } // try session start | restart - @session_start(); + $this->session->start(); $sessionUseCmds = array(); if (isset($opts['sessionUseCmds']) && is_array($opts['sessionUseCmds'])) { @@ -308,23 +339,22 @@ class elFinder { $this->sessionUseCmds = array_flip($sessionUseCmds); $this->timeout = (isset($opts['timeout']) ? $opts['timeout'] : 0); $this->uploadTempPath = (isset($opts['uploadTempPath']) ? $opts['uploadTempPath'] : ''); - $this->netVolumesSessionKey = !empty($opts['netVolumesSessionKey'])? $opts['netVolumesSessionKey'] : 'elFinderNetVolumes'; $this->callbackWindowURL = (isset($opts['callbackWindowURL']) ? $opts['callbackWindowURL'] : ''); - self::$sessionCacheKey = !empty($opts['sessionCacheKey']) ? $opts['sessionCacheKey'] : 'elFinderCaches'; elFinder::$commonTempPath = (isset($opts['commonTempPath']) ? $opts['commonTempPath'] : './.tmp'); if (!is_writable(elFinder::$commonTempPath)) { elFinder::$commonTempPath = ''; } $this->maxArcFilesSize = isset($opts['maxArcFilesSize'])? intval($opts['maxArcFilesSize']) : 0; + // deprecated settings + $this->netVolumesSessionKey = !empty($opts['netVolumesSessionKey'])? $opts['netVolumesSessionKey'] : 'elFinderNetVolumes'; + self::$sessionCacheKey = !empty($opts['sessionCacheKey']) ? $opts['sessionCacheKey'] : 'elFinderCaches'; + // check session cache $_optsMD5 = md5(json_encode($opts['roots'])); - if (! isset($_SESSION[self::$sessionCacheKey]) || $_SESSION[self::$sessionCacheKey]['_optsMD5'] !== $_optsMD5) { - $_SESSION[self::$sessionCacheKey] = array( - '_optsMD5' => $_optsMD5 - ); + if ($this->session->get('_optsMD5') !== $_optsMD5) { + $this->session->set('_optsMD5', $_optsMD5); } - self::$base64encodeSessionData = !empty($opts['base64encodeSessionData']); // setlocale and global locale regists to elFinder::locale self::$locale = !empty($opts['locale']) ? $opts['locale'] : 'en_US.UTF-8'; @@ -385,6 +415,8 @@ class elFinder { if ($this->maxArcFilesSize && (empty($o['maxArcFilesSize']) || $this->maxArcFilesSize < $o['maxArcFilesSize'])) { $o['maxArcFilesSize'] = $this->maxArcFilesSize; } + // pass session handler + $volume->setSession($this->session); if ($volume->mount($o)) { // unique volume id (ends on "_") - used as prefix to files hash $id = $volume->id(); @@ -410,6 +442,15 @@ class elFinder { $this->loaded = !empty($this->default); } + /** + * Return elFinder session wrapper instance + * + * @return object elFinderSessionInterface + **/ + public function getSession() { + return $this->session; + } + /** * Return true if fm init correctly * @@ -527,17 +568,17 @@ class elFinder { private function session_expires() { - if (!isset($_SESSION[self::$sessionCacheKey . ':LAST_ACTIVITY'])) { - $_SESSION[self::$sessionCacheKey . ':LAST_ACTIVITY'] = time(); + if (! $last = $this->session->get(':LAST_ACTIVITY')) { + $this->session->set(':LAST_ACTIVITY', time()); return false; } - if ( ($this->timeout > 0) && (time() - $_SESSION[self::$sessionCacheKey . ':LAST_ACTIVITY'] > $this->timeout) ) { + if ( ($this->timeout > 0) && (time() - $last > $this->timeout) ) { return true; } - $_SESSION[self::$sessionCacheKey . ':LAST_ACTIVITY'] = time(); - return false; + $this->session->set(':LAST_ACTIVITY', time()); + return false; } /** @@ -578,8 +619,9 @@ class elFinder { } // unlock session data for multiple access - if ($this->sessionCloseEarlier && $args['sessionCloseEarlier'] && session_id()) { - session_write_close(); + if ($this->sessionCloseEarlier && $args['sessionCloseEarlier']) { + $this->session->close(); + // deprecated property elFinder::$sessionClosed = true; } @@ -682,10 +724,8 @@ class elFinder { * @author Dmitry (dio) Levashov */ protected function getNetVolumes() { - if (isset($_SESSION[$this->netVolumesSessionKey])) { - if ($data = elFinder::sessionDataDecode($_SESSION[$this->netVolumesSessionKey], 'array')) { - return $data; - } + if ($data = $this->session->get('netvolume', array())) { + return $data; } return array(); } @@ -698,10 +738,7 @@ class elFinder { * @author Dmitry (dio) Levashov */ protected function saveNetVolumes($volumes) { - // try session restart - @session_start(); - $_SESSION[$this->netVolumesSessionKey] = elFinder::sessionDataEncode($volumes); - elFinder::sessionWrite(); + $this->session->set('netvolume', $volumes); } /** @@ -765,9 +802,6 @@ class elFinder { } protected function netmount($args) { - // try session restart - @session_start(); - $options = array(); $protocol = $args['protocol']; @@ -814,6 +848,9 @@ class elFinder { $volume = new $class(); + // pass session handler + $volume->setSession($this->session); + if (method_exists($volume, 'netmountPrepare')) { $options = $volume->netmountPrepare($options); if (isset($options['exit'])) { @@ -2647,6 +2684,7 @@ class elFinder { /** * serialize and base64_encode of session data (If needed) * + * @deprecated * @param mixed $var target variable * @author Naoki Sawada */ @@ -2660,6 +2698,7 @@ class elFinder { /** * base64_decode and unserialize of session data (If needed) * + * @deprecated * @param mixed $var target variable * @param bool $checkIs data type for check (array|string|object|int) * @author Naoki Sawada @@ -2697,12 +2736,11 @@ class elFinder { /** * Call session_write_close() if session is restarted * + * @deprecated * @return void */ public static function sessionWrite() { - if (elFinder::$sessionClosed) { - session_write_close(); - } + $this->session->close(); } /** diff --git a/php/elFinderConnector.class.php b/php/elFinderConnector.class.php index 14b4da246..b30c41d83 100644 --- a/php/elFinderConnector.class.php +++ b/php/elFinderConnector.class.php @@ -184,7 +184,7 @@ class elFinderConnector { } // unlock session data for multiple access - session_id() && session_write_close(); + $this->elFinder->getSession()->close(); // client disconnect should abort ignore_user_abort(false); diff --git a/php/elFinderSession.php b/php/elFinderSession.php new file mode 100644 index 000000000..63934dd3f --- /dev/null +++ b/php/elFinderSession.php @@ -0,0 +1,199 @@ + false, + 'keys' => array( + 'default' => 'elFinderCaches', + 'netvolume' => 'elFinderNetVolumes' + ) + ); + + public function __construct($opts) + { + $this->opts = array_merge($this->opts, $opts); + $this->base64encode = !empty($this->opts['base64encode']); + $this->keys = $this->opts['keys']; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function start() + { + @session_start(); + $this->started = session_id()? true : false; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function close() + { + if ($this->started) { + session_write_close(); + } + $this->started = false; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function get($key, $empty = null) + { + $closed = false; + if (! $this->started) { + $closed = true; + $this->start(); + } + + $data = null; + + if ($this->started) { + $session =& $this->getSessionRef($key); + $data = $session; + if ($data && $this->base64encode) { + $data = $this->decodeData($data); + } + } + + $checkFn = null; + if (! is_null($empty)) { + if (is_string($empty)) { + $checkFn = 'is_string'; + } elseif (is_array($empty)) { + $checkFn = 'is_array'; + } elseif (is_object($empty)) { + $checkFn = 'is_object'; + } elseif (is_float($empty)) { + $checkFn = 'is_float'; + } elseif (is_int($empty)) { + $checkFn = 'is_int'; + } + } + + if (is_null($data) || ($checkFn && ! $checkFn($data))) { + $session = $data = $empty; + } + + if ($closed) { + $this->close(); + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function set($key, $data) + { + $closed = false; + if (! $this->started) { + $closed = true; + $this->start(); + } + $session =& $this->getSessionRef($key); + if ($this->base64encode) { + $data = $this->encodeData($data); + } + $session = $data; + + if ($closed) { + $this->close(); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function remove($key) + { + $session =& $this->getSessionRef($key); + unset($session); + + return $this; + } + + protected function & getSessionRef($key) + { + $session = null; + if ($this->started) { + list($cat, $name) = array_pad(explode('.', $key, 2), 2, null); + if (is_null($name)) { + if (! isset($this->keys[$cat])) { + $name = $cat; + $cat = 'default'; + } + } + if (isset($this->keys[$cat])) { + $cat = $this->keys[$cat]; + } else { + $name = $cat . '.' . $name; + $cat = $this->keys['default']; + } + if (is_null($name)) { + if (! isset($_SESSION[$cat])) { + $_SESSION[$cat] = null; + } + $session =& $_SESSION[$cat]; + } else { + if (! isset($_SESSION[$cat]) || ! is_array($_SESSION[$cat])) { + $_SESSION[$cat] = array(); + } + if (! isset($_SESSION[$cat][$name])) { + $_SESSION[$cat][$name] = null; + } + $session =& $_SESSION[$cat][$name]; + } + } + return $session; + } + + protected function encodeData($data) + { + if ($this->base64encode) { + $data = base64_encode(serialize($data)); + } + return $data; + } + + protected function decodeData($data) + { + if ($this->base64encode) { + if (is_string($data)) { + if (($data = base64_decode($data)) !== false) { + $data = @unserialize($data); + } else { + $data = null; + } + } else { + $data = null; + } + } + return $data; + } +} diff --git a/php/elFinderSessionInterface.php b/php/elFinderSessionInterface.php new file mode 100644 index 000000000..936848c7a --- /dev/null +++ b/php/elFinderSessionInterface.php @@ -0,0 +1,59 @@ +id] + * This volume session cache * * @var array */ protected $sessionCache; + /** + * elFinder session wrapper object + * + * @var elFinderSessionInterface + */ + protected $session; /** * Search start time @@ -658,14 +664,14 @@ abstract class elFinderVolumeDriver { } } + /** + * @deprecated + */ protected function sessionRestart() { - $start = @session_start(); - if (!isset($_SESSION[elFinder::$sessionCacheKey])) { - $_SESSION[elFinder::$sessionCacheKey] = array(); - } - $this->sessionCache = &$_SESSION[elFinder::$sessionCacheKey][$this->id]; - return $start; + $this->sessionCache = $this->session->start()->get($this->id, array()); + return true; } + /*********************************************************************/ /* PUBLIC API */ /*********************************************************************/ @@ -689,7 +695,16 @@ abstract class elFinderVolumeDriver { public function id() { return $this->id; } - + + /** + * Assign elFinder session wrapper object + * + * @param $session elFinderSessionInterface + */ + public function setSession($session) { + $this->session = $session; + } + /** * Return debug info for client * @@ -780,7 +795,14 @@ abstract class elFinderVolumeDriver { **/ public function mount(array $opts) { if (!isset($opts['path']) || $opts['path'] === '') { - return $this->setError('Path undefined.');; + return $this->setError('Path undefined.'); + } + + if (! $this->session) { + return $this->setError('Session wrapper dose not set. Need to `$volume->setSession(elFinderSessionInterface);` before mount.'); + } + if (! ($this->session instanceof elFinderSessionInterface)) { + return $this->setError('Session wrapper instance must be "elFinderSessionInterface".'); } $this->options = array_merge($this->options, $opts); @@ -799,10 +821,10 @@ abstract class elFinderVolumeDriver { $argInit = !empty($this->ARGS['init']); // session cache - if ($argInit || ! isset($_SESSION[elFinder::$sessionCacheKey][$this->id])) { - $_SESSION[elFinder::$sessionCacheKey][$this->id] = array(); + if ($argInit) { + $this->session->set($this->id, array()); } - $this->sessionCache = &$_SESSION[elFinder::$sessionCacheKey][$this->id]; + $this->sessionCache = $this->session->get($this->id, array()); // default file attribute $this->defaults = array( @@ -3039,7 +3061,7 @@ abstract class elFinderVolumeDriver { if (! $this->isMyReload()) { // need $path as key for netmount/netunmount if (isset($this->sessionCache['rootstat'][$rootKey])) { - if ($ret = elFinder::sessionDataDecode($this->sessionCache['rootstat'][$rootKey], 'array')) { + if ($ret = $this->sessionCache['rootstat'][$rootKey]) { return $ret; } } @@ -3049,9 +3071,8 @@ abstract class elFinderVolumeDriver { ? $this->cache[$path] : $this->updateCache($path, $this->convEncOut($this->_stat($this->convEncIn($path)))); if ($is_root) { - $this->sessionRestart(); - $this->sessionCache['rootstat'][$rootKey] = elFinder::sessionDataEncode($ret); - elFinder::sessionWrite(); + $this->sessionCache['rootstat'][$rootKey] = $ret; + $this->session->set($this->id, $this->sessionCache); } return $ret; } @@ -3257,9 +3278,8 @@ abstract class elFinderVolumeDriver { **/ protected function clearcache() { $this->cache = $this->dirsCache = array(); - $this->sessionRestart(); unset($this->sessionCache['rootstat'][md5($this->root)]); - elFinder::sessionWrite(); + $this->session->set($this->id, $this->sessionCache); } /** @@ -4673,6 +4693,7 @@ abstract class elFinderVolumeDriver { } $this->sessionCache[$sessionKey] = $arcs; + $this->session->set($this->id, $this->sessionCache); return $arcs; } diff --git a/php/elFinderVolumeDropbox.class.php b/php/elFinderVolumeDropbox.class.php index ae99a1eb0..1c7741bcf 100644 --- a/php/elFinderVolumeDropbox.class.php +++ b/php/elFinderVolumeDropbox.class.php @@ -164,10 +164,10 @@ class elFinderVolumeDropbox extends elFinderVolumeDriver { if ($options['pass'] === 'init') { $html = ''; - if (isset($_SESSION['elFinderDropboxTokens'])) { + if ($sessionToken = $this->session->get('DropboxTokens')) { // token check try { - list(, $accessToken, $accessTokenSecret) = $_SESSION['elFinderDropboxTokens']; + list(, $accessToken, $accessTokenSecret) = $sessionToken; $this->oauth->setToken($accessToken, $accessTokenSecret); $this->dropbox = new Dropbox_API($this->oauth, $this->options['root']); $this->dropbox->getAccountInfo(); @@ -176,7 +176,7 @@ class elFinderVolumeDropbox extends elFinderVolumeDriver { '; $html = $script; } catch (Dropbox_Exception $e) { - unset($_SESSION['elFinderDropboxTokens']); + $this->session->remove('DropboxTokens'); } } if (! $html) { @@ -202,7 +202,7 @@ class elFinderVolumeDropbox extends elFinderVolumeDriver { return array('exit' => true, 'body' => '{msg:errAccess}'); } - $_SESSION['elFinderDropboxAuthTokens'] = $tokens; + $this->session->set('DropboxAuthTokens', $tokens); $html = ''; $html .= '