session.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. /*
  3. Copyright (c) 2009-2017 F3::Factory/Bong Cosca, All rights reserved.
  4. This file is part of the Fat-Free Framework (http://fatfreeframework.com).
  5. This is free software: you can redistribute it and/or modify it under the
  6. terms of the GNU General Public License as published by the Free Software
  7. Foundation, either version 3 of the License, or later.
  8. Fat-Free Framework is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with Fat-Free Framework. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. //! Cache-based session handler
  16. class Session {
  17. protected
  18. //! Session ID
  19. $sid,
  20. //! Anti-CSRF token
  21. $_csrf,
  22. //! User agent
  23. $_agent,
  24. //! IP,
  25. $_ip,
  26. //! Suspect callback
  27. $onsuspect,
  28. //! Cache instance
  29. $_cache;
  30. /**
  31. * Open session
  32. * @return TRUE
  33. * @param $path string
  34. * @param $name string
  35. **/
  36. function open($path,$name) {
  37. return TRUE;
  38. }
  39. /**
  40. * Close session
  41. * @return TRUE
  42. **/
  43. function close() {
  44. $this->sid=NULL;
  45. return TRUE;
  46. }
  47. /**
  48. * Return session data in serialized format
  49. * @return string
  50. * @param $id string
  51. **/
  52. function read($id) {
  53. $this->sid=$id;
  54. if (!$data=$this->_cache->get($id.'.@'))
  55. return '';
  56. if ($data['ip']!=$this->_ip || $data['agent']!=$this->_agent) {
  57. $fw=Base::instance();
  58. if (!isset($this->onsuspect) ||
  59. $fw->call($this->onsuspect,[$this,$id])===FALSE) {
  60. //NB: `session_destroy` can't be called at that stage (`session_start` not completed)
  61. $this->destroy($id);
  62. $this->close();
  63. unset($fw->{'COOKIE.'.session_name()});
  64. $fw->error(403);
  65. }
  66. }
  67. return $data['data'];
  68. }
  69. /**
  70. * Write session data
  71. * @return TRUE
  72. * @param $id string
  73. * @param $data string
  74. **/
  75. function write($id,$data) {
  76. $fw=Base::instance();
  77. $jar=$fw->JAR;
  78. $this->_cache->set($id.'.@',
  79. [
  80. 'data'=>$data,
  81. 'ip'=>$this->_ip,
  82. 'agent'=>$this->_agent,
  83. 'stamp'=>time()
  84. ],
  85. $jar['expire']
  86. );
  87. return TRUE;
  88. }
  89. /**
  90. * Destroy session
  91. * @return TRUE
  92. * @param $id string
  93. **/
  94. function destroy($id) {
  95. $this->_cache->clear($id.'.@');
  96. return TRUE;
  97. }
  98. /**
  99. * Garbage collector
  100. * @return TRUE
  101. * @param $max int
  102. **/
  103. function cleanup($max) {
  104. $this->_cache->reset('.@',$max);
  105. return TRUE;
  106. }
  107. /**
  108. * Return session id (if session has started)
  109. * @return string|NULL
  110. **/
  111. function sid() {
  112. return $this->sid;
  113. }
  114. /**
  115. * Return anti-CSRF token
  116. * @return string
  117. **/
  118. function csrf() {
  119. return $this->_csrf;
  120. }
  121. /**
  122. * Return IP address
  123. * @return string
  124. **/
  125. function ip() {
  126. return $this->_ip;
  127. }
  128. /**
  129. * Return Unix timestamp
  130. * @return string|FALSE
  131. **/
  132. function stamp() {
  133. if (!$this->sid)
  134. session_start();
  135. return $this->_cache->exists($this->sid.'.@',$data)?
  136. $data['stamp']:FALSE;
  137. }
  138. /**
  139. * Return HTTP user agent
  140. * @return string
  141. **/
  142. function agent() {
  143. return $this->_agent;
  144. }
  145. /**
  146. * Instantiate class
  147. * @param $onsuspect callback
  148. * @param $key string
  149. **/
  150. function __construct($onsuspect=NULL,$key=NULL,$cache=null) {
  151. $this->onsuspect=$onsuspect;
  152. $this->_cache=$cache?:Cache::instance();
  153. session_set_save_handler(
  154. [$this,'open'],
  155. [$this,'close'],
  156. [$this,'read'],
  157. [$this,'write'],
  158. [$this,'destroy'],
  159. [$this,'cleanup']
  160. );
  161. register_shutdown_function('session_commit');
  162. $fw=\Base::instance();
  163. $headers=$fw->HEADERS;
  164. $this->_csrf=$fw->hash($fw->SEED.
  165. extension_loaded('openssl')?
  166. implode(unpack('L',openssl_random_pseudo_bytes(4))):
  167. mt_rand()
  168. );
  169. if ($key)
  170. $fw->$key=$this->_csrf;
  171. $this->_agent=isset($headers['User-Agent'])?$headers['User-Agent']:'';
  172. $this->_ip=$fw->IP;
  173. }
  174. }