2 // This file is part of GNU social - https://www.gnu.org/software/social
4 // GNU social is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // GNU social is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
18 * GNU social's implementation of SessionHandler
21 * @author Evan Prodromou
22 * @author Brion Vibber
23 * @author Mikael Nordfeldth
24 * @author Sorokin Alexei
25 * @author Diogo Cordeiro <diogo@fc.up.pt>
26 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
27 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
30 defined('GNUSOCIAL') || die();
33 * Superclass representing the associated interfaces of session handling.
35 * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
36 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
38 class InternalSessionHandler implements SessionHandlerInterface
41 * A helper function to print a session-related message to the debug log if
42 * the site session debug configuration option is enabled.
46 public static function logdeb($msg)
48 if (common_config('sessions', 'debug')) {
49 common_debug("Session: " . $msg);
54 * Dummy option for saving to file needed for full PHP adherence.
57 * @param $session_name
60 public function open($save_path, $session_name)
66 * Dummy option for saving to file needed for full PHP adherence.
70 public function close()
76 * Fetch the session data for the session with the given $id.
79 * @return string Returns an encoded string of the read data. If nothing was read, it must return an empty string. Note this value is returned internally to PHP for processing.
81 public function read($id)
83 self::logdeb("Fetching session '$id'.");
85 $session = Session::getKV('id', $id);
87 if (empty($session)) {
88 self::logdeb("Couldn't find '$id'.");
91 self::logdeb("Found '$id', returning " .
92 strlen($session->session_data) .
94 return (string)$session->session_data;
99 * Write the session data for session with given $id as $session_data.
102 * @param $session_data
103 * @return bool Returns TRUE on success or FALSE on failure.
105 public function write($id, $session_data)
107 self::logdeb("Writing session '$id'.");
109 $session = Session::getKV('id', $id);
111 if (empty($session)) {
112 self::logdeb("'$id' doesn't yet exist; inserting.");
113 $session = new Session();
116 $session->session_data = $session_data;
117 $session->created = common_sql_now();
119 $result = $session->insert();
122 common_log_db_error($session, 'INSERT', __FILE__);
123 self::logdeb("Failed to insert '$id'.");
125 self::logdeb("Successfully inserted '$id' (result = $result).");
127 return (bool) $result;
129 self::logdeb("'$id' already exists; updating.");
130 if (strcmp($session->session_data, $session_data) == 0) {
131 self::logdeb("Not writing session '$id' - unchanged.");
134 self::logdeb("Session '$id' data changed - updating.");
136 // Only update the required field
137 $orig = clone($session);
138 $session->session_data = $session_data;
139 $result = $session->update($orig);
142 common_log_db_error($session, 'UPDATE', __FILE__);
143 self::logdeb("Failed to update '$id'.");
145 self::logdeb("Successfully updated '$id' (result = $result).");
148 return (bool) $result;
154 * Find sessions that have persisted beyond $maxlifetime and delete them.
155 * This will be limited by config['sessions']['gc_limit'] - it won't delete
156 * more than the number of sessions specified there at a single pass.
158 * @param $maxlifetime
159 * @return bool Returns TRUE on success or FALSE on failure.
161 public function gc($maxlifetime)
163 self::logdeb("Garbage Collector has now started with maxlifetime = '$maxlifetime'.");
165 $epoch = common_sql_date(time() - $maxlifetime);
169 $session = new Session();
170 $session->whereAdd('modified < "' . $epoch . '"');
171 $session->selectAdd();
172 $session->selectAdd('id');
174 $limit = common_config('sessions', 'gc_limit');
176 // On large sites, too many sessions to expire
177 // at once will just result in failure.
178 $session->limit($limit);
183 while ($session->fetch()) {
184 $ids[] = $session->id;
189 self::logdeb("Garbage Collector found " . count($ids) . " ids to delete.");
191 foreach ($ids as $id) {
192 self::logdeb("Garbage Collector will now delete session '$id'.");
200 * Deletes session with given id $id.
203 * @return bool Returns TRUE on success or FALSE on failure.
205 public function destroy($id)
207 self::logdeb("Destroying session '$id'.");
209 $session = Session::getKV('id', $id);
211 if (empty($session)) {
212 self::logdeb("Can't find '$id' to destroy.");
215 $result = $session->delete();
217 common_log_db_error($session, 'DELETE', __FILE__);
218 self::logdeb("Failed to destroy '$id'.");
220 self::logdeb("Successfully destroyed '$id' (result = $result).");
222 return (bool) $result;