PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/utilities/WaxSession.php

http://github.com/phpwax/phpwax
PHP | 190 lines | 139 code | 30 blank | 21 comment | 27 complexity | 5ec97ae8a8478129eb170c02874a4d22 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()) {
  34. return;
  35. } // Don't start a session if this is a search engine
  36. //set passed in data
  37. foreach($data as $k => $v) {
  38. $this->$k = $v;
  39. }
  40. //get id from request or generate an id
  41. if(($this->id = $_COOKIE[$this->name]) || ($this->id = $_REQUEST[$this->name])){
  42. //initialize data from cross-request storage
  43. if(!static::$data[$this->name] && (is_readable($storage = $this->file_storage())) && ($stats = stat($storage))){
  44. if(time() < $stats[9]) {
  45. static::$data[$this->name] = unserialize(file_get_contents($this->file_storage()));
  46. }
  47. else {
  48. unlink($this->file_storage());
  49. }
  50. }
  51. } else {
  52. $this->id = $this->safe_encrypt($_SERVER['REMOTE_ADDR'].microtime().mt_rand());
  53. }
  54. //add folder to collection of folders to be garbage collected
  55. static::$garbage_collection_folders[] = $this->file_storage_dir();
  56. //set cookie on render to propagate session
  57. $session = $this;
  58. WaxEvent::add(
  59. 'wax.response.execute', function() use ($session) {
  60. $response = WaxEvent::data();
  61. $expires = $session->lifetime ? (time() + $session->lifetime) : false;
  62. $response->set_cookie($session->name, $session->id, $expires);
  63. });
  64. $session_save = $this;
  65. WaxEvent::add(
  66. 'wax.response.execute', function () use ($session_save){
  67. $session_save->save_session();
  68. });
  69. }
  70. public function save_session(){
  71. //create folder to store sessions
  72. if(!is_dir($this->file_storage_dir())){
  73. if(!mkdir($this->file_storage_dir(), 0750, true)) throw new WaxException(
  74. 'Session not writable - ' . $this->file_storage_dir());
  75. }
  76. if(static::$updated[$this->name]){
  77. if(file_put_contents($this->file_storage(), serialize(static::$data[$this->name])) === false) throw new WaxException("Session not writable - ".$this->file_storage_dir());
  78. }
  79. touch($this->file_storage(), time() + ($this->lifetime?$this->lifetime:(WaxSession::$garbage_collection_timeout * 10)));
  80. }
  81. public function get($key)
  82. {
  83. if (!$key) {
  84. return static::$data[$this->name];
  85. }
  86. if (isset(static::$data[$this->name][$key])) {
  87. return static::$data[$this->name][$key];
  88. }
  89. return null;
  90. }
  91. public function __get($key) { return $this->get($key); }
  92. public function set($key, $value) { static::$updated[$this->name] = true; static::$data[$this->name][$key] = $value; }
  93. public function __set($key, $value) { return $this->set($key, $value); }
  94. public function unset_var($key) { static::$updated[$this->name] = true; unset(static::$data[$this->name][$key]); }
  95. public function get_hash() { return $this->id; }
  96. public function isset_var($key) { return isset(static::$data[$this->name][$key]); }
  97. public function add_message($string) { static::$updated[$this->name] = true; static::$data[$this->name]['user_messages'][] = $string; }
  98. public function add_error($string) { static::$updated[$this->name] = true; static::$data[$this->name]['user_errors'][] = $string; }
  99. public function unset_session() { static::$updated[$this->name] = true; unset(static::$data[$this->name]); }
  100. public function destroy_session() { $this->unset_session(); }
  101. public function is_bot() {
  102. foreach($this->bots as $bot) {
  103. if (stristr($_SERVER['HTTP_USER_AGENT'], $bot)) {
  104. return true;
  105. }
  106. }
  107. }
  108. public function file_storage_dir(){ return "$this->file_storage_prefix$this->name"; }
  109. public function file_storage(){ return $this->file_storage_dir()."/".$this->id; }
  110. protected function safe_encrypt($password, $iterations = 8) {
  111. $itoa64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';
  112. $random = substr(md5(mt_rand()), 0, 16);
  113. if($iterations < 4 || $iterations > 31) $iterations = 8;
  114. $salt = '$2a$';
  115. $salt .= chr(ord('0') + $iterations / 10);
  116. $salt .= chr(ord('0') + $iterations % 10);
  117. $salt .= '$';
  118. $i = 0;
  119. do {
  120. $c1 = ord($random[$i++]);
  121. $salt .= $itoa64[$c1 >> 2];
  122. $c1 = ($c1 & 0x03) << 4;
  123. if ($i >= 16) {
  124. $salt .= $itoa64[$c1];
  125. $hash = crypt($password, $salt);
  126. return strlen($hash) == 60 ? str_replace("/", "_", $hash) : '*';
  127. }
  128. $c2 = ord($random[$i++]);
  129. $c1 |= $c2 >> 4;
  130. $salt .= $itoa64[$c1];
  131. $c1 = ($c2 & 0x0f) << 2;
  132. $c2 = ord($random[$i++]);
  133. $c1 |= $c2 >> 6;
  134. $salt .= $itoa64[$c1];
  135. $salt .= $itoa64[$c2 & 0x3f];
  136. } while (true);
  137. }
  138. /**
  139. * depreciated. start does nothing now, since starting happens in construction. making use of sessions in any way will start them behind the scenes.
  140. */
  141. public function start(){}
  142. }
  143. //when run from console directly, garbage collect. parameters are directories to be processed
  144. if($argv){
  145. array_shift($argv);
  146. foreach($argv as $dir){
  147. if(!is_dir($dir)) {
  148. continue;
  149. }
  150. touch("$dir/garbage.collect.lock", time() + WaxSession::$garbage_collection_timeout);
  151. foreach(glob("$dir/*") as $file){
  152. if($file === "$dir/garbage.collect.lock") {
  153. continue;
  154. }
  155. if(($stats = stat($file)) && time() > $stats[9]) {
  156. unlink($file);
  157. }
  158. }
  159. }
  160. }