Session.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. <?php
  2. /**
  3. * Table Definition for session
  4. *
  5. * StatusNet - the distributed open-source microblogging tool
  6. * Copyright (C) 2009, StatusNet, Inc.
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. if (!defined('STATUSNET') && !defined('LACONICA')) {
  22. exit(1);
  23. }
  24. require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
  25. class Session extends Managed_DataObject
  26. {
  27. ###START_AUTOCODE
  28. /* the code below is auto generated do not remove the above tag */
  29. public $__table = 'session'; // table name
  30. public $id; // varchar(32) primary_key not_null
  31. public $session_data; // text()
  32. public $created; // datetime() not_null
  33. public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
  34. /* the code above is auto generated do not remove the tag below */
  35. ###END_AUTOCODE
  36. public static function schemaDef()
  37. {
  38. return [
  39. 'fields' => [
  40. 'id' => ['type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'session ID'],
  41. 'session_data' => ['type' => 'text', 'description' => 'session data'],
  42. 'created' => ['type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'],
  43. 'modified' => ['type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'],
  44. ],
  45. 'primary key' => ['id'],
  46. 'indexes' => [
  47. 'session_modified_idx' => ['modified'],
  48. ],
  49. ];
  50. }
  51. static function open($save_path, $session_name)
  52. {
  53. return true;
  54. }
  55. static function close()
  56. {
  57. return true;
  58. }
  59. static function read($id)
  60. {
  61. self::logdeb("Fetching session '$id'");
  62. $session = Session::getKV('id', $id);
  63. if (empty($session)) {
  64. self::logdeb("Couldn't find '$id'");
  65. return '';
  66. } else {
  67. self::logdeb("Found '$id', returning " .
  68. strlen($session->session_data) .
  69. " chars of data");
  70. return (string)$session->session_data;
  71. }
  72. }
  73. static function logdeb($msg)
  74. {
  75. if (common_config('sessions', 'debug')) {
  76. common_debug("Session: " . $msg);
  77. }
  78. }
  79. static function write($id, $session_data)
  80. {
  81. self::logdeb("Writing session '$id'");
  82. $session = Session::getKV('id', $id);
  83. if (empty($session)) {
  84. self::logdeb("'$id' doesn't yet exist; inserting.");
  85. $session = new Session();
  86. $session->id = $id;
  87. $session->session_data = $session_data;
  88. $session->created = common_sql_now();
  89. $result = $session->insert();
  90. if (!$result) {
  91. common_log_db_error($session, 'INSERT', __FILE__);
  92. self::logdeb("Failed to insert '$id'.");
  93. } else {
  94. self::logdeb("Successfully inserted '$id' (result = $result).");
  95. }
  96. return $result;
  97. } else {
  98. self::logdeb("'$id' already exists; updating.");
  99. if (strcmp($session->session_data, $session_data) == 0) {
  100. self::logdeb("Not writing session '$id'; unchanged");
  101. return true;
  102. } else {
  103. self::logdeb("Session '$id' data changed; updating");
  104. $orig = clone($session);
  105. $session->session_data = $session_data;
  106. $result = $session->update($orig);
  107. if (!$result) {
  108. common_log_db_error($session, 'UPDATE', __FILE__);
  109. self::logdeb("Failed to update '$id'.");
  110. } else {
  111. self::logdeb("Successfully updated '$id' (result = $result).");
  112. }
  113. return $result;
  114. }
  115. }
  116. }
  117. static function gc($maxlifetime)
  118. {
  119. self::logdeb("garbage collection (maxlifetime = $maxlifetime)");
  120. $epoch = common_sql_date(time() - $maxlifetime);
  121. $ids = [];
  122. $session = new Session();
  123. $session->whereAdd('modified < "' . $epoch . '"');
  124. $session->selectAdd();
  125. $session->selectAdd('id');
  126. $limit = common_config('sessions', 'gc_limit');
  127. if ($limit > 0) {
  128. // On large sites, too many sessions to expire
  129. // at once will just result in failure.
  130. $session->limit($limit);
  131. }
  132. $session->find();
  133. while ($session->fetch()) {
  134. $ids[] = $session->id;
  135. }
  136. $session->free();
  137. self::logdeb("Found " . count($ids) . " ids to delete.");
  138. foreach ($ids as $id) {
  139. self::logdeb("Destroying session '$id'.");
  140. self::destroy($id);
  141. }
  142. }
  143. static function destroy($id)
  144. {
  145. self::logdeb("Deleting session $id");
  146. $session = Session::getKV('id', $id);
  147. if (empty($session)) {
  148. self::logdeb("Can't find '$id' to delete.");
  149. return false;
  150. } else {
  151. $result = $session->delete();
  152. if (!$result) {
  153. common_log_db_error($session, 'DELETE', __FILE__);
  154. self::logdeb("Failed to delete '$id'.");
  155. } else {
  156. self::logdeb("Successfully deleted '$id' (result = $result).");
  157. }
  158. return $result;
  159. }
  160. }
  161. static function setSaveHandler()
  162. {
  163. self::logdeb("setting save handlers");
  164. $result = session_set_save_handler('Session::open', 'Session::close', 'Session::read',
  165. 'Session::write', 'Session::destroy', 'Session::gc');
  166. self::logdeb("save handlers result = $result");
  167. // PHP 5.3 with APC ends up destroying a bunch of object stuff before the session
  168. // save handlers get called on request teardown.
  169. // Registering an explicit shutdown function should take care of this before
  170. // everything breaks on us.
  171. register_shutdown_function('Session::cleanup');
  172. return $result;
  173. }
  174. static function cleanup()
  175. {
  176. session_write_close();
  177. }
  178. }