[php] session handling wrapper replaceable

This commit is contained in:
nao-pon
2016-02-25 17:39:14 +09:00
parent c0fda8074d
commit 78452f3429
7 changed files with 378 additions and 65 deletions
+67 -29
View File
@@ -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();
}
/**
+1 -1
View File
@@ -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);
+199
View File
@@ -0,0 +1,199 @@
<?php
/**
* elFinder - file manager for web.
* Session Wrapper Class.
*
* @package elfinder
* @author Naoki Sawada
**/
class elFinderSession implements elFinderSessionInterface
{
private $started = false;
protected $keys = array();
protected $base64encode = false;
protected $opts = array(
'base64encode' => 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;
}
}
+59
View File
@@ -0,0 +1,59 @@
<?php
/**
* elFinder - file manager for web.
* Session Wrapper Interface.
*
* @package elfinder
* @author Naoki Sawada
**/
interface elFinderSessionInterface
{
/**
* Session start
*
* @return self
**/
public function start();
/**
* Session write & close
*
* @return self
**/
public function close();
/**
* Get session data
*
* This method must be equipped with an automatic start / close.
*
* @param string $key Target key
* @param mixed $empty Return value of if session target key does not exist
*
* @return mixed
**/
public function get($key, $empty = '');
/**
* Set session data
*
* This method must be equipped with an automatic start / close.
*
* @param string $key Target key
* @param mixed $data Value
*
* @return self
**/
public function set($key, $data);
/**
* Get session data
*
* @param string $key Target key
*
* @return self
**/
public function remove($key);
}
+39 -18
View File
@@ -568,12 +568,18 @@ abstract class elFinderVolumeDriver {
protected $subdirsCache = array();
/**
* Reference of $_SESSION[elFinder::$sessionCacheKey][$this->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;
}
+11 -11
View File
@@ -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 {
</script>';
$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 = '<input id="elf-volumedriver-dropbox-host-btn" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" value="{msg:btnApprove}" type="button" onclick="window.open(\''.$url.'\')">';
$html .= '<script>
$("#'.$options['id'].'").elfinder("instance").trigger("netmount", {protocol: "dropbox", mode: "makebtn"});
@@ -210,10 +210,10 @@ class elFinderVolumeDropbox extends elFinderVolumeDriver {
}
return array('exit' => true, 'body' => $html);
} else {
$this->oauth->setToken($_SESSION['elFinderDropboxAuthTokens']);
unset($_SESSION['elFinderDropboxAuthTokens']);
$this->oauth->setToken($this->session->get('DropboxAuthTokens'));
$this->session->remove('DropboxAuthTokens');
$tokens = $this->oauth->getAccessToken();
$_SESSION['elFinderDropboxTokens'] = array($_GET['uid'], $tokens['token'], $tokens['token_secret']);
$this->session->set('DropboxTokens', array($_GET['uid'], $tokens['token'], $tokens['token_secret']));
$out = array(
'node' => $_GET['node'],
@@ -224,8 +224,8 @@ class elFinderVolumeDropbox extends elFinderVolumeDriver {
return array('exit' => 'callback', 'out' => $out);
}
}
if (isset($_SESSION['elFinderDropboxTokens'])) {
list($options['dropboxUid'], $options['accessToken'], $options['accessTokenSecret']) = $_SESSION['elFinderDropboxTokens'];
if ($sessionToken = $this->session->get('DropboxTokens')) {
list($options['dropboxUid'], $options['accessToken'], $options['accessTokenSecret']) = $sessionToken;
}
unset($options['user'], $options['pass']);
return $options;
@@ -339,7 +339,7 @@ class elFinderVolumeDropbox extends elFinderVolumeDriver {
$this->oauth->setToken($this->options['accessToken'], $this->options['accessTokenSecret']);
$this->dropbox = new Dropbox_API($this->oauth, $this->options['root']);
} catch (Dropbox_Exception $e) {
unset($_SESSION['elFinderDropboxTokens']);
$this->session->remove('DropboxTokens');
return $this->setError('Dropbox error: '.$e->getMessage());
}
@@ -349,7 +349,7 @@ class elFinderVolumeDropbox extends elFinderVolumeDriver {
$res = $this->dropbox->getAccountInfo();
$this->options['dropboxUid'] = $res['uid'];
} catch (Dropbox_Exception $e) {
unset($_SESSION['elFinderDropboxTokens']);
$this->session->remove('DropboxTokens');
return $this->setError('Dropbox error: '.$e->getMessage());
}
}
+2 -6
View File
@@ -225,12 +225,8 @@ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver {
}
// error
// cache to $_SESSION
$sessionStart = $this->sessionRestart();
if ($sessionStart) {
$this->sessionCache['localFileSystemInotify_disable'] = true;
elFinder::sessionWrite();
}
$this->sessionCache['localFileSystemInotify_disable'] = true;
$this->session->set($this->id, $this->sessionCache, true);
return false;
}