Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 1441
Línea 12... Línea 12...
12
// GNU General Public License for more details.
12
// GNU General Public License for more details.
13
//
13
//
14
// You should have received a copy of the GNU General Public License
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
Línea 16... Línea -...
16
 
-
 
17
/**
-
 
18
 * Session handler base.
-
 
19
 *
-
 
20
 * @package    core
-
 
21
 * @copyright  2013 Petr Skoda {@link http://skodak.org}
-
 
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
-
 
23
 */
-
 
24
 
16
 
Línea -... Línea 17...
-
 
17
namespace core\session;
25
namespace core\session;
18
 
-
 
19
use core\clock;
Línea 26... Línea 20...
26
 
20
use core\di;
27
defined('MOODLE_INTERNAL') || die();
21
use stdClass;
28
 
22
 
29
/**
23
/**
Línea 78... Línea 72...
78
    public function set_requires_write_lock($requireswritelock) {
72
    public function set_requires_write_lock($requireswritelock) {
79
        $this->requireswritelock = $requireswritelock;
73
        $this->requireswritelock = $requireswritelock;
80
    }
74
    }
Línea 81... Línea 75...
81
 
75
 
-
 
76
    /**
-
 
77
     * Returns all session records.
-
 
78
     *
-
 
79
     * @return \Iterator
-
 
80
     */
-
 
81
    public function get_all_sessions(): \Iterator {
-
 
82
        global $DB;
-
 
83
 
-
 
84
        $rs = $DB->get_recordset('sessions');
-
 
85
        foreach ($rs as $row) {
-
 
86
            yield $row;
-
 
87
        }
-
 
88
        $rs->close();
-
 
89
    }
-
 
90
 
-
 
91
    /**
-
 
92
     * Returns a single session record for this session id.
-
 
93
     *
-
 
94
     * @param string $sid
-
 
95
     * @return stdClass
-
 
96
     */
-
 
97
    public function get_session_by_sid(string $sid): stdClass {
-
 
98
        global $DB;
-
 
99
 
-
 
100
        return $DB->get_record('sessions', ['sid' => $sid]) ?: new stdClass();
-
 
101
    }
-
 
102
 
-
 
103
    /**
-
 
104
     * Returns all the session records for this user id.
-
 
105
     *
-
 
106
     * @param int $userid
-
 
107
     * @return array
-
 
108
     */
-
 
109
    public function get_sessions_by_userid(int $userid): array {
-
 
110
        global $DB;
-
 
111
 
-
 
112
        return $DB->get_records('sessions', ['userid' => $userid]);
-
 
113
    }
-
 
114
 
-
 
115
    /**
-
 
116
     * Insert new empty session record.
-
 
117
     *
-
 
118
     * @param int $userid
-
 
119
     * @return stdClass the new record
-
 
120
     */
-
 
121
    public function add_session(int $userid): stdClass {
-
 
122
        global $DB;
-
 
123
 
-
 
124
        $record = new stdClass();
-
 
125
        $record->state       = 0;
-
 
126
        $record->sid         = session_id();
-
 
127
        $record->sessdata    = null;
-
 
128
        $record->userid      = $userid;
-
 
129
        $record->timecreated = $record->timemodified = di::get(clock::class)->time();
-
 
130
        $record->firstip     = $record->lastip = getremoteaddr();
-
 
131
 
-
 
132
        $record->id = $DB->insert_record('sessions', $record);
-
 
133
 
-
 
134
        return $record;
-
 
135
    }
-
 
136
 
-
 
137
    /**
-
 
138
     * Update a session record.
-
 
139
     *
-
 
140
     * @param stdClass $record
-
 
141
     * @return bool
-
 
142
     */
-
 
143
    public function update_session(stdClass $record): bool {
-
 
144
        global $DB;
-
 
145
 
-
 
146
        if (!isset($record->id) && isset($record->sid)) {
-
 
147
            $record->id = $DB->get_field('sessions', 'id', ['sid' => $record->sid]);
-
 
148
        }
-
 
149
 
-
 
150
        return $DB->update_record('sessions', $record);
-
 
151
    }
