PageRenderTime 50ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/utilities/WaxSession.php

https://gitlab.com/sheldonels/phpwax
PHP | 163 lines | 115 code | 28 blank | 20 comment | 26 complexity | 10276e50a16ea19f066ef33c3a31e3a0 MD5 | raw file
  1. <?php
  2. //if sessions are used, add http headers defining the cookie use. this is above the class definition since it only needs to be sent once for all sessions, not once per session.
  3. if(class_exists("WaxEvent", false)){
  4. WaxEvent::add("wax.post_render", function(){
  5. $response = WaxEvent::data();
  6. $response->add_header('P3P', ' CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"');
  7. //garbage collection
  8. $cmd = "php ".__FILE__." ";
  9. $run_garbage_collection = true;
  10. foreach(WaxSession::$garbage_collection_folders as $dir){
  11. if(($stats = stat($dir."/garbage.collect.lock")) && time() < $stats[9]){
  12. $run_garbage_collection = false;
  13. break;
  14. }
  15. $cmd .= $dir." ";
  16. }
  17. if($run_garbage_collection) exec($cmd." > /dev/null &");
  18. });
  19. }
  20. class WaxSession {
  21. public static
  22. $data = array(),
  23. $updated = array(),
  24. $garbage_collection_folders = array(),
  25. $garbage_collection_timeout = 1440;
  26. public
  27. $bots = array('googlebot','ask jeeves','slurp','fast','scooter','zyborg','msnbot'),
  28. $file_storage_prefix = SESSION_DIR,
  29. $id = false,
  30. $lifetime = 0,
  31. $name = "wxsession";
  32. function __construct($data = array()){
  33. if($this->is_bot()) return; // Don't start a session if this is a search engine
  34. //set passed in data
  35. foreach($data as $k => $v) $this->$k = $v;
  36. //get id from request or generate an id
  37. if(($this->id = $_COOKIE[$this->name]) || ($this->id = $_REQUEST[$this->name])){
  38. //initialize data from cross-request storage
  39. if(!static::$data[$this->name] && (is_readable($storage = $this->file_storage())) && ($stats = stat($storage))){
  40. if(time() < $stats[9]) static::$data[$this->name] = unserialize(file_get_contents($this->file_storage()));
  41. else unlink($this->file_storage());
  42. }
  43. }else $this->id = $this->safe_encrypt($_SERVER['REMOTE_ADDR'].microtime().mt_rand());
  44. //add folder to collection of folders to be garbage collected
  45. static::$garbage_collection_folders[] = $this->file_storage_dir();
  46. //set cookie on render to propogate session
  47. $session = $this;
  48. WaxEvent::add("wax.response.execute", function() use ($session) {
  49. $response = WaxEvent::data();
  50. $response->set_cookie($session->name, $session->id, $session->lifetime?(time() + $session->lifetime):false);
  51. });
  52. $session_save = $this;
  53. WaxEvent::add("wax.response.execute", function() use($session_save){
  54. $session_save->save_session();
  55. });
  56. }
  57. function save_session(){
  58. //create folder to store sessions
  59. if(!is_dir($this->file_storage_dir())){
  60. if(!mkdir($this->file_storage_dir(), 0750, true)) throw new WaxException("Session not writable - ".$this->file_storage_dir());
  61. }
  62. if(static::$updated[$this->name]){
  63. if(file_put_contents($this->file_storage(), serialize(static::$data[$this->name])) === false) throw new WaxException("Session not writable - ".$this->file_storage_dir());
  64. }
  65. touch($this->file_storage(), time() + ($this->lifetime?$this->lifetime:(WaxSession::$garbage_collection_timeout * 10)));
  66. }
  67. public function get($key){
  68. if(!$key) return static::$data[$this->name];
  69. else return static::$data[$this->name][$key];
  70. }
  71. public function __get($key) { return $this->get($key); }
  72. public function set($key, $value) { static::$updated[$this->name] = true; static::$data[$this->name][$key] = $value; }
  73. public function __set($key, $value) { return $this->set($key, $value); }
  74. public function unset_var($key) { static::$updated[$this->name] = true; unset(static::$data[$this->name][$key]); }
  75. public function get_hash() { return $this->id; }
  76. public function isset_var($key) { return isset(static::$data[$this->name][$key]); }
  77. public function add_message($string) { static::$updated[$this->name] = true; static::$data[$this->name]['user_messages'][] = $string; }
  78. public function add_error($string) { static::$updated[$this->name] = true; static::$data[$this->name]['user_errors'][] = $string; }
  79. public function unset_session() { static::$updated[$this->name] = true; unset(static::$data[$this->name]); }
  80. public function destroy_session() { $this->unset_session(); }
  81. public function is_bot() {
  82. foreach($this->bots as $bot)
  83. if(stristr($_SERVER['HTTP_USER_AGENT'], $bot))
  84. return true;
  85. }
  86. public function file_storage_dir(){ return "$this->file_storage_prefix$this->name"; }
  87. public function file_storage(){ return $this->file_storage_dir()."/".$this->id; }
  88. protected function safe_encrypt($password, $iterations = 8) {
  89. $itoa64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';
  90. $random = substr(md5(mt_rand()), 0, 16);
  91. if($iterations < 4 || $iterations > 31) $iterations = 8;
  92. $salt = '$2a$';
  93. $salt .= chr(ord('0') + $iterations / 10);
  94. $salt .= chr(ord('0') + $iterations % 10);
  95. $salt .= '$';
  96. $i = 0;
  97. do {
  98. $c1 = ord($random[$i++]);
  99. $salt .= $itoa64[$c1 >> 2];
  100. $c1 = ($c1 & 0x03) << 4;
  101. if ($i >= 16) {
  102. $salt .= $itoa64[$c1];
  103. $hash = crypt($password, $salt);
  104. return strlen($hash) == 60 ? str_replace("/", "_", $hash) : '*';
  105. }
  106. $c2 = ord($random[$i++]);
  107. $c1 |= $c2 >> 4;
  108. $salt .= $itoa64[$c1];
  109. $c1 = ($c2 & 0x0f) << 2;
  110. $c2 = ord($random[$i++]);
  111. $c1 |= $c2 >> 6;
  112. $salt .= $itoa64[$c1];
  113. $salt .= $itoa64[$c2 & 0x3f];
  114. } while (true);
  115. }
  116. /**
  117. * depreciated. start does nothing now, since starting happens in construction. making use of sessions in any way will start them behind the scenes.
  118. */
  119. public function start(){}
  120. }
  121. //when run from console directly, garbage collect. parameters are directories to be processed
  122. if($argv){
  123. array_shift($argv);
  124. foreach($argv as $dir){
  125. if(!is_dir($dir)) continue;
  126. touch("$dir/garbage.collect.lock", time() + WaxSession::$garbage_collection_timeout);
  127. foreach(glob("$dir/*") as $file){
  128. if($file == "$dir/garbage.collect.lock") continue;
  129. if(($stats = stat($file)) && time() > $stats[9])
  130. unlink($file);
  131. }
  132. }
  133. }
  134. ?>