See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // Moodle 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 General Public License for more details. 13 // 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/>. 16 17 /** 18 * Legacy log reader. 19 * @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead. 20 * @todo MDL-52805 This is to be removed in Moodle 3.10 21 * 22 * @package logstore_legacy 23 * @copyright 2013 Petr Skoda {@link http://skodak.org} 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 27 namespace logstore_legacy\log; 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 class store implements \tool_log\log\store, \core\log\sql_reader { 32 use \tool_log\helper\store, 33 \tool_log\helper\reader; 34 35 /** 36 * @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead. 37 * @todo MDL-52805 This is to be removed in Moodle 3.10 38 * 39 * @param \tool_log\log\manager $manager 40 */ 41 public function __construct(\tool_log\log\manager $manager) { 42 $this->helper_setup($manager); 43 } 44 45 /** @var array list of db fields which needs to be replaced for legacy log query */ 46 protected static $standardtolegacyfields = array( 47 'timecreated' => 'time', 48 'courseid' => 'course', 49 'contextinstanceid' => 'cmid', 50 'origin' => 'ip', 51 'anonymous' => 0, 52 ); 53 54 /** @var string Regex to replace the crud params */ 55 const CRUD_REGEX = "/(crud).*?(<>|=|!=).*?'(.*?)'/s"; 56 57 /** 58 * This method contains mapping required for Moodle core to make legacy store compatible with other sql_reader based 59 * queries. 60 * 61 * @param string $selectwhere Select statment 62 * @param array $params params for the sql 63 * @param string $sort sort fields 64 * 65 * @return array returns an array containing the sql predicate, an array of params and sorting parameter. 66 */ 67 protected static function replace_sql_legacy($selectwhere, array $params, $sort = '') { 68 // Following mapping is done to make can_delete_course() compatible with legacy store. 69 if ($selectwhere == "userid = :userid AND courseid = :courseid AND eventname = :eventname AND timecreated > :since" and 70 empty($sort)) { 71 $replace = "module = 'course' AND action = 'new' AND userid = :userid AND url = :url AND time > :since"; 72 $params += array('url' => "view.php?id={$params['courseid']}"); 73 return array($replace, $params, $sort); 74 } 75 76 // Replace db field names to make it compatible with legacy log. 77 foreach (self::$standardtolegacyfields as $from => $to) { 78 $selectwhere = str_replace($from, $to, $selectwhere); 79 if (!empty($sort)) { 80 $sort = str_replace($from, $to, $sort); 81 } 82 if (isset($params[$from])) { 83 $params[$to] = $params[$from]; 84 unset($params[$from]); 85 } 86 } 87 88 // Replace crud fields. 89 $selectwhere = preg_replace_callback("/(crud).*?(<>|=|!=).*?'(.*?)'/s", 'self::replace_crud', $selectwhere); 90 91 return array($selectwhere, $params, $sort); 92 } 93 94 /** 95 * @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead. 96 * @todo MDL-52805 This will be removed in Moodle 3.10 97 * 98 * @param string $selectwhere 99 * @param array $params 100 * @param string $sort 101 * @param int $limitfrom 102 * @param int $limitnum 103 * @return array 104 */ 105 public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum) { 106 global $DB; 107 108 $sort = self::tweak_sort_by_id($sort); 109 110 // Replace the query with hardcoded mappings required for core. 111 list($selectwhere, $params, $sort) = self::replace_sql_legacy($selectwhere, $params, $sort); 112 113 $records = array(); 114 115 try { 116 // A custom report + on the fly SQL rewriting = a possible exception. 117 $records = $DB->get_recordset_select('log', $selectwhere, $params, $sort, '*', $limitfrom, $limitnum); 118 } catch (\moodle_exception $ex) { 119 debugging("error converting legacy event data " . $ex->getMessage() . $ex->debuginfo, DEBUG_DEVELOPER); 120 return array(); 121 } 122 123 $events = array(); 124 125 foreach ($records as $data) { 126 $events[$data->id] = $this->get_log_event($data); 127 } 128 129 $records->close(); 130 131 return $events; 132 } 133 134 /** 135 * Get whether events are present for the given select clause. 136 * @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead. 137 * 138 * @param string $selectwhere select conditions. 139 * @param array $params params. 140 * 141 * @return bool Whether events available for the given conditions 142 */ 143 public function get_events_select_exists(string $selectwhere, array $params): bool { 144 global $DB; 145 146 // Replace the query with hardcoded mappings required for core. 147 list($selectwhere, $params) = self::replace_sql_legacy($selectwhere, $params); 148 149 try { 150 return $DB->record_exists_select('log', $selectwhere, $params); 151 } catch (\moodle_exception $ex) { 152 debugging("error converting legacy event data " . $ex->getMessage() . $ex->debuginfo, DEBUG_DEVELOPER); 153 return false; 154 } 155 } 156 157 /** 158 * Fetch records using given criteria returning a Traversable object. 159 * @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead. 160 * @todo MDL-52805 This will be removed in Moodle 3.10 161 * 162 * Note that the traversable object contains a moodle_recordset, so 163 * remember that is important that you call close() once you finish 164 * using it. 165 * 166 * @param string $selectwhere 167 * @param array $params 168 * @param string $sort 169 * @param int $limitfrom 170 * @param int $limitnum 171 * @return \Traversable|\core\event\base[] 172 */ 173 public function get_events_select_iterator($selectwhere, array $params, $sort, $limitfrom, $limitnum) { 174 global $DB; 175 176 $sort = self::tweak_sort_by_id($sort); 177 178 // Replace the query with hardcoded mappings required for core. 179 list($selectwhere, $params, $sort) = self::replace_sql_legacy($selectwhere, $params, $sort); 180 181 try { 182 $recordset = $DB->get_recordset_select('log', $selectwhere, $params, $sort, '*', $limitfrom, $limitnum); 183 } catch (\moodle_exception $ex) { 184 debugging("error converting legacy event data " . $ex->getMessage() . $ex->debuginfo, DEBUG_DEVELOPER); 185 return new \EmptyIterator; 186 } 187 188 return new \core\dml\recordset_walk($recordset, array($this, 'get_log_event')); 189 } 190 191 /** 192 * Returns an event from the log data. 193 * @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead. 194 * @todo MDL-52805 This will be removed in Moodle 3.10 195 * 196 * @param stdClass $data Log data 197 * @return \core\event\base 198 */ 199 public function get_log_event($data) { 200 return \logstore_legacy\event\legacy_logged::restore_legacy($data); 201 } 202 203 /** 204 * @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead. 205 * @todo MDL-52805 This will be removed in Moodle 3.10 206 * 207 * @param string $selectwhere 208 * @param array $params 209 * @return int 210 */ 211 public function get_events_select_count($selectwhere, array $params) { 212 global $DB; 213 214 // Replace the query with hardcoded mappings required for core. 215 list($selectwhere, $params) = self::replace_sql_legacy($selectwhere, $params); 216 217 try { 218 return $DB->count_records_select('log', $selectwhere, $params); 219 } catch (\moodle_exception $ex) { 220 debugging("error converting legacy event data " . $ex->getMessage() . $ex->debuginfo, DEBUG_DEVELOPER); 221 return 0; 222 } 223 } 224 225 /** 226 * Are the new events appearing in the reader? 227 * @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead. 228 * @todo MDL-52805 This will be removed in Moodle 3.10 229 * 230 * @return bool true means new log events are being added, false means no new data will be added 231 */ 232 public function is_logging() { 233 return (bool)$this->get_config('loglegacy', true); 234 } 235 236 /** 237 * @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead. 238 * @todo MDL-52805 This will be removed in Moodle 3.10 239 */ 240 public function dispose() { 241 } 242 243 /** 244 * Legacy add_to_log() code. 245 * @deprecated since Moodle 3.1 MDL-45104 - Please use supported log stores such as "standard" or "external" instead. 246 * @todo MDL-52805 This will be removed in Moodle 3.3 247 * 248 * @param int $courseid The course id 249 * @param string $module The module name e.g. forum, journal, resource, course, user etc 250 * @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify. 251 * @param string $url The file and parameters used to see the results of the action 252 * @param string $info Additional description information 253 * @param int $cm The course_module->id if there is one 254 * @param int|\stdClass $user If log regards $user other than $USER 255 * @param string $ip Override the IP, should only be used for restore. 256 * @param int $time Override the log time, should only be used for restore. 257 */ 258 public function legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user, $ip = null, $time = null) { 259 // Note that this function intentionally does not follow the normal Moodle DB access idioms. 260 // This is for a good reason: it is the most frequently used DB update function, 261 // so it has been optimised for speed. 262 global $DB, $CFG, $USER; 263 if (!$this->is_logging()) { 264 return; 265 } 266 267 if ($cm === '' || is_null($cm)) { // Postgres won't translate empty string to its default. 268 $cm = 0; 269 } 270 271 if ($user) { 272 $userid = $user; 273 } else { 274 if (\core\session\manager::is_loggedinas()) { // Don't log. 275 return; 276 } 277 $userid = empty($USER->id) ? '0' : $USER->id; 278 } 279 280 if (isset($CFG->logguests) and !$CFG->logguests) { 281 if (!$userid or isguestuser($userid)) { 282 return; 283 } 284 } 285 286 $remoteaddr = (is_null($ip)) ? getremoteaddr() : $ip; 287 288 $timenow = (is_null($time)) ? time() : $time; 289 if (!empty($url)) { // Could break doing html_entity_decode on an empty var. 290 $url = html_entity_decode($url, ENT_QUOTES, 'UTF-8'); 291 } else { 292 $url = ''; 293 } 294 295 // Restrict length of log lines to the space actually available in the 296 // database so that it doesn't cause a DB error. Log a warning so that 297 // developers can avoid doing things which are likely to cause this on a 298 // routine basis. 299 if (\core_text::strlen($action) > 40) { 300 $action = \core_text::substr($action, 0, 37) . '...'; 301 debugging('Warning: logged very long action', DEBUG_DEVELOPER); 302 } 303 304 if (!empty($info) && \core_text::strlen($info) > 255) { 305 $info = \core_text::substr($info, 0, 252) . '...'; 306 debugging('Warning: logged very long info', DEBUG_DEVELOPER); 307 } 308 309 // If the 100 field size is changed, also need to alter print_log in course/lib.php. 310 if (!empty($url) && \core_text::strlen($url) > 100) { 311 $url = \core_text::substr($url, 0, 97) . '...'; 312 debugging('Warning: logged very long URL', DEBUG_DEVELOPER); 313 } 314 315 if (defined('MDL_PERFDB')) { 316 global $PERF; 317 $PERF->logwrites++; 318 }; 319 320 $log = array('time' => $timenow, 'userid' => $userid, 'course' => $courseid, 'ip' => $remoteaddr, 321 'module' => $module, 'cmid' => $cm, 'action' => $action, 'url' => $url, 'info' => $info); 322 323 try { 324 $DB->insert_record_raw('log', $log, false); 325 } catch (\dml_exception $e) { 326 debugging('Error: Could not insert a new entry to the Moodle log. ' . $e->errorcode, DEBUG_ALL); 327 328 // MDL-11893, alert $CFG->supportemail if insert into log failed. 329 if ($CFG->supportemail and empty($CFG->noemailever)) { 330 // Function email_to_user is not usable because email_to_user tries to write to the logs table, 331 // and this will get caught in an infinite loop, if disk is full. 332 $site = get_site(); 333 $subject = 'Insert into log failed at your moodle site ' . $site->fullname; 334 $message = "Insert into log table failed at " . date('l dS \of F Y h:i:s A') . 335 ".\n It is possible that your disk is full.\n\n"; 336 $message .= "The failed query parameters are:\n\n" . var_export($log, true); 337 338 $lasttime = get_config('admin', 'lastloginserterrormail'); 339 if (empty($lasttime) || time() - $lasttime > 60 * 60 * 24) { // Limit to 1 email per day. 340 // Using email directly rather than messaging as they may not be able to log in to access a message. 341 mail($CFG->supportemail, $subject, $message); 342 set_config('lastloginserterrormail', time(), 'admin'); 343 } 344 } 345 } 346 } 347 348 /** 349 * Generate a replace string for crud related sql conditions. This function is called as callback to preg_replace_callback() 350 * on the actual sql. 351 * 352 * @param array $match matched string for the passed pattern 353 * 354 * @return string The sql string to use instead of original 355 */ 356 protected static function replace_crud($match) { 357 $return = ''; 358 unset($match[0]); // The first entry is the whole string. 359 foreach ($match as $m) { 360 // We hard code LIKE here because we are not worried about case sensitivity and want this to be fast. 361 switch ($m) { 362 case 'crud' : 363 $replace = 'action'; 364 break; 365 case 'c' : 366 switch ($match[2]) { 367 case '=' : 368 $replace = " LIKE '%add%'"; 369 break; 370 case '!=' : 371 case '<>' : 372 $replace = " NOT LIKE '%add%'"; 373 break; 374 default: 375 $replace = ''; 376 } 377 break; 378 case 'r' : 379 switch ($match[2]) { 380 case '=' : 381 $replace = " LIKE '%view%' OR action LIKE '%report%'"; 382 break; 383 case '!=' : 384 case '<>' : 385 $replace = " NOT LIKE '%view%' AND action NOT LIKE '%report%'"; 386 break; 387 default: 388 $replace = ''; 389 } 390 break; 391 case 'u' : 392 switch ($match[2]) { 393 case '=' : 394 $replace = " LIKE '%update%'"; 395 break; 396 case '!=' : 397 case '<>' : 398 $replace = " NOT LIKE '%update%'"; 399 break; 400 default: 401 $replace = ''; 402 } 403 break; 404 case 'd' : 405 switch ($match[2]) { 406 case '=' : 407 $replace = " LIKE '%delete%'"; 408 break; 409 case '!=' : 410 case '<>' : 411 $replace = " NOT LIKE '%delete%'"; 412 break; 413 default: 414 $replace = ''; 415 } 416 break; 417 default : 418 $replace = ''; 419 } 420 $return .= $replace; 421 } 422 return $return; 423 } 424 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body