]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - lib/internalsessionhandler.php
[CORE] Bump Database requirement to MariaDB 10.3+
[quix0rs-gnu-social.git] / lib / internalsessionhandler.php
1 <?php
2 // This file is part of GNU social - https://www.gnu.org/software/social
3 //
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.
8 //
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.
13 //
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/>.
16
17 /**
18  * GNU social's implementation of SessionHandler
19  *
20  * @package   GNUsocial
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
28  */
29
30 defined('GNUSOCIAL') || die();
31
32 /**
33  * Superclass representing the associated interfaces of session handling.
34  *
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
37  */
38 class InternalSessionHandler implements SessionHandlerInterface
39 {
40     /**
41      * A helper function to print a session-related message to the debug log if
42      * the site session debug configuration option is enabled.
43      * @param $msg
44      * @return void
45      */
46     public static function logdeb($msg)
47     {
48         if (common_config('sessions', 'debug')) {
49             common_debug("Session: " . $msg);
50         }
51     }
52
53     /**
54      * Dummy option for saving to file needed for full PHP adherence.
55      *
56      * @param $save_path
57      * @param $session_name
58      * @return bool true
59      */
60     public function open($save_path, $session_name)
61     {
62         return true;
63     }
64
65     /**
66      * Dummy option for saving to file needed for full PHP adherence.
67      *
68      * @return bool true
69      */
70     public function close()
71     {
72         return true;
73     }
74
75     /**
76      * Fetch the session data for the session with the given $id.
77      *
78      * @param $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.
80      */
81     public function read($id)
82     {
83         self::logdeb("Fetching session '$id'.");
84
85         $session = Session::getKV('id', $id);
86
87         if (empty($session)) {
88             self::logdeb("Couldn't find '$id'.");
89             return '';
90         } else {
91             self::logdeb("Found '$id', returning " .
92                          strlen($session->session_data) .
93                          " chars of data.");
94             return (string)$session->session_data;
95         }
96     }
97
98     /**
99      * Write the session data for session with given $id as $session_data.
100      *
101      * @param $id
102      * @param $session_data
103      * @return bool Returns TRUE on success or FALSE on failure.
104      */
105     public function write($id, $session_data)
106     {
107         self::logdeb("Writing session '$id'.");
108
109         $session = Session::getKV('id', $id);
110
111         if (empty($session)) {
112             self::logdeb("'$id' doesn't yet exist; inserting.");
113             $session = new Session();
114
115             $session->id = $id;
116             $session->session_data = $session_data;
117             $session->created = common_sql_now();
118
119             $result = $session->insert();
120
121             if (!$result) {
122                 common_log_db_error($session, 'INSERT', __FILE__);
123                 self::logdeb("Failed to insert '$id'.");
124             } else {
125                 self::logdeb("Successfully inserted '$id' (result = $result).");
126             }
127             return (bool) $result;
128         } else {
129             self::logdeb("'$id' already exists; updating.");
130             if (strcmp($session->session_data, $session_data) == 0) {
131                 self::logdeb("Not writing session '$id' - unchanged.");
132                 return true;
133             } else {
134                 self::logdeb("Session '$id' data changed - updating.");
135
136                 // Only update the required field
137                 $orig = clone($session);
138                 $session->session_data = $session_data;
139                 $result = $session->update($orig);
140
141                 if (!$result) {
142                     common_log_db_error($session, 'UPDATE', __FILE__);
143                     self::logdeb("Failed to update '$id'.");
144                 } else {
145                     self::logdeb("Successfully updated '$id' (result = $result).");
146                 }
147
148                 return (bool) $result;
149             }
150         }
151     }
152
153     /**
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.
157      *
158      * @param $maxlifetime
159      * @return bool Returns TRUE on success or FALSE on failure.
160      */
161     public function gc($maxlifetime)
162     {
163         self::logdeb("Garbage Collector has now started with maxlifetime = '$maxlifetime'.");
164
165         $epoch = common_sql_date(time() - $maxlifetime);
166
167         $ids = [];
168
169         $session = new Session();
170         $session->whereAdd('modified < "' . $epoch . '"');
171         $session->selectAdd();
172         $session->selectAdd('id');
173
174         $limit = common_config('sessions', 'gc_limit');
175         if ($limit > 0) {
176             // On large sites, too many sessions to expire
177             // at once will just result in failure.
178             $session->limit($limit);
179         }
180
181         $session->find();
182
183         while ($session->fetch()) {
184             $ids[] = $session->id;
185         }
186
187         $session->free();
188
189         self::logdeb("Garbage Collector found " . count($ids) . " ids to delete.");
190
191         foreach ($ids as $id) {
192             self::logdeb("Garbage Collector will now delete session '$id'.");
193             self::destroy($id);
194         }
195
196         return true;
197     }
198
199     /**
200      * Deletes session with given id $id.
201      *
202      * @param $id
203      * @return bool Returns TRUE on success or FALSE on failure.
204      */
205     public function destroy($id)
206     {
207         self::logdeb("Destroying session '$id'.");
208
209         $session = Session::getKV('id', $id);
210
211         if (empty($session)) {
212             self::logdeb("Can't find '$id' to destroy.");
213             return false;
214         } else {
215             $result = $session->delete();
216             if (!$result) {
217                 common_log_db_error($session, 'DELETE', __FILE__);
218                 self::logdeb("Failed to destroy '$id'.");
219             } else {
220                 self::logdeb("Successfully destroyed '$id' (result = $result).");
221             }
222             return (bool) $result;
223         }
224     }
225 }