diff --git a/lib/classes/exception/coding_exception.php b/lib/classes/exception/coding_exception.php new file mode 100644 index 00000000000..94936bea7fa --- /dev/null +++ b/lib/classes/exception/coding_exception.php @@ -0,0 +1,35 @@ +. + +/** + * Exception indicating programming error, must be fixed by a programer. For example + * a core API might throw this type of exception if a plugin calls it incorrectly. + * + * @package core + * @subpackage lib + * @copyright 2008 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class coding_exception extends moodle_exception { + /** + * Constructor + * @param string $hint short description of problem + * @param string $debuginfo detailed information how to fix problem + */ + function __construct($hint, $debuginfo=null) { + parent::__construct('codingerror', 'debug', '', $hint, $debuginfo); + } +} diff --git a/lib/classes/exception/file_serving_exception.php b/lib/classes/exception/file_serving_exception.php new file mode 100644 index 00000000000..f60c21d0e77 --- /dev/null +++ b/lib/classes/exception/file_serving_exception.php @@ -0,0 +1,34 @@ +. + + +/** + * An exception that indicates that file can not be served + * + * @package core + * @subpackage lib + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class file_serving_exception extends moodle_exception { + /** + * Constructor + * @param string $debuginfo optional more detailed information + */ + function __construct($debuginfo = NULL) { + parent::__construct('cannotservefile', 'error', '', NULL, $debuginfo); + } +} diff --git a/lib/classes/exception/invalid_dataroot_permissions.php b/lib/classes/exception/invalid_dataroot_permissions.php new file mode 100644 index 00000000000..cb7feeaa079 --- /dev/null +++ b/lib/classes/exception/invalid_dataroot_permissions.php @@ -0,0 +1,34 @@ +. + + +/** + * An exception that indicates incorrect permissions in $CFG->dataroot + * + * @package core + * @subpackage lib + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class invalid_dataroot_permissions extends moodle_exception { + /** + * Constructor + * @param string $debuginfo optional more detailed information + */ + function __construct($debuginfo = NULL) { + parent::__construct('invaliddatarootpermissions', 'error', '', NULL, $debuginfo); + } +} diff --git a/lib/classes/exception/invalid_parameter_exception.php b/lib/classes/exception/invalid_parameter_exception.php new file mode 100644 index 00000000000..a8b3d58608f --- /dev/null +++ b/lib/classes/exception/invalid_parameter_exception.php @@ -0,0 +1,36 @@ +. + +/** + * Exception indicating malformed parameter problem. + * This exception is not supposed to be thrown when processing + * user submitted data in forms. It is more suitable + * for WS and other low level stuff. + * + * @package core + * @subpackage lib + * @copyright 2009 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class invalid_parameter_exception extends moodle_exception { + /** + * Constructor + * @param string $debuginfo some detailed information + */ + function __construct($debuginfo=null) { + parent::__construct('invalidparameter', 'debug', '', null, $debuginfo); + } +} diff --git a/lib/classes/exception/invalid_response_exception.php b/lib/classes/exception/invalid_response_exception.php new file mode 100644 index 00000000000..22317ee6a7e --- /dev/null +++ b/lib/classes/exception/invalid_response_exception.php @@ -0,0 +1,31 @@ +. + +/** + * Exception indicating malformed response problem. + * This exception is not supposed to be thrown when processing + * user submitted data in forms. It is more suitable + * for WS and other low level stuff. + */ +class invalid_response_exception extends moodle_exception { + /** + * Constructor + * @param string $debuginfo some detailed information + */ + function __construct($debuginfo=null) { + parent::__construct('invalidresponse', 'debug', '', null, $debuginfo); + } +} diff --git a/lib/classes/exception/invalid_state_exception.php b/lib/classes/exception/invalid_state_exception.php new file mode 100644 index 00000000000..09aa18a5625 --- /dev/null +++ b/lib/classes/exception/invalid_state_exception.php @@ -0,0 +1,38 @@ +. + +/** + * An exception that indicates something really weird happened. For example, + * if you do switch ($context->contextlevel), and have one case for each + * CONTEXT_... constant. You might throw an invalid_state_exception in the + * default case, to just in case something really weird is going on, and + * $context->contextlevel is invalid - rather than ignoring this possibility. + * + * @package core + * @subpackage lib + * @copyright 2009 onwards Martin Dougiamas {@link http://moodle.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class invalid_state_exception extends moodle_exception { + /** + * Constructor + * @param string $hint short description of problem + * @param string $debuginfo optional more detailed information + */ + function __construct($hint, $debuginfo=null) { + parent::__construct('invalidstatedetected', 'debug', '', $hint, $debuginfo); + } +} diff --git a/lib/classes/exception/moodle_exception.php b/lib/classes/exception/moodle_exception.php new file mode 100644 index 00000000000..10c67d661f7 --- /dev/null +++ b/lib/classes/exception/moodle_exception.php @@ -0,0 +1,107 @@ +. + +/** + * Base Moodle Exception class + * + * Although this class is defined here, you cannot throw a moodle_exception until + * after moodlelib.php has been included (which will happen very soon). + * + * @package core + * @subpackage lib + * @copyright 2008 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class moodle_exception extends \Exception { + + /** + * @var string The name of the string from error.php to print + */ + public $errorcode; + + /** + * @var string The name of module + */ + public $module; + + /** + * @var mixed Extra words and phrases that might be required in the error string + */ + public $a; + + /** + * @var string The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page. + */ + public $link; + + /** + * @var string Optional information to aid the debugging process + */ + public $debuginfo; + + /** + * Constructor + * @param string $errorcode The name of the string from error.php to print + * @param string $module name of module + * @param string $link The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page. + * @param mixed $a Extra words and phrases that might be required in the error string + * @param string $debuginfo optional debugging information + */ + function __construct($errorcode, $module='', $link='', $a=NULL, $debuginfo=null) { + global $CFG; + + if (empty($module) || $module == 'moodle' || $module == 'core') { + $module = 'error'; + } + + $this->errorcode = $errorcode; + $this->module = $module; + $this->link = $link; + $this->a = $a; + $this->debuginfo = is_null($debuginfo) ? null : (string)$debuginfo; + + if (get_string_manager()->string_exists($errorcode, $module)) { + $message = get_string($errorcode, $module, $a); + $haserrorstring = true; + } else { + $message = $module . '/' . $errorcode; + $haserrorstring = false; + } + + $isinphpunittest = (defined('PHPUNIT_TEST') && PHPUNIT_TEST); + $hasdebugdeveloper = ( + isset($CFG->debugdisplay) && + isset($CFG->debug) && + $CFG->debugdisplay && + $CFG->debug === DEBUG_DEVELOPER + ); + + if ($debuginfo) { + if ($isinphpunittest || $hasdebugdeveloper) { + $message = "$message ($debuginfo)"; + } + } + + if (!$haserrorstring and $isinphpunittest) { + // Append the contents of $a to $debuginfo so helpful information isn't lost. + // This emulates what {@link get_exception_info()} does. Unfortunately that + // function is not used by phpunit. + $message .= PHP_EOL.'$a contents: '.print_r($a, true); + } + + parent::__construct($message, 0); + } +} diff --git a/lib/classes/exception/require_login_exception.php b/lib/classes/exception/require_login_exception.php new file mode 100644 index 00000000000..b66dd09b093 --- /dev/null +++ b/lib/classes/exception/require_login_exception.php @@ -0,0 +1,34 @@ +. + +/** + * Course/activity access exception. + * + * This exception is thrown from require_login() + * + * @package core_access + * @copyright 2010 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class require_login_exception extends moodle_exception { + /** + * Constructor + * @param string $debuginfo Information to aid the debugging process + */ + function __construct($debuginfo) { + parent::__construct('requireloginerror', 'error', '', NULL, $debuginfo); + } +} diff --git a/lib/classes/exception/require_login_session_timeout_exception.php b/lib/classes/exception/require_login_session_timeout_exception.php new file mode 100644 index 00000000000..b8519c4a2ac --- /dev/null +++ b/lib/classes/exception/require_login_session_timeout_exception.php @@ -0,0 +1,33 @@ +. + +/** + * Session timeout exception. + * + * This exception is thrown from require_login() + * + * @package core_access + * @copyright 2015 Andrew Nicols + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class require_login_session_timeout_exception extends require_login_exception { + /** + * Constructor + */ + public function __construct() { + moodle_exception::__construct('sessionerroruser', 'error'); + } +} diff --git a/lib/classes/exception/required_capability_exception.php b/lib/classes/exception/required_capability_exception.php new file mode 100644 index 00000000000..9ea1827c3dd --- /dev/null +++ b/lib/classes/exception/required_capability_exception.php @@ -0,0 +1,44 @@ +. + +/** + * Exceptions indicating user does not have permissions to do something + * and the execution can not continue. + * + * @package core_access + * @copyright 2009 Petr Skoda {@link http://skodak.org} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class required_capability_exception extends moodle_exception { + /** + * Constructor + * @param context $context The context used for the capability check + * @param string $capability The required capability + * @param string $errormessage The error message to show the user + * @param string $stringfile + */ + function __construct($context, $capability, $errormessage, $stringfile) { + $capabilityname = get_capability_string($capability); + if ($context->contextlevel == CONTEXT_MODULE and preg_match('/:view$/', $capability)) { + // we can not go to mod/xx/view.php because we most probably do not have cap to view it, let's go to course instead + $parentcontext = $context->get_parent_context(); + $link = $parentcontext->get_url(); + } else { + $link = $context->get_url(); + } + parent::__construct($errormessage, $stringfile, $link, $capabilityname); + } +} diff --git a/lib/classes/exception/webservice_parameter_exception.php b/lib/classes/exception/webservice_parameter_exception.php new file mode 100644 index 00000000000..ef6917cc4a2 --- /dev/null +++ b/lib/classes/exception/webservice_parameter_exception.php @@ -0,0 +1,35 @@ +. + + +/** + * Web service parameter exception class. + * + * @deprecated since Moodle 2.2 - use moodle exception instead + * This exception must be thrown to the web service client when a web service parameter is invalid + * The error string is gotten from webservice.php + */ +class webservice_parameter_exception extends moodle_exception { + /** + * Constructor + * @param string $errorcode The name of the string from webservice.php to print + * @param string $a The name of the parameter + * @param string $debuginfo Optional information to aid debugging + */ + function __construct($errorcode=null, $a = '', $debuginfo = null) { + parent::__construct($errorcode, 'webservice', '', $a, $debuginfo); + } +} diff --git a/lib/classes/output/bootstrap_renderer.php b/lib/classes/output/bootstrap_renderer.php new file mode 100644 index 00000000000..6bc8e1893e2 --- /dev/null +++ b/lib/classes/output/bootstrap_renderer.php @@ -0,0 +1,294 @@ +. + +/** + * This class solves the problem of how to initialise $OUTPUT. + * + * The problem is caused be two factors + *
    + *
  1. On the one hand, we cannot be sure when output will start. In particular, + * an error, which needs to be displayed, could be thrown at any time.
  2. + *
  3. On the other hand, we cannot be sure when we will have all the information + * necessary to correctly initialise $OUTPUT. $OUTPUT depends on the theme, which + * (potentially) depends on the current course, course categories, and logged in user. + * It also depends on whether the current page requires HTTPS.
  4. + *
+ * + * So, it is hard to find a single natural place during Moodle script execution, + * which we can guarantee is the right time to initialise $OUTPUT. Instead we + * adopt the following strategy + *
    + *
  1. We will initialise $OUTPUT the first time it is used.
  2. + *
  3. If, after $OUTPUT has been initialised, the script tries to change something + * that $OUTPUT depends on, we throw an exception making it clear that the script + * did something wrong. + *
+ * + * The only problem with that is, how do we initialise $OUTPUT on first use if, + * it is going to be used like $OUTPUT->somthing(...)? Well that is where this + * class comes in. Initially, we set up $OUTPUT = new bootstrap_renderer(). Then, + * when any method is called on that object, we initialise $OUTPUT, and pass the call on. + * + * Note that this class is used before lib/outputlib.php has been loaded, so we + * must be careful referring to classes/functions from there, they may not be + * defined yet, and we must avoid fatal errors. + * + * @package core + * @copyright 2009 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class bootstrap_renderer { + /** + * Handles re-entrancy. Without this, errors or debugging output that occur + * during the initialisation of $OUTPUT, cause infinite recursion. + * @var boolean + */ + protected $initialising = false; + + /** + * Have we started output yet? + * @return boolean true if the header has been printed. + */ + public function has_started() { + return false; + } + + /** + * Constructor - to be used by core code only. + * @param string $method The method to call + * @param array $arguments Arguments to pass to the method being called + * @return string + */ + public function __call($method, $arguments) { + global $OUTPUT, $PAGE; + + $recursing = false; + if ($method == 'notification') { + // Catch infinite recursion caused by debugging output during print_header. + $backtrace = debug_backtrace(); + array_shift($backtrace); + array_shift($backtrace); + $recursing = is_early_init($backtrace); + } + + $earlymethods = array( + 'fatal_error' => 'early_error', + 'notification' => 'early_notification', + ); + + // If lib/outputlib.php has been loaded, call it. + if (!empty($PAGE) && !$recursing) { + if (array_key_exists($method, $earlymethods)) { + //prevent PAGE->context warnings - exceptions might appear before we set any context + $PAGE->set_context(null); + } + $PAGE->initialise_theme_and_output(); + return call_user_func_array(array($OUTPUT, $method), $arguments); + } + + $this->initialising = true; + + // Too soon to initialise $OUTPUT, provide a couple of key methods. + if (array_key_exists($method, $earlymethods)) { + return call_user_func_array(array('bootstrap_renderer', $earlymethods[$method]), $arguments); + } + + throw new coding_exception('Attempt to start output before enough information is known to initialise the theme.'); + } + + /** + * Returns nicely formatted error message in a div box. + * @static + * @param string $message error message + * @param ?string $moreinfourl (ignored in early errors) + * @param ?string $link (ignored in early errors) + * @param ?array $backtrace + * @param ?string $debuginfo + * @return string + */ + public static function early_error_content($message, $moreinfourl, $link, $backtrace, $debuginfo = null) { + global $CFG; + + $content = "
$message
"; + // Check whether debug is set. + $debug = (!empty($CFG->debug) && $CFG->debug >= DEBUG_DEVELOPER); + // Also check we have it set in the config file. This occurs if the method to read the config table from the + // database fails, reading from the config table is the first database interaction we have. + $debug = $debug || (!empty($CFG->config_php_settings['debug']) && $CFG->config_php_settings['debug'] >= DEBUG_DEVELOPER ); + if ($debug) { + if (!empty($debuginfo)) { + // Remove all nasty JS. + if (function_exists('s')) { // Function may be not available for some early errors. + $debuginfo = s($debuginfo); + } else { + // Because weblib is not available for these early errors, we + // just duplicate s() code here to be safe. + $debuginfo = preg_replace('/&#(\d+|x[0-9a-f]+);/i', '&#$1;', + htmlspecialchars($debuginfo, ENT_QUOTES | ENT_HTML401 | ENT_SUBSTITUTE)); + } + $debuginfo = str_replace("\n", '
', $debuginfo); // keep newlines + $content .= '
Debug info: ' . $debuginfo . '
'; + } + if (!empty($backtrace)) { + $content .= '
Stack trace: ' . format_backtrace($backtrace, false) . '
'; + } + } + + return $content; + } + + /** + * This function should only be called by this class, or from exception handlers + * @static + * @param string $message error message + * @param string $moreinfourl (ignored in early errors) + * @param string $link (ignored in early errors) + * @param array $backtrace + * @param string $debuginfo extra information for developers + * @return ?string + */ + public static function early_error($message, $moreinfourl, $link, $backtrace, $debuginfo = null, $errorcode = null) { + global $CFG; + + if (CLI_SCRIPT) { + echo "!!! $message !!!\n"; + if (!empty($CFG->debug) and $CFG->debug >= DEBUG_DEVELOPER) { + if (!empty($debuginfo)) { + echo "\nDebug info: $debuginfo"; + } + if (!empty($backtrace)) { + echo "\nStack trace: " . format_backtrace($backtrace, true); + } + } + return; + + } else if (AJAX_SCRIPT) { + $e = new stdClass(); + $e->error = $message; + $e->stacktrace = NULL; + $e->debuginfo = NULL; + if (!empty($CFG->debug) and $CFG->debug >= DEBUG_DEVELOPER) { + if (!empty($debuginfo)) { + $e->debuginfo = $debuginfo; + } + if (!empty($backtrace)) { + $e->stacktrace = format_backtrace($backtrace, true); + } + } + $e->errorcode = $errorcode; + @header('Content-Type: application/json; charset=utf-8'); + echo json_encode($e); + return; + } + + // In the name of protocol correctness, monitoring and performance + // profiling, set the appropriate error headers for machine consumption. + $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0'); + @header($protocol . ' 500 Internal Server Error'); + + // better disable any caching + @header('Content-Type: text/html; charset=utf-8'); + @header('X-UA-Compatible: IE=edge'); + @header('Cache-Control: no-store, no-cache, must-revalidate'); + @header('Cache-Control: post-check=0, pre-check=0', false); + @header('Pragma: no-cache'); + @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT'); + @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + + if (function_exists('get_string')) { + $strerror = get_string('error'); + } else { + $strerror = 'Error'; + } + + $content = self::early_error_content($message, $moreinfourl, $link, $backtrace, $debuginfo); + + return self::plain_page($strerror, $content); + } + + /** + * Early notification message + * @static + * @param string $message + * @param string $classes usually notifyproblem or notifysuccess + * @return string + */ + public static function early_notification($message, $classes = 'notifyproblem') { + return '
' . $message . '
'; + } + + /** + * Page should redirect message. + * @static + * @param string $encodedurl redirect url + * @return string + */ + public static function plain_redirect_message($encodedurl) { + $message = '
' . get_string('pageshouldredirect') . '
'. get_string('continue') .'
'; + return self::plain_page(get_string('redirect'), $message); + } + + /** + * Early redirection page, used before full init of $PAGE global + * @static + * @param string $encodedurl redirect url + * @param string $message redirect message + * @param int $delay time in seconds + * @return string redirect page + */ + public static function early_redirect_message($encodedurl, $message, $delay) { + $meta = ''; + $content = self::early_error_content($message, null, null, null); + $content .= self::plain_redirect_message($encodedurl); + + return self::plain_page(get_string('redirect'), $content, $meta); + } + + /** + * Output basic html page. + * @static + * @param string $title page title + * @param string $content page content + * @param string $meta meta tag + * @return string html page + */ + public static function plain_page($title, $content, $meta = '') { + global $CFG; + + if (function_exists('get_string') && function_exists('get_html_lang')) { + $htmllang = get_html_lang(); + } else { + $htmllang = ''; + } + + $footer = ''; + if (function_exists('get_performance_info')) { // Function may be not available for some early errors. + if (MDL_PERF_TEST) { + $perfinfo = get_performance_info(); + $footer = ''; + } + } + + ob_start(); + include($CFG->dirroot . '/error/plainpage.php'); + $html = ob_get_contents(); + ob_end_clean(); + + return $html; + } +} diff --git a/lib/db/legacyclasses.php b/lib/db/legacyclasses.php new file mode 100644 index 00000000000..ea85c4f63e2 --- /dev/null +++ b/lib/db/legacyclasses.php @@ -0,0 +1,45 @@ +. + +/** + * This file contains mappings for legacy classes that do not fit the standard class naming conventions. + * + * In time these classes should be renamed to fit the standard class naming conventions but this is not an overnight process. + * + * @package core + * @copyright Andrew Lyons + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +// Like other files in the db directory this file uses an array. +// The old class name is the key, the path to the file containing the class is the vlaue. +// The array must be called $legacyclasses. +$legacyclasses = [ + \bootstrap_renderer::class => 'output\bootstrap_renderer', + \coding_exception::class => 'exception/coding_exception.php', + \file_serving_exception::class => 'exception/file_serving_exception.php', + \invalid_dataroot_permissions::class => 'exception/invalid_dataroot_permissions.php', + \invalid_parameter_exception::class => 'exception/invalid_parameter_exception.php', + \invalid_response_exception::class => 'exception/invalid_response_exception.php', + \invalid_state_exception::class => 'exception/invalid_state_exception.php', + \moodle_exception::class => 'exception/moodle_exception.php', + \require_login_exception::class => 'exception/require_login_exception.php', + \require_login_session_timeout_exception::class => 'exception/require_login_session_timeout_exception.php', + \required_capability_exception::class => 'exception/required_capability_exception.php', + \webservice_parameter_exception::class => 'exception/webservice_parameter_exception.php', +]; diff --git a/lib/setup.php b/lib/setup.php index 81c7658e9fe..da284a7422d 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -620,6 +620,10 @@ if (defined('ABORT_AFTER_CONFIG')) { require_once($CFG->libdir .'/setuplib.php'); // Functions that MUST be loaded first. +// TODO MDL-81933 Remove after Moodle 4.5 release. +require_once($CFG->libdir . '/classes/exception/moodle_exception.php'); // Required by some other legacy libraries. +require_once($CFG->libdir . '/classes/output/bootstrap_renderer.php'); // Required by some other legacy libraries. + // Load up standard libraries. require_once($CFG->libdir .'/filterlib.php'); // Functions for filtering test as it is output. require_once($CFG->libdir .'/ajax/ajaxlib.php'); // Functions for managing our use of JavaScript and YUI. diff --git a/lib/setuplib.php b/lib/setuplib.php index 62b72477c9a..470a15a924e 100644 --- a/lib/setuplib.php +++ b/lib/setuplib.php @@ -51,298 +51,6 @@ define('MEMORY_EXTRA', -3); /** Extremely large memory limit - not recommended for standard scripts */ define('MEMORY_HUGE', -4); -/** - * Base Moodle Exception class - * - * Although this class is defined here, you cannot throw a moodle_exception until - * after moodlelib.php has been included (which will happen very soon). - * - * @package core - * @subpackage lib - * @copyright 2008 Petr Skoda {@link http://skodak.org} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class moodle_exception extends Exception { - - /** - * @var string The name of the string from error.php to print - */ - public $errorcode; - - /** - * @var string The name of module - */ - public $module; - - /** - * @var mixed Extra words and phrases that might be required in the error string - */ - public $a; - - /** - * @var string The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page. - */ - public $link; - - /** - * @var string Optional information to aid the debugging process - */ - public $debuginfo; - - /** - * Constructor - * @param string $errorcode The name of the string from error.php to print - * @param string $module name of module - * @param string $link The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page. - * @param mixed $a Extra words and phrases that might be required in the error string - * @param string $debuginfo optional debugging information - */ - function __construct($errorcode, $module='', $link='', $a=NULL, $debuginfo=null) { - global $CFG; - - if (empty($module) || $module == 'moodle' || $module == 'core') { - $module = 'error'; - } - - $this->errorcode = $errorcode; - $this->module = $module; - $this->link = $link; - $this->a = $a; - $this->debuginfo = is_null($debuginfo) ? null : (string)$debuginfo; - - if (get_string_manager()->string_exists($errorcode, $module)) { - $message = get_string($errorcode, $module, $a); - $haserrorstring = true; - } else { - $message = $module . '/' . $errorcode; - $haserrorstring = false; - } - - $isinphpunittest = (defined('PHPUNIT_TEST') && PHPUNIT_TEST); - $hasdebugdeveloper = ( - isset($CFG->debugdisplay) && - isset($CFG->debug) && - $CFG->debugdisplay && - $CFG->debug === DEBUG_DEVELOPER - ); - - if ($debuginfo) { - if ($isinphpunittest || $hasdebugdeveloper) { - $message = "$message ($debuginfo)"; - } - } - - if (!$haserrorstring and $isinphpunittest) { - // Append the contents of $a to $debuginfo so helpful information isn't lost. - // This emulates what {@link get_exception_info()} does. Unfortunately that - // function is not used by phpunit. - $message .= PHP_EOL.'$a contents: '.print_r($a, true); - } - - parent::__construct($message, 0); - } -} - -/** - * Course/activity access exception. - * - * This exception is thrown from require_login() - * - * @package core_access - * @copyright 2010 Petr Skoda {@link http://skodak.org} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class require_login_exception extends moodle_exception { - /** - * Constructor - * @param string $debuginfo Information to aid the debugging process - */ - function __construct($debuginfo) { - parent::__construct('requireloginerror', 'error', '', NULL, $debuginfo); - } -} - -/** - * Session timeout exception. - * - * This exception is thrown from require_login() - * - * @package core_access - * @copyright 2015 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class require_login_session_timeout_exception extends require_login_exception { - /** - * Constructor - */ - public function __construct() { - moodle_exception::__construct('sessionerroruser', 'error'); - } -} - -/** - * Web service parameter exception class - * @deprecated since Moodle 2.2 - use moodle exception instead - * This exception must be thrown to the web service client when a web service parameter is invalid - * The error string is gotten from webservice.php - */ -class webservice_parameter_exception extends moodle_exception { - /** - * Constructor - * @param string $errorcode The name of the string from webservice.php to print - * @param string $a The name of the parameter - * @param string $debuginfo Optional information to aid debugging - */ - function __construct($errorcode=null, $a = '', $debuginfo = null) { - parent::__construct($errorcode, 'webservice', '', $a, $debuginfo); - } -} - -/** - * Exceptions indicating user does not have permissions to do something - * and the execution can not continue. - * - * @package core_access - * @copyright 2009 Petr Skoda {@link http://skodak.org} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class required_capability_exception extends moodle_exception { - /** - * Constructor - * @param context $context The context used for the capability check - * @param string $capability The required capability - * @param string $errormessage The error message to show the user - * @param string $stringfile - */ - function __construct($context, $capability, $errormessage, $stringfile) { - $capabilityname = get_capability_string($capability); - if ($context->contextlevel == CONTEXT_MODULE and preg_match('/:view$/', $capability)) { - // we can not go to mod/xx/view.php because we most probably do not have cap to view it, let's go to course instead - $parentcontext = $context->get_parent_context(); - $link = $parentcontext->get_url(); - } else { - $link = $context->get_url(); - } - parent::__construct($errormessage, $stringfile, $link, $capabilityname); - } -} - -/** - * Exception indicating programming error, must be fixed by a programer. For example - * a core API might throw this type of exception if a plugin calls it incorrectly. - * - * @package core - * @subpackage lib - * @copyright 2008 Petr Skoda {@link http://skodak.org} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class coding_exception extends moodle_exception { - /** - * Constructor - * @param string $hint short description of problem - * @param string $debuginfo detailed information how to fix problem - */ - function __construct($hint, $debuginfo=null) { - parent::__construct('codingerror', 'debug', '', $hint, $debuginfo); - } -} - -/** - * Exception indicating malformed parameter problem. - * This exception is not supposed to be thrown when processing - * user submitted data in forms. It is more suitable - * for WS and other low level stuff. - * - * @package core - * @subpackage lib - * @copyright 2009 Petr Skoda {@link http://skodak.org} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class invalid_parameter_exception extends moodle_exception { - /** - * Constructor - * @param string $debuginfo some detailed information - */ - function __construct($debuginfo=null) { - parent::__construct('invalidparameter', 'debug', '', null, $debuginfo); - } -} - -/** - * Exception indicating malformed response problem. - * This exception is not supposed to be thrown when processing - * user submitted data in forms. It is more suitable - * for WS and other low level stuff. - */ -class invalid_response_exception extends moodle_exception { - /** - * Constructor - * @param string $debuginfo some detailed information - */ - function __construct($debuginfo=null) { - parent::__construct('invalidresponse', 'debug', '', null, $debuginfo); - } -} - -/** - * An exception that indicates something really weird happened. For example, - * if you do switch ($context->contextlevel), and have one case for each - * CONTEXT_... constant. You might throw an invalid_state_exception in the - * default case, to just in case something really weird is going on, and - * $context->contextlevel is invalid - rather than ignoring this possibility. - * - * @package core - * @subpackage lib - * @copyright 2009 onwards Martin Dougiamas {@link http://moodle.com} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class invalid_state_exception extends moodle_exception { - /** - * Constructor - * @param string $hint short description of problem - * @param string $debuginfo optional more detailed information - */ - function __construct($hint, $debuginfo=null) { - parent::__construct('invalidstatedetected', 'debug', '', $hint, $debuginfo); - } -} - -/** - * An exception that indicates incorrect permissions in $CFG->dataroot - * - * @package core - * @subpackage lib - * @copyright 2010 Petr Skoda {@link http://skodak.org} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class invalid_dataroot_permissions extends moodle_exception { - /** - * Constructor - * @param string $debuginfo optional more detailed information - */ - function __construct($debuginfo = NULL) { - parent::__construct('invaliddatarootpermissions', 'error', '', NULL, $debuginfo); - } -} - -/** - * An exception that indicates that file can not be served - * - * @package core - * @subpackage lib - * @copyright 2010 Petr Skoda {@link http://skodak.org} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class file_serving_exception extends moodle_exception { - /** - * Constructor - * @param string $debuginfo optional more detailed information - */ - function __construct($debuginfo = NULL) { - parent::__construct('cannotservefile', 'error', '', NULL, $debuginfo); - } -} - /** * Get the Whoops! handler. * @@ -1948,283 +1656,6 @@ function set_access_log_user() { } } -/** - * This class solves the problem of how to initialise $OUTPUT. - * - * The problem is caused be two factors - *
    - *
  1. On the one hand, we cannot be sure when output will start. In particular, - * an error, which needs to be displayed, could be thrown at any time.
  2. - *
  3. On the other hand, we cannot be sure when we will have all the information - * necessary to correctly initialise $OUTPUT. $OUTPUT depends on the theme, which - * (potentially) depends on the current course, course categories, and logged in user. - * It also depends on whether the current page requires HTTPS.
  4. - *
- * - * So, it is hard to find a single natural place during Moodle script execution, - * which we can guarantee is the right time to initialise $OUTPUT. Instead we - * adopt the following strategy - *
    - *
  1. We will initialise $OUTPUT the first time it is used.
  2. - *
  3. If, after $OUTPUT has been initialised, the script tries to change something - * that $OUTPUT depends on, we throw an exception making it clear that the script - * did something wrong. - *
- * - * The only problem with that is, how do we initialise $OUTPUT on first use if, - * it is going to be used like $OUTPUT->somthing(...)? Well that is where this - * class comes in. Initially, we set up $OUTPUT = new bootstrap_renderer(). Then, - * when any method is called on that object, we initialise $OUTPUT, and pass the call on. - * - * Note that this class is used before lib/outputlib.php has been loaded, so we - * must be careful referring to classes/functions from there, they may not be - * defined yet, and we must avoid fatal errors. - * - * @copyright 2009 Tim Hunt - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since Moodle 2.0 - */ -class bootstrap_renderer { - /** - * Handles re-entrancy. Without this, errors or debugging output that occur - * during the initialisation of $OUTPUT, cause infinite recursion. - * @var boolean - */ - protected $initialising = false; - - /** - * Have we started output yet? - * @return boolean true if the header has been printed. - */ - public function has_started() { - return false; - } - - /** - * Constructor - to be used by core code only. - * @param string $method The method to call - * @param array $arguments Arguments to pass to the method being called - * @return string - */ - public function __call($method, $arguments) { - global $OUTPUT, $PAGE; - - $recursing = false; - if ($method == 'notification') { - // Catch infinite recursion caused by debugging output during print_header. - $backtrace = debug_backtrace(); - array_shift($backtrace); - array_shift($backtrace); - $recursing = is_early_init($backtrace); - } - - $earlymethods = array( - 'fatal_error' => 'early_error', - 'notification' => 'early_notification', - ); - - // If lib/outputlib.php has been loaded, call it. - if (!empty($PAGE) && !$recursing) { - if (array_key_exists($method, $earlymethods)) { - //prevent PAGE->context warnings - exceptions might appear before we set any context - $PAGE->set_context(null); - } - $PAGE->initialise_theme_and_output(); - return call_user_func_array(array($OUTPUT, $method), $arguments); - } - - $this->initialising = true; - - // Too soon to initialise $OUTPUT, provide a couple of key methods. - if (array_key_exists($method, $earlymethods)) { - return call_user_func_array(array('bootstrap_renderer', $earlymethods[$method]), $arguments); - } - - throw new coding_exception('Attempt to start output before enough information is known to initialise the theme.'); - } - - /** - * Returns nicely formatted error message in a div box. - * @static - * @param string $message error message - * @param ?string $moreinfourl (ignored in early errors) - * @param ?string $link (ignored in early errors) - * @param ?array $backtrace - * @param ?string $debuginfo - * @return string - */ - public static function early_error_content($message, $moreinfourl, $link, $backtrace, $debuginfo = null) { - global $CFG; - - $content = "
$message
"; - // Check whether debug is set. - $debug = (!empty($CFG->debug) && $CFG->debug >= DEBUG_DEVELOPER); - // Also check we have it set in the config file. This occurs if the method to read the config table from the - // database fails, reading from the config table is the first database interaction we have. - $debug = $debug || (!empty($CFG->config_php_settings['debug']) && $CFG->config_php_settings['debug'] >= DEBUG_DEVELOPER ); - if ($debug) { - if (!empty($debuginfo)) { - // Remove all nasty JS. - if (function_exists('s')) { // Function may be not available for some early errors. - $debuginfo = s($debuginfo); - } else { - // Because weblib is not available for these early errors, we - // just duplicate s() code here to be safe. - $debuginfo = preg_replace('/&#(\d+|x[0-9a-f]+);/i', '&#$1;', - htmlspecialchars($debuginfo, ENT_QUOTES | ENT_HTML401 | ENT_SUBSTITUTE)); - } - $debuginfo = str_replace("\n", '
', $debuginfo); // keep newlines - $content .= '
Debug info: ' . $debuginfo . '
'; - } - if (!empty($backtrace)) { - $content .= '
Stack trace: ' . format_backtrace($backtrace, false) . '
'; - } - } - - return $content; - } - - /** - * This function should only be called by this class, or from exception handlers - * @static - * @param string $message error message - * @param string $moreinfourl (ignored in early errors) - * @param string $link (ignored in early errors) - * @param array $backtrace - * @param string $debuginfo extra information for developers - * @return ?string - */ - public static function early_error($message, $moreinfourl, $link, $backtrace, $debuginfo = null, $errorcode = null) { - global $CFG; - - if (CLI_SCRIPT) { - echo "!!! $message !!!\n"; - if (!empty($CFG->debug) and $CFG->debug >= DEBUG_DEVELOPER) { - if (!empty($debuginfo)) { - echo "\nDebug info: $debuginfo"; - } - if (!empty($backtrace)) { - echo "\nStack trace: " . format_backtrace($backtrace, true); - } - } - return; - - } else if (AJAX_SCRIPT) { - $e = new stdClass(); - $e->error = $message; - $e->stacktrace = NULL; - $e->debuginfo = NULL; - if (!empty($CFG->debug) and $CFG->debug >= DEBUG_DEVELOPER) { - if (!empty($debuginfo)) { - $e->debuginfo = $debuginfo; - } - if (!empty($backtrace)) { - $e->stacktrace = format_backtrace($backtrace, true); - } - } - $e->errorcode = $errorcode; - @header('Content-Type: application/json; charset=utf-8'); - echo json_encode($e); - return; - } - - // In the name of protocol correctness, monitoring and performance - // profiling, set the appropriate error headers for machine consumption. - $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0'); - @header($protocol . ' 500 Internal Server Error'); - - // better disable any caching - @header('Content-Type: text/html; charset=utf-8'); - @header('X-UA-Compatible: IE=edge'); - @header('Cache-Control: no-store, no-cache, must-revalidate'); - @header('Cache-Control: post-check=0, pre-check=0', false); - @header('Pragma: no-cache'); - @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT'); - @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); - - if (function_exists('get_string')) { - $strerror = get_string('error'); - } else { - $strerror = 'Error'; - } - - $content = self::early_error_content($message, $moreinfourl, $link, $backtrace, $debuginfo); - - return self::plain_page($strerror, $content); - } - - /** - * Early notification message - * @static - * @param string $message - * @param string $classes usually notifyproblem or notifysuccess - * @return string - */ - public static function early_notification($message, $classes = 'notifyproblem') { - return '
' . $message . '
'; - } - - /** - * Page should redirect message. - * @static - * @param string $encodedurl redirect url - * @return string - */ - public static function plain_redirect_message($encodedurl) { - $message = '
' . get_string('pageshouldredirect') . '
'. get_string('continue') .'
'; - return self::plain_page(get_string('redirect'), $message); - } - - /** - * Early redirection page, used before full init of $PAGE global - * @static - * @param string $encodedurl redirect url - * @param string $message redirect message - * @param int $delay time in seconds - * @return string redirect page - */ - public static function early_redirect_message($encodedurl, $message, $delay) { - $meta = ''; - $content = self::early_error_content($message, null, null, null); - $content .= self::plain_redirect_message($encodedurl); - - return self::plain_page(get_string('redirect'), $content, $meta); - } - - /** - * Output basic html page. - * @static - * @param string $title page title - * @param string $content page content - * @param string $meta meta tag - * @return string html page - */ - public static function plain_page($title, $content, $meta = '') { - global $CFG; - - if (function_exists('get_string') && function_exists('get_html_lang')) { - $htmllang = get_html_lang(); - } else { - $htmllang = ''; - } - - $footer = ''; - if (function_exists('get_performance_info')) { // Function may be not available for some early errors. - if (MDL_PERF_TEST) { - $perfinfo = get_performance_info(); - $footer = ''; - } - } - - ob_start(); - include($CFG->dirroot . '/error/plainpage.php'); - $html = ob_get_contents(); - ob_end_clean(); - - return $html; - } -} /** * Add http stream instrumentation