-
 
152
 
-
 
153
    /**
-
 
154
     * Destroy a specific session and delete this session record for this session id.
-
 
155
     *
-
 
156
     * @param string $id session id
-
 
157
     * @return bool
-
 
158
     */
-
 
159
    public function destroy(string $id): bool {
-
 
160
        global $DB;
-
 
161
 
-
 
162
        return $DB->delete_records('sessions', ['sid' => $id]);
-
 
163
    }
-
 
164
 
-
 
165
    /**
-
 
166
     * Destroy all sessions, and delete all the session data.
-
 
167
     *
-
 
168
     * @return bool
-
 
169
     */
-
 
170
    public function destroy_all(): bool {
-
 
171
        global $DB;
-
 
172
 
-
 
173
        return $DB->delete_records('sessions');
-
 
174
    }
-
 
175
 
-
 
176
    /**
-
 
177
     * Clean up expired sessions.
-
 
178
     *
-
 
179
     * @param int $purgebefore Sessions that have not updated for the last purgebefore timestamp will be removed.
-
 
180
     * @param int $userid
-
 
181
     */
-
 
182
    protected function destroy_expired_user_sessions(int $purgebefore, int $userid): void {
-
 
183
        $sessions = $this->get_sessions_by_userid($userid);
-
 
184
        foreach ($sessions as $session) {
-
 
185
            if ($session->timemodified < $purgebefore) {
-
 
186
                $this->destroy($session->sid);
-
 
187
            }
-
 
188
        }
-
 
189
    }
-
 
190
 
-
 
191
    /**
-
 
192
     * Clean up all expired sessions.
-
 
193
     *
-
 
194
     * @param int $purgebefore
-
 
195
     */
-
 
196
    protected function destroy_all_expired_sessions(int $purgebefore): void {
-
 
197
        global $DB, $CFG;
-
 
198
 
-
 
199
        $authsequence = get_enabled_auth_plugins();
-
 
200
        $authsequence = array_flip($authsequence);
-
 
201
        unset($authsequence['nologin']); // No login means user cannot login.
-
 
202
        $authsequence = array_flip($authsequence);
-
 
203
        $authplugins = [];
-
 
204
        foreach ($authsequence as $authname) {
-
 
205
            $authplugins[$authname] = get_auth_plugin($authname);
-
 
206
        }
-
 
207
        $sql = "SELECT u.*, s.sid, s.timecreated AS s_timecreated, s.timemodified AS s_timemodified
-
 
208
                  FROM {user} u
-
 
209
                  JOIN {sessions} s ON s.userid = u.id
-
 
210
                 WHERE s.timemodified < :purgebefore AND u.id <> :guestid";
-
 
211
        $params = ['purgebefore' => $purgebefore, 'guestid' => $CFG->siteguest];
-
 
212
 
-
 
213
        $rs = $DB->get_recordset_sql($sql, $params);
-
 
214
        foreach ($rs as $user) {
-
 
215
            foreach ($authplugins as $authplugin) {
-
 
216
                if ($authplugin->ignore_timeout_hook($user, $user->sid, $user->s_timecreated, $user->s_timemodified)) {
-
 
217
                    continue 2;
-
 
218
                }
-
 
219
            }
-
 
220
            $this->destroy($user->sid);
-
 
221
        }
-
 
222
        $rs->close();
-
 
223
    }
-
 
224
 
-
 
225
    /**
-
 
226
     * Destroy all sessions for a given plugin.
-
 
227
     * Typically used when a plugin is disabled or uninstalled, so all sessions (users) for that plugin are logged out.
-
 
228
     *
-
 
229
     * @param string $pluginname Auth plugin name.
-
 
230
     */
-
 
231
    public function destroy_by_auth_plugin(string $pluginname): void {
-
 
232
        global $DB;
-
 
233
 
-
 
234
        $rs = $DB->get_recordset('user', ['auth' => $pluginname], 'id ASC', 'id');
-
 
235
        foreach ($rs as $user) {
-
 
236
            $sessions = $this->get_sessions_by_userid($user->id);
-
 
237
            foreach ($sessions as $session) {
-
 
238
                $this->destroy($session->sid);
-
 
239
            }
-
 
240
        }
-
 
241
        $rs->close();
-
 
242
    }
-
 
243
 
-
 
244
    // phpcs:disable moodle.NamingConventions.ValidVariableName.VariableNameUnderscore
-
 
245
    /**
-
 
246
     * Periodic timed-out session cleanup.
-
 
247
     *
-
 
248
     * @param int $max_lifetime Sessions that have not updated for the last max_lifetime seconds will be removed.
-
 
249
     * @return int|false Number of deleted sessions or false if an error occurred.
-
 
250
     */
-
 
251
    public function gc(int $max_lifetime = 0): int|false {
-
 
252
        global $CFG;
-
 
253
 
-
 
254
        // This may take a long time.
-
 
255
        \core_php_time_limit::raise();
-
 
256
 
-
 
257
        if ($max_lifetime === 0) {
-
 
258
            $max_lifetime = (int) $CFG->sessiontimeout;
-
 
259
        }
-
 
260
 
-
 
261
        try {
-
 
262
            // Calculate the timestamp before which sessions are considered expired.
-
 
263
            $purgebefore = di::get(clock::class)->time() - $max_lifetime;
-
 
264
 
-
 
265
            // Delete expired sessions for guest user account.
-
 
266
            $this->destroy_expired_user_sessions($purgebefore, $CFG->siteguest);
-
 
267
 
-
 
268
            // Delete expired sessions for userid = 0 (not logged in), better kill them asap to release memory.
-
 
269
            $this->destroy_expired_user_sessions($purgebefore, 0);
-
 
270
 
-
 
271
            // Clean up expired sessions for real users only.
-
 
272
            $this->destroy_all_expired_sessions($purgebefore);
-
 
273
 
-
 
274
            // Cleanup leftovers from the first browser access because it may set multiple cookies and then use only one.
-
 
275
            $purgebefore = di::get(clock::class)->time() - (60 * 3);
-
 
276
            $sessions = $this->get_sessions_by_userid(0);
-
 
277
            foreach ($sessions as $session) {
-
 
278
                if ($session->timemodified == $session->timecreated && $session->timemodified < $purgebefore) {
-
 
279
                    $this->destroy($session->sid);
-
 
280
                }
-
 
281
            }
-
 
282
 
-
 
283
        } catch (\Exception $ex) {
-
 
284
            debugging('Error gc-ing sessions: '.$ex->getMessage(), DEBUG_NORMAL, $ex->getTrace());
-
 
285
        }
-
 
286
 
-
 
287
        return 0;
-
 
288
    }
-
 
289
    // phpcs:enable
-
 
290
 
82
    /**
291
    /**
83
     * Has this session been opened with a writelock? Your handler should call this during
292
     * Has this session been opened with a writelock? Your handler should call this during
84
     * start() if you support read-only sessions.
293
     * start() if you support read-only sessions.
85
     * @return bool true if session is intended to have a write lock.
294
     * @return bool true if session is intended to have a write lock.
86
     */
295
     */
Línea 100... Línea 309...
100
     *
309
     *
101
     * @param string $sid
310
     * @param string $sid
102
     * @return bool true if session found.
311
     * @return bool true if session found.
103
     */
312
     */
104
    abstract public function session_exists($sid);
313
    abstract public function session_exists($sid);
105
 
-
 
106
    /**
-
 
107
     * Kill all active sessions, the core sessions table is
-
 
108
     * purged afterwards.
-
 
109
     */
-
 
110
    abstract public function kill_all_sessions();
-
 
111
 
-
 
112
    /**
-
 
113
     * Kill one session, the session record is removed afterwards.
-
 
114
     * @param string $sid
-
 
115
     */
-
 
116
    abstract public function kill_session($sid);
-
 
117
}
314
}