elFinderSession.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. <?php
  2. /**
  3. * elFinder - file manager for web.
  4. * Session Wrapper Class.
  5. *
  6. * @package elfinder
  7. * @author Naoki Sawada
  8. **/
  9. class elFinderSession implements elFinderSessionInterface
  10. {
  11. /**
  12. * A flag of session started
  13. *
  14. * @var boolean
  15. */
  16. protected $started = false;
  17. /**
  18. * To fix PHP bug that duplicate Set-Cookie header to be sent
  19. *
  20. * @var boolean
  21. * @see https://bugs.php.net/bug.php?id=75554
  22. */
  23. protected $fixCookieRegist = false;
  24. /**
  25. * Array of session keys of this instance
  26. *
  27. * @var array
  28. */
  29. protected $keys = array();
  30. /**
  31. * Is enabled base64encode
  32. *
  33. * @var boolean
  34. */
  35. protected $base64encode = false;
  36. /**
  37. * Default options array
  38. *
  39. * @var array
  40. */
  41. protected $opts = array(
  42. 'base64encode' => false,
  43. 'keys' => array(
  44. 'default' => 'elFinderCaches',
  45. 'netvolume' => 'elFinderNetVolumes'
  46. ),
  47. 'cookieParams' => array()
  48. );
  49. /**
  50. * Constractor
  51. *
  52. * @param array $opts The options
  53. *
  54. * @return self Instanse of this class
  55. */
  56. public function __construct($opts)
  57. {
  58. $this->opts = array_merge($this->opts, $opts);
  59. $this->base64encode = !empty($this->opts['base64encode']);
  60. $this->keys = $this->opts['keys'];
  61. if (function_exists('apache_get_version') || $this->opts['cookieParams']) {
  62. $this->fixCookieRegist = true;
  63. }
  64. return $this;
  65. }
  66. /**
  67. * {@inheritdoc}
  68. */
  69. public function get($key, $empty = null)
  70. {
  71. $closed = false;
  72. if (!$this->started) {
  73. $closed = true;
  74. $this->start();
  75. }
  76. $data = null;
  77. if ($this->started) {
  78. $session =& $this->getSessionRef($key);
  79. $data = $session;
  80. if ($data && $this->base64encode) {
  81. $data = $this->decodeData($data);
  82. }
  83. }
  84. $checkFn = null;
  85. if (!is_null($empty)) {
  86. if (is_string($empty)) {
  87. $checkFn = 'is_string';
  88. } elseif (is_array($empty)) {
  89. $checkFn = 'is_array';
  90. } elseif (is_object($empty)) {
  91. $checkFn = 'is_object';
  92. } elseif (is_float($empty)) {
  93. $checkFn = 'is_float';
  94. } elseif (is_int($empty)) {
  95. $checkFn = 'is_int';
  96. }
  97. }
  98. if (is_null($data) || ($checkFn && !$checkFn($data))) {
  99. $session = $data = $empty;
  100. }
  101. if ($closed) {
  102. $this->close();
  103. }
  104. return $data;
  105. }
  106. /**
  107. * {@inheritdoc}
  108. */
  109. public function start()
  110. {
  111. set_error_handler(array($this, 'session_start_error'), E_NOTICE | E_WARNING);
  112. // apache2 SAPI has a bug of session cookie register
  113. // see https://bugs.php.net/bug.php?id=75554
  114. // see https://github.com/php/php-src/pull/3231
  115. if ($this->fixCookieRegist === true) {
  116. if ((int)ini_get('session.use_cookies') === 1) {
  117. if (ini_set('session.use_cookies', 0) === false) {
  118. $this->fixCookieRegist === false;
  119. }
  120. }
  121. }
  122. if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
  123. if (session_status() !== PHP_SESSION_ACTIVE) {
  124. session_start();
  125. }
  126. } else {
  127. session_start();
  128. }
  129. $this->started = session_id() ? true : false;
  130. restore_error_handler();
  131. return $this;
  132. }
  133. /**
  134. * Get variable reference of $_SESSION
  135. *
  136. * @param string $key key of $_SESSION array
  137. *
  138. * @return mixed|null
  139. */
  140. protected function & getSessionRef($key)
  141. {
  142. $session = null;
  143. if ($this->started) {
  144. list($cat, $name) = array_pad(explode('.', $key, 2), 2, null);
  145. if (is_null($name)) {
  146. if (!isset($this->keys[$cat])) {
  147. $name = $cat;
  148. $cat = 'default';
  149. }
  150. }
  151. if (isset($this->keys[$cat])) {
  152. $cat = $this->keys[$cat];
  153. } else {
  154. $name = $cat . '.' . $name;
  155. $cat = $this->keys['default'];
  156. }
  157. if (is_null($name)) {
  158. if (!isset($_SESSION[$cat])) {
  159. $_SESSION[$cat] = null;
  160. }
  161. $session =& $_SESSION[$cat];
  162. } else {
  163. if (!isset($_SESSION[$cat]) || !is_array($_SESSION[$cat])) {
  164. $_SESSION[$cat] = array();
  165. }
  166. if (!isset($_SESSION[$cat][$name])) {
  167. $_SESSION[$cat][$name] = null;
  168. }
  169. $session =& $_SESSION[$cat][$name];
  170. }
  171. }
  172. return $session;
  173. }
  174. /**
  175. * base64 decode of session val
  176. *
  177. * @param $data
  178. *
  179. * @return bool|mixed|string|null
  180. */
  181. protected function decodeData($data)
  182. {
  183. if ($this->base64encode) {
  184. if (is_string($data)) {
  185. if (($data = base64_decode($data)) !== false) {
  186. $data = unserialize($data);
  187. } else {
  188. $data = null;
  189. }
  190. } else {
  191. $data = null;
  192. }
  193. }
  194. return $data;
  195. }
  196. /**
  197. * {@inheritdoc}
  198. */
  199. public function close()
  200. {
  201. if ($this->started) {
  202. if ($this->fixCookieRegist === true) {
  203. // regist cookie only once for apache2 SAPI
  204. $cParm = session_get_cookie_params();
  205. if ($this->opts['cookieParams'] && is_array($this->opts['cookieParams'])) {
  206. $cParm = array_merge($cParm, $this->opts['cookieParams']);
  207. }
  208. if (version_compare(PHP_VERSION, '7.3', '<')) {
  209. setcookie(session_name(), session_id(), 0, $cParm['path'] . (!empty($cParm['SameSite'])? '; SameSite=' . $cParm['SameSite'] : ''), $cParm['domain'], $cParm['secure'], $cParm['httponly']);
  210. } else {
  211. $allows = array('expires' => true, 'path' => true, 'domain' => true, 'secure' => true, 'httponly' => true, 'samesite' => true);
  212. foreach(array_keys($cParm) as $_k) {
  213. if (!isset($allows[$_k])) {
  214. unset($cParm[$_k]);
  215. }
  216. }
  217. setcookie(session_name(), session_id(), $cParm);
  218. }
  219. $this->fixCookieRegist = false;
  220. }
  221. session_write_close();
  222. }
  223. $this->started = false;
  224. return $this;
  225. }
  226. /**
  227. * {@inheritdoc}
  228. */
  229. public function set($key, $data)
  230. {
  231. $closed = false;
  232. if (!$this->started) {
  233. $closed = true;
  234. $this->start();
  235. }
  236. $session =& $this->getSessionRef($key);
  237. if ($this->base64encode) {
  238. $data = $this->encodeData($data);
  239. }
  240. $session = $data;
  241. if ($closed) {
  242. $this->close();
  243. }
  244. return $this;
  245. }
  246. /**
  247. * base64 encode for session val
  248. *
  249. * @param $data
  250. *
  251. * @return string
  252. */
  253. protected function encodeData($data)
  254. {
  255. if ($this->base64encode) {
  256. $data = base64_encode(serialize($data));
  257. }
  258. return $data;
  259. }
  260. /**
  261. * {@inheritdoc}
  262. */
  263. public function remove($key)
  264. {
  265. $closed = false;
  266. if (!$this->started) {
  267. $closed = true;
  268. $this->start();
  269. }
  270. list($cat, $name) = array_pad(explode('.', $key, 2), 2, null);
  271. if (is_null($name)) {
  272. if (!isset($this->keys[$cat])) {
  273. $name = $cat;
  274. $cat = 'default';
  275. }
  276. }
  277. if (isset($this->keys[$cat])) {
  278. $cat = $this->keys[$cat];
  279. } else {
  280. $name = $cat . '.' . $name;
  281. $cat = $this->keys['default'];
  282. }
  283. if (is_null($name)) {
  284. unset($_SESSION[$cat]);
  285. } else {
  286. if (isset($_SESSION[$cat]) && is_array($_SESSION[$cat])) {
  287. unset($_SESSION[$cat][$name]);
  288. }
  289. }
  290. if ($closed) {
  291. $this->close();
  292. }
  293. return $this;
  294. }
  295. /**
  296. * sessioin error handler (Only for suppression of error at session start)
  297. *
  298. * @param $errno
  299. * @param $errstr
  300. */
  301. protected function session_start_error($errno, $errstr)
  302. {
  303. }
  304. }