Session.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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')) { exit(1); }
  22. require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
  23. class Session extends Managed_DataObject
  24. {
  25. ###START_AUTOCODE
  26. /* the code below is auto generated do not remove the above tag */
  27. public $__table = 'session'; // table name
  28. public $id; // varchar(32) primary_key not_null
  29. public $session_data; // text()
  30. public $created; // datetime() not_null
  31. public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
  32. /* the code above is auto generated do not remove the tag below */
  33. ###END_AUTOCODE
  34. public static function schemaDef()
  35. {
  36. return array(
  37. 'fields' => array(
  38. 'id' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'session ID'),
  39. 'session_data' => array('type' => 'text', 'description' => 'session data'),
  40. 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
  41. 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
  42. ),
  43. 'primary key' => array('id'),
  44. 'indexes' => array(
  45. 'session_modified_idx' => array('modified'),
  46. ),
  47. );
  48. }
  49. static function logdeb($msg)
  50. {
  51. if (common_config('sessions', 'debug')) {
  52. common_debug("Session: " . $msg);
  53. }
  54. }
  55. static function open($save_path, $session_name)
  56. {
  57. return true;
  58. }
  59. static function close()
  60. {
  61. return true;
  62. }
  63. static function read($id)
  64. {
  65. self::logdeb("Fetching session '$id'");
  66. $session = Session::getKV('id', $id);
  67. if (empty($session)) {
  68. self::logdeb("Couldn't find '$id'");
  69. return '';
  70. } else {
  71. self::logdeb("Found '$id', returning " .
  72. strlen($session->session_data) .
  73. " chars of data");
  74. return (string)$session->session_data;
  75. }
  76. }
  77. static function write($id, $session_data)
  78. {
  79. self::logdeb("Writing session '$id'");
  80. $session = Session::getKV('id', $id);
  81. if (empty($session)) {
  82. self::logdeb("'$id' doesn't yet exist; inserting.");
  83. $session = new Session();
  84. $session->id = $id;
  85. $session->session_data = $session_data;
  86. $session->created = common_sql_now();
  87. $result = $session->insert();
  88. if (!$result) {
  89. common_log_db_error($session, 'INSERT', __FILE__);
  90. self::logdeb("Failed to insert '$id'.");
  91. } else {
  92. self::logdeb("Successfully inserted '$id' (result = $result).");
  93. }
  94. return $result;
  95. } else {
  96. self::logdeb("'$id' already exists; updating.");
  97. if (strcmp($session->session_data, $session_data) == 0) {
  98. self::logdeb("Not writing session '$id'; unchanged");
  99. return true;
  100. } else {
  101. self::logdeb("Session '$id' data changed; updating");
  102. $orig = clone($session);
  103. $session->session_data = $session_data;
  104. $result = $session->update($orig);
  105. if (!$result) {
  106. common_log_db_error($session, 'UPDATE', __FILE__);
  107. self::logdeb("Failed to update '$id'.");
  108. } else {
  109. self::logdeb("Successfully updated '$id' (result = $result).");
  110. }
  111. return $result;
  112. }
  113. }
  114. }
  115. static function destroy($id)
  116. {
  117. self::logdeb("Deleting session $id");
  118. $session = Session::getKV('id', $id);
  119. if (empty($session)) {
  120. self::logdeb("Can't find '$id' to delete.");
  121. } else {
  122. $result = $session->delete();
  123. if (!$result) {
  124. common_log_db_error($session, 'DELETE', __FILE__);
  125. self::logdeb("Failed to delete '$id'.");
  126. } else {
  127. self::logdeb("Successfully deleted '$id' (result = $result).");
  128. }
  129. return $result;
  130. }
  131. }
  132. static function gc($maxlifetime)
  133. {
  134. self::logdeb("garbage collection (maxlifetime = $maxlifetime)");
  135. $epoch = common_sql_date(time() - $maxlifetime);
  136. $ids = array();
  137. $session = new Session();
  138. $session->whereAdd('modified < "'.$epoch.'"');
  139. $session->selectAdd();
  140. $session->selectAdd('id');
  141. $limit = common_config('sessions', 'gc_limit');
  142. if ($limit > 0) {
  143. // On large sites, too many sessions to expire
  144. // at once will just result in failure.
  145. $session->limit($limit);
  146. }
  147. $session->find();
  148. while ($session->fetch()) {
  149. $ids[] = $session->id;
  150. }
  151. $session->free();
  152. self::logdeb("Found " . count($ids) . " ids to delete.");
  153. foreach ($ids as $id) {
  154. self::logdeb("Destroying session '$id'.");
  155. self::destroy($id);
  156. }
  157. }
  158. static function setSaveHandler()
  159. {
  160. self::logdeb("setting save handlers");
  161. $result = session_set_save_handler('Session::open', 'Session::close', 'Session::read',
  162. 'Session::write', 'Session::destroy', 'Session::gc');
  163. self::logdeb("save handlers result = $result");
  164. // PHP 5.3 with APC ends up destroying a bunch of object stuff before the session
  165. // save handlers get called on request teardown.
  166. // Registering an explicit shutdown function should take care of this before
  167. // everything breaks on us.
  168. register_shutdown_function('Session::cleanup');
  169. return $result;
  170. }
  171. static function cleanup()
  172. {
  173. session_write_close();
  174. }
  175. }