Search moodle.org's
Developer Documentation


  • Bug fixes for general core bugs in 2.8.x ended 9 November 2015 (12 months).
  • Bug fixes for security issues in 2.8.x ended 9 May 2016 (18 months).
  • minimum PHP 5.4.4 (always use latest PHP 5.4.x or 5.5.x on Windows - http://windows.php.net/download/), PHP 7 is NOT supported
  • /lib/ -> setuplib.php (source)

    Differences Between: [Versions 28 and 29] [Versions 28 and 30] [Versions 28 and 31] [Versions 28 and 32] [Versions 28 and 33] [Versions 28 and 34] [Versions 28 and 35] [Versions 28 and 36] [Versions 28 and 37]

       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   * These functions are required very early in the Moodle
      19   * setup process, before any of the main libraries are
      20   * loaded.
      21   *
      22   * @package    core
      23   * @subpackage lib
      24   * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
      25   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      26   */
      27  
      28  defined('MOODLE_INTERNAL') || die();
      29  
      30  // Debug levels - always keep the values in ascending order!
      31  /** No warnings and errors at all */
      32  define('DEBUG_NONE', 0);
      33  /** Fatal errors only */
      34  define('DEBUG_MINIMAL', E_ERROR | E_PARSE);
      35  /** Errors, warnings and notices */
      36  define('DEBUG_NORMAL', E_ERROR | E_PARSE | E_WARNING | E_NOTICE);
      37  /** All problems except strict PHP warnings */
      38  define('DEBUG_ALL', E_ALL & ~E_STRICT);
      39  /** DEBUG_ALL with all debug messages and strict warnings */
      40  define('DEBUG_DEVELOPER', E_ALL | E_STRICT);
      41  
      42  /** Remove any memory limits */
      43  define('MEMORY_UNLIMITED', -1);
      44  /** Standard memory limit for given platform */
      45  define('MEMORY_STANDARD', -2);
      46  /**
      47   * Large memory limit for given platform - used in cron, upgrade, and other places that need a lot of memory.
      48   * Can be overridden with $CFG->extramemorylimit setting.
      49   */
      50  define('MEMORY_EXTRA', -3);
      51  /** Extremely large memory limit - not recommended for standard scripts */
      52  define('MEMORY_HUGE', -4);
      53  
      54  
      55  /**
      56   * Simple class. It is usually used instead of stdClass because it looks
      57   * more familiar to Java developers ;-) Do not use for type checking of
      58   * function parameters. Please use stdClass instead.
      59   *
      60   * @package    core
      61   * @subpackage lib
      62   * @copyright  2009 Petr Skoda  {@link http://skodak.org}
      63   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      64   * @deprecated since 2.0
      65   */
      66  class object extends stdClass {};
      67  
      68  /**
      69   * Base Moodle Exception class
      70   *
      71   * Although this class is defined here, you cannot throw a moodle_exception until
      72   * after moodlelib.php has been included (which will happen very soon).
      73   *
      74   * @package    core
      75   * @subpackage lib
      76   * @copyright  2008 Petr Skoda  {@link http://skodak.org}
      77   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      78   */
      79  class moodle_exception extends Exception {
      80  
      81      /**
      82       * @var string The name of the string from error.php to print
      83       */
      84      public $errorcode;
      85  
      86      /**
      87       * @var string The name of module
      88       */
      89      public $module;
      90  
      91      /**
      92       * @var mixed Extra words and phrases that might be required in the error string
      93       */
      94      public $a;
      95  
      96      /**
      97       * @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.
      98       */
      99      public $link;
     100  
     101      /**
     102       * @var string Optional information to aid the debugging process
     103       */
     104      public $debuginfo;
     105  
     106      /**
     107       * Constructor
     108       * @param string $errorcode The name of the string from error.php to print
     109       * @param string $module name of module
     110       * @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.
     111       * @param mixed $a Extra words and phrases that might be required in the error string
     112       * @param string $debuginfo optional debugging information
     113       */
     114      function __construct($errorcode, $module='', $link='', $a=NULL, $debuginfo=null) {
     115          if (empty($module) || $module == 'moodle' || $module == 'core') {
     116              $module = 'error';
     117          }
     118  
     119          $this->errorcode = $errorcode;
     120          $this->module    = $module;
     121          $this->link      = $link;
     122          $this->a         = $a;
     123          $this->debuginfo = is_null($debuginfo) ? null : (string)$debuginfo;
     124  
     125          if (get_string_manager()->string_exists($errorcode, $module)) {
     126              $message = get_string($errorcode, $module, $a);
     127              $haserrorstring = true;
     128          } else {
     129              $message = $module . '/' . $errorcode;
     130              $haserrorstring = false;
     131          }
     132  
     133          if (defined('PHPUNIT_TEST') and PHPUNIT_TEST and $debuginfo) {
     134              $message = "$message ($debuginfo)";
     135          }
     136  
     137          if (!$haserrorstring and defined('PHPUNIT_TEST') and PHPUNIT_TEST) {
     138              // Append the contents of $a to $debuginfo so helpful information isn't lost.
     139              // This emulates what {@link get_exception_info()} does. Unfortunately that
     140              // function is not used by phpunit.
     141              $message .= PHP_EOL.'$a contents: '.print_r($a, true);
     142          }
     143  
     144          parent::__construct($message, 0);
     145      }
     146  }
     147  
     148  /**
     149   * Course/activity access exception.
     150   *
     151   * This exception is thrown from require_login()
     152   *
     153   * @package    core_access
     154   * @copyright  2010 Petr Skoda  {@link http://skodak.org}
     155   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     156   */
     157  class require_login_exception extends moodle_exception {
     158      /**
     159       * Constructor
     160       * @param string $debuginfo Information to aid the debugging process
     161       */
     162      function __construct($debuginfo) {
     163          parent::__construct('requireloginerror', 'error', '', NULL, $debuginfo);
     164      }
     165  }
     166  
     167  /**
     168   * Session timeout exception.
     169   *
     170   * This exception is thrown from require_login()
     171   *
     172   * @package    core_access
     173   * @copyright  2015 Andrew Nicols <andrew@nicols.co.uk>
     174   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     175   */
     176  class require_login_session_timeout_exception extends require_login_exception {
     177      /**
     178       * Constructor
     179       */
     180      public function __construct() {
     181          moodle_exception::__construct('sessionerroruser', 'error');
     182      }
     183  }
     184  
     185  /**
     186   * Web service parameter exception class
     187   * @deprecated since Moodle 2.2 - use moodle exception instead
     188   * This exception must be thrown to the web service client when a web service parameter is invalid
     189   * The error string is gotten from webservice.php
     190   */
     191  class webservice_parameter_exception extends moodle_exception {
     192      /**
     193       * Constructor
     194       * @param string $errorcode The name of the string from webservice.php to print
     195       * @param string $a The name of the parameter
     196       * @param string $debuginfo Optional information to aid debugging
     197       */
     198      function __construct($errorcode=null, $a = '', $debuginfo = null) {
     199          parent::__construct($errorcode, 'webservice', '', $a, $debuginfo);
     200      }
     201  }
     202  
     203  /**
     204   * Exceptions indicating user does not have permissions to do something
     205   * and the execution can not continue.
     206   *
     207   * @package    core_access
     208   * @copyright  2009 Petr Skoda  {@link http://skodak.org}
     209   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     210   */
     211  class required_capability_exception extends moodle_exception {
     212      /**
     213       * Constructor
     214       * @param context $context The context used for the capability check
     215       * @param string $capability The required capability
     216       * @param string $errormessage The error message to show the user
     217       * @param string $stringfile
     218       */
     219      function __construct($context, $capability, $errormessage, $stringfile) {
     220          $capabilityname = get_capability_string($capability);
     221          if ($context->contextlevel == CONTEXT_MODULE and preg_match('/:view$/', $capability)) {
     222              // 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
     223              $parentcontext = $context->get_parent_context();
     224              $link = $parentcontext->get_url();
     225          } else {
     226              $link = $context->get_url();
     227          }
     228          parent::__construct($errormessage, $stringfile, $link, $capabilityname);
     229      }
     230  }
     231  
     232  /**
     233   * Exception indicating programming error, must be fixed by a programer. For example
     234   * a core API might throw this type of exception if a plugin calls it incorrectly.
     235   *
     236   * @package    core
     237   * @subpackage lib
     238   * @copyright  2008 Petr Skoda  {@link http://skodak.org}
     239   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     240   */
     241  class coding_exception extends moodle_exception {
     242      /**
     243       * Constructor
     244       * @param string $hint short description of problem
     245       * @param string $debuginfo detailed information how to fix problem
     246       */
     247      function __construct($hint, $debuginfo=null) {
     248          parent::__construct('codingerror', 'debug', '', $hint, $debuginfo);
     249      }
     250  }
     251  
     252  /**
     253   * Exception indicating malformed parameter problem.
     254   * This exception is not supposed to be thrown when processing
     255   * user submitted data in forms. It is more suitable
     256   * for WS and other low level stuff.
     257   *
     258   * @package    core
     259   * @subpackage lib
     260   * @copyright  2009 Petr Skoda  {@link http://skodak.org}
     261   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     262   */
     263  class invalid_parameter_exception extends moodle_exception {
     264      /**
     265       * Constructor
     266       * @param string $debuginfo some detailed information
     267       */
     268      function __construct($debuginfo=null) {
     269          parent::__construct('invalidparameter', 'debug', '', null, $debuginfo);
     270      }
     271  }
     272  
     273  /**
     274   * Exception indicating malformed response problem.
     275   * This exception is not supposed to be thrown when processing
     276   * user submitted data in forms. It is more suitable
     277   * for WS and other low level stuff.
     278   */
     279  class invalid_response_exception extends moodle_exception {
     280      /**
     281       * Constructor
     282       * @param string $debuginfo some detailed information
     283       */
     284      function __construct($debuginfo=null) {
     285          parent::__construct('invalidresponse', 'debug', '', null, $debuginfo);
     286      }
     287  }
     288  
     289  /**
     290   * An exception that indicates something really weird happened. For example,
     291   * if you do switch ($context->contextlevel), and have one case for each
     292   * CONTEXT_... constant. You might throw an invalid_state_exception in the
     293   * default case, to just in case something really weird is going on, and
     294   * $context->contextlevel is invalid - rather than ignoring this possibility.
     295   *
     296   * @package    core
     297   * @subpackage lib
     298   * @copyright  2009 onwards Martin Dougiamas  {@link http://moodle.com}
     299   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     300   */
     301  class invalid_state_exception extends moodle_exception {
     302      /**
     303       * Constructor
     304       * @param string $hint short description of problem
     305       * @param string $debuginfo optional more detailed information
     306       */
     307      function __construct($hint, $debuginfo=null) {
     308          parent::__construct('invalidstatedetected', 'debug', '', $hint, $debuginfo);
     309      }
     310  }
     311  
     312  /**
     313   * An exception that indicates incorrect permissions in $CFG->dataroot
     314   *
     315   * @package    core
     316   * @subpackage lib
     317   * @copyright  2010 Petr Skoda {@link http://skodak.org}
     318   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     319   */
     320  class invalid_dataroot_permissions extends moodle_exception {
     321      /**
     322       * Constructor
     323       * @param string $debuginfo optional more detailed information
     324       */
     325      function __construct($debuginfo = NULL) {
     326          parent::__construct('invaliddatarootpermissions', 'error', '', NULL, $debuginfo);
     327      }
     328  }
     329  
     330  /**
     331   * An exception that indicates that file can not be served
     332   *
     333   * @package    core
     334   * @subpackage lib
     335   * @copyright  2010 Petr Skoda {@link http://skodak.org}
     336   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     337   */
     338  class file_serving_exception extends moodle_exception {
     339      /**
     340       * Constructor
     341       * @param string $debuginfo optional more detailed information
     342       */
     343      function __construct($debuginfo = NULL) {
     344          parent::__construct('cannotservefile', 'error', '', NULL, $debuginfo);
     345      }
     346  }
     347  
     348  /**
     349   * Default exception handler, uncaught exceptions are equivalent to error() in 1.9 and earlier
     350   *
     351   * @param Exception $ex
     352   * @return void -does not return. Terminates execution!
     353   */
     354  function default_exception_handler($ex) {
     355      global $CFG, $DB, $OUTPUT, $USER, $FULLME, $SESSION, $PAGE;
     356  
     357      // detect active db transactions, rollback and log as error
     358      abort_all_db_transactions();
     359  
     360      if (($ex instanceof required_capability_exception) && !CLI_SCRIPT && !AJAX_SCRIPT && !empty($CFG->autologinguests) && !empty($USER->autologinguest)) {
     361          $SESSION->wantsurl = qualified_me();
     362          redirect(get_login_url());
     363      }
     364  
     365      $info = get_exception_info($ex);
     366  
     367      if (debugging('', DEBUG_MINIMAL)) {
     368          $logerrmsg = "Default exception handler: ".$info->message.' Debug: '.$info->debuginfo."\n".format_backtrace($info->backtrace, true);
     369          error_log($logerrmsg);
     370      }
     371  
     372      if (is_early_init($info->backtrace)) {
     373          echo bootstrap_renderer::early_error($info->message, $info->moreinfourl, $info->link, $info->backtrace, $info->debuginfo, $info->errorcode);
     374      } else {
     375          try {
     376              if ($DB) {
     377                  // If you enable db debugging and exception is thrown, the print footer prints a lot of rubbish
     378                  $DB->set_debug(0);
     379              }
     380              echo $OUTPUT->fatal_error($info->message, $info->moreinfourl, $info->link, $info->backtrace, $info->debuginfo);
     381          } catch (Exception $out_ex) {
     382              // default exception handler MUST not throw any exceptions!!
     383              // the problem here is we do not know if page already started or not, we only know that somebody messed up in outputlib or theme
     384              // so we just print at least something instead of "Exception thrown without a stack frame in Unknown on line 0":-(
     385              if (CLI_SCRIPT or AJAX_SCRIPT) {
     386                  // just ignore the error and send something back using the safest method
     387                  echo bootstrap_renderer::early_error($info->message, $info->moreinfourl, $info->link, $info->backtrace, $info->debuginfo, $info->errorcode);
     388              } else {
     389                  echo bootstrap_renderer::early_error_content($info->message, $info->moreinfourl, $info->link, $info->backtrace, $info->debuginfo);
     390                  $outinfo = get_exception_info($out_ex);
     391                  echo bootstrap_renderer::early_error_content($outinfo->message, $outinfo->moreinfourl, $outinfo->link, $outinfo->backtrace, $outinfo->debuginfo);
     392              }
     393          }
     394      }
     395  
     396      exit(1); // General error code
     397  }
     398  
     399  /**
     400   * Default error handler, prevents some white screens.
     401   * @param int $errno
     402   * @param string $errstr
     403   * @param string $errfile
     404   * @param int $errline
     405   * @param array $errcontext
     406   * @return bool false means use default error handler
     407   */
     408  function default_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
     409      if ($errno == 4096) {
     410          //fatal catchable error
     411          throw new coding_exception('PHP catchable fatal error', $errstr);
     412      }
     413      return false;
     414  }
     415  
     416  /**
     417   * Unconditionally abort all database transactions, this function
     418   * should be called from exception handlers only.
     419   * @return void
     420   */
     421  function abort_all_db_transactions() {
     422      global $CFG, $DB, $SCRIPT;
     423  
     424      // default exception handler MUST not throw any exceptions!!
     425  
     426      if ($DB && $DB->is_transaction_started()) {
     427          error_log('Database transaction aborted automatically in ' . $CFG->dirroot . $SCRIPT);
     428          // note: transaction blocks should never change current $_SESSION
     429          $DB->force_transaction_rollback();
     430      }
     431  }
     432  
     433  /**
     434   * This function encapsulates the tests for whether an exception was thrown in
     435   * early init -- either during setup.php or during init of $OUTPUT.
     436   *
     437   * If another exception is thrown then, and if we do not take special measures,
     438   * we would just get a very cryptic message "Exception thrown without a stack
     439   * frame in Unknown on line 0". That makes debugging very hard, so we do take
     440   * special measures in default_exception_handler, with the help of this function.
     441   *
     442   * @param array $backtrace the stack trace to analyse.
     443   * @return boolean whether the stack trace is somewhere in output initialisation.
     444   */
     445  function is_early_init($backtrace) {
     446      $dangerouscode = array(
     447          array('function' => 'header', 'type' => '->'),
     448          array('class' => 'bootstrap_renderer'),
     449          array('file' => dirname(__FILE__).'/setup.php'),
     450      );
     451      foreach ($backtrace as $stackframe) {
     452          foreach ($dangerouscode as $pattern) {
     453              $matches = true;
     454              foreach ($pattern as $property => $value) {
     455                  if (!isset($stackframe[$property]) || $stackframe[$property] != $value) {
     456                      $matches = false;
     457                  }
     458              }
     459              if ($matches) {
     460                  return true;
     461              }
     462          }
     463      }
     464      return false;
     465  }
     466  
     467  /**
     468   * Abort execution by throwing of a general exception,
     469   * default exception handler displays the error message in most cases.
     470   *
     471   * @param string $errorcode The name of the language string containing the error message.
     472   *      Normally this should be in the error.php lang file.
     473   * @param string $module The language file to get the error message from.
     474   * @param string $link The url where the user will be prompted to continue.
     475   *      If no url is provided the user will be directed to the site index page.
     476   * @param object $a Extra words and phrases that might be required in the error string
     477   * @param string $debuginfo optional debugging information
     478   * @return void, always throws exception!
     479   */
     480  function print_error($errorcode, $module = 'error', $link = '', $a = null, $debuginfo = null) {
     481      throw new moodle_exception($errorcode, $module, $link, $a, $debuginfo);
     482  }
     483  
     484  /**
     485   * Returns detailed information about specified exception.
     486   * @param exception $ex
     487   * @return object
     488   */
     489  function get_exception_info($ex) {
     490      global $CFG, $DB, $SESSION;
     491  
     492      if ($ex instanceof moodle_exception) {
     493          $errorcode = $ex->errorcode;
     494          $module = $ex->module;
     495          $a = $ex->a;
     496          $link = $ex->link;
     497          $debuginfo = $ex->debuginfo;
     498      } else {
     499          $errorcode = 'generalexceptionmessage';
     500          $module = 'error';
     501          $a = $ex->getMessage();
     502          $link = '';
     503          $debuginfo = '';
     504      }
     505  
     506      // Append the error code to the debug info to make grepping and googling easier
     507      $debuginfo .= PHP_EOL."Error code: $errorcode";
     508  
     509      $backtrace = $ex->getTrace();
     510      $place = array('file'=>$ex->getFile(), 'line'=>$ex->getLine(), 'exception'=>get_class($ex));
     511      array_unshift($backtrace, $place);
     512  
     513      // Be careful, no guarantee moodlelib.php is loaded.
     514      if (empty($module) || $module == 'moodle' || $module == 'core') {
     515          $module = 'error';
     516      }
     517      // Search for the $errorcode's associated string
     518      // If not found, append the contents of $a to $debuginfo so helpful information isn't lost
     519      if (function_exists('get_string_manager')) {
     520          if (get_string_manager()->string_exists($errorcode, $module)) {
     521              $message = get_string($errorcode, $module, $a);
     522          } elseif ($module == 'error' && get_string_manager()->string_exists($errorcode, 'moodle')) {
     523              // Search in moodle file if error specified - needed for backwards compatibility
     524              $message = get_string($errorcode, 'moodle', $a);
     525          } else {
     526              $message = $module . '/' . $errorcode;
     527              $debuginfo .= PHP_EOL.'$a contents: '.print_r($a, true);
     528          }
     529      } else {
     530          $message = $module . '/' . $errorcode;
     531          $debuginfo .= PHP_EOL.'$a contents: '.print_r($a, true);
     532      }
     533  
     534      // Remove some absolute paths from message and debugging info.
     535      $searches = array();
     536      $replaces = array();
     537      $cfgnames = array('tempdir', 'cachedir', 'localcachedir', 'themedir', 'dataroot', 'dirroot');
     538      foreach ($cfgnames as $cfgname) {
     539          if (property_exists($CFG, $cfgname)) {
     540              $searches[] = $CFG->$cfgname;
     541              $replaces[] = "[$cfgname]";
     542          }
     543      }
     544      if (!empty($searches)) {
     545          $message   = str_replace($searches, $replaces, $message);
     546          $debuginfo = str_replace($searches, $replaces, $debuginfo);
     547      }
     548  
     549      // Be careful, no guarantee weblib.php is loaded.
     550      if (function_exists('clean_text')) {
     551          $message = clean_text($message);
     552      } else {
     553          $message = htmlspecialchars($message);
     554      }
     555  
     556      if (!empty($CFG->errordocroot)) {
     557          $errordoclink = $CFG->errordocroot . '/en/';
     558      } else {
     559          $errordoclink = get_docs_url();
     560      }
     561  
     562      if ($module === 'error') {
     563          $modulelink = 'moodle';
     564      } else {
     565          $modulelink = $module;
     566      }
     567      $moreinfourl = $errordoclink . 'error/' . $modulelink . '/' . $errorcode;
     568  
     569      if (empty($link)) {
     570          if (!empty($SESSION->fromurl)) {
     571              $link = $SESSION->fromurl;
     572              unset($SESSION->fromurl);
     573          } else {
     574              $link = $CFG->wwwroot .'/';
     575          }
     576      }
     577  
     578      // When printing an error the continue button should never link offsite.
     579      // We cannot use clean_param() here as it is not guaranteed that it has been loaded yet.
     580      $httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot);
     581      if (stripos($link, $CFG->wwwroot) === 0) {
     582          // Internal HTTP, all good.
     583      } else if (!empty($CFG->loginhttps) && stripos($link, $httpswwwroot) === 0) {
     584          // Internal HTTPS, all good.
     585      } else {
     586          // External link spotted!
     587          $link = $CFG->wwwroot . '/';
     588      }
     589  
     590      $info = new stdClass();
     591      $info->message     = $message;
     592      $info->errorcode   = $errorcode;
     593      $info->backtrace   = $backtrace;
     594      $info->link        = $link;
     595      $info->moreinfourl = $moreinfourl;
     596      $info->a           = $a;
     597      $info->debuginfo   = $debuginfo;
     598  
     599      return $info;
     600  }
     601  
     602  /**
     603   * Returns the Moodle Docs URL in the users language for a given 'More help' link.
     604   *
     605   * There are three cases:
     606   *
     607   * 1. In the normal case, $path will be a short relative path 'component/thing',
     608   * like 'mod/folder/view' 'group/import'. This gets turned into an link to
     609   * MoodleDocs in the user's language, and for the appropriate Moodle version.
     610   * E.g. 'group/import' may become 'http://docs.moodle.org/2x/en/group/import'.
     611   * The 'http://docs.moodle.org' bit comes from $CFG->docroot.
     612   *
     613   * This is the only option that should be used in standard Moodle code. The other
     614   * two options have been implemented because they are useful for third-party plugins.
     615   *
     616   * 2. $path may be an absolute URL, starting http:// or https://. In this case,
     617   * the link is used as is.
     618   *
     619   * 3. $path may start %%WWWROOT%%, in which case that is replaced by
     620   * $CFG->wwwroot to make the link.
     621   *
     622   * @param string $path the place to link to. See above for details.
     623   * @return string The MoodleDocs URL in the user's language. for example @link http://docs.moodle.org/2x/en/$path}
     624   */
     625  function get_docs_url($path = null) {
     626      global $CFG;
     627  
     628      // Absolute URLs are used unmodified.
     629      if (substr($path, 0, 7) === 'http://' || substr($path, 0, 8) === 'https://') {
     630          return $path;
     631      }
     632  
     633      // Paths starting %%WWWROOT%% have that replaced by $CFG->wwwroot.
     634      if (substr($path, 0, 11) === '%%WWWROOT%%') {
     635          return $CFG->wwwroot . substr($path, 11);
     636      }
     637  
     638      // Otherwise we do the normal case, and construct a MoodleDocs URL relative to $CFG->docroot.
     639  
     640      // Check that $CFG->branch has been set up, during installation it won't be.
     641      if (empty($CFG->branch)) {
     642          // It's not there yet so look at version.php.
     643          include($CFG->dirroot.'/version.php');
     644      } else {
     645          // We can use $CFG->branch and avoid having to include version.php.
     646          $branch = $CFG->branch;
     647      }
     648      // ensure branch is valid.
     649      if (!$branch) {
     650          // We should never get here but in case we do lets set $branch to .
     651          // the smart one's will know that this is the current directory
     652          // and the smarter ones will know that there is some smart matching
     653          // that will ensure people end up at the latest version of the docs.
     654          $branch = '.';
     655      }
     656      if (empty($CFG->doclang)) {
     657          $lang = current_language();
     658      } else {
     659          $lang = $CFG->doclang;
     660      }
     661      $end = '/' . $branch . '/' . $lang . '/' . $path;
     662      if (empty($CFG->docroot)) {
     663          return 'http://docs.moodle.org'. $end;
     664      } else {
     665          return $CFG->docroot . $end ;
     666      }
     667  }
     668  
     669  /**
     670   * Formats a backtrace ready for output.
     671   *
     672   * @param array $callers backtrace array, as returned by debug_backtrace().
     673   * @param boolean $plaintext if false, generates HTML, if true generates plain text.
     674   * @return string formatted backtrace, ready for output.
     675   */
     676  function format_backtrace($callers, $plaintext = false) {
     677      // do not use $CFG->dirroot because it might not be available in destructors
     678      $dirroot = dirname(dirname(__FILE__));
     679  
     680      if (empty($callers)) {
     681          return '';
     682      }
     683  
     684      $from = $plaintext ? '' : '<ul style="text-align: left" data-rel="backtrace">';
     685      foreach ($callers as $caller) {
     686          if (!isset($caller['line'])) {
     687              $caller['line'] = '?'; // probably call_user_func()
     688          }
     689          if (!isset($caller['file'])) {
     690              $caller['file'] = 'unknownfile'; // probably call_user_func()
     691          }
     692          $from .= $plaintext ? '* ' : '<li>';
     693          $from .= 'line ' . $caller['line'] . ' of ' . str_replace($dirroot, '', $caller['file']);
     694          if (isset($caller['function'])) {
     695              $from .= ': call to ';
     696              if (isset($caller['class'])) {
     697                  $from .= $caller['class'] . $caller['type'];
     698              }
     699              $from .= $caller['function'] . '()';
     700          } else if (isset($caller['exception'])) {
     701              $from .= ': '.$caller['exception'].' thrown';
     702          }
     703          $from .= $plaintext ? "\n" : '</li>';
     704      }
     705      $from .= $plaintext ? '' : '</ul>';
     706  
     707      return $from;
     708  }
     709  
     710  /**
     711   * This function makes the return value of ini_get consistent if you are
     712   * setting server directives through the .htaccess file in apache.
     713   *
     714   * Current behavior for value set from php.ini On = 1, Off = [blank]
     715   * Current behavior for value set from .htaccess On = On, Off = Off
     716   * Contributed by jdell @ unr.edu
     717   *
     718   * @param string $ini_get_arg The argument to get
     719   * @return bool True for on false for not
     720   */
     721  function ini_get_bool($ini_get_arg) {
     722      $temp = ini_get($ini_get_arg);
     723  
     724      if ($temp == '1' or strtolower($temp) == 'on') {
     725          return true;
     726      }
     727      return false;
     728  }
     729  
     730  /**
     731   * This function verifies the sanity of PHP configuration
     732   * and stops execution if anything critical found.
     733   */
     734  function setup_validate_php_configuration() {
     735     // this must be very fast - no slow checks here!!!
     736  
     737     if (ini_get_bool('session.auto_start')) {
     738         print_error('sessionautostartwarning', 'admin');
     739     }
     740  }
     741  
     742  /**
     743   * Initialise global $CFG variable.
     744   * @private to be used only from lib/setup.php
     745   */
     746  function initialise_cfg() {
     747      global $CFG, $DB;
     748  
     749      if (!$DB) {
     750          // This should not happen.
     751          return;
     752      }
     753  
     754      try {
     755          $localcfg = get_config('core');
     756      } catch (dml_exception $e) {
     757          // Most probably empty db, going to install soon.
     758          return;
     759      }
     760  
     761      foreach ($localcfg as $name => $value) {
     762          // Note that get_config() keeps forced settings
     763          // and normalises values to string if possible.
     764          $CFG->{$name} = $value;
     765      }
     766  }
     767  
     768  /**
     769   * Initialises $FULLME and friends. Private function. Should only be called from
     770   * setup.php.
     771   */
     772  function initialise_fullme() {
     773      global $CFG, $FULLME, $ME, $SCRIPT, $FULLSCRIPT;
     774  
     775      // Detect common config error.
     776      if (substr($CFG->wwwroot, -1) == '/') {
     777          print_error('wwwrootslash', 'error');
     778      }
     779  
     780      if (CLI_SCRIPT) {
     781          initialise_fullme_cli();
     782          return;
     783      }
     784  
     785      $rurl = setup_get_remote_url();
     786      $wwwroot = parse_url($CFG->wwwroot.'/');
     787  
     788      if (empty($rurl['host'])) {
     789          // missing host in request header, probably not a real browser, let's ignore them
     790  
     791      } else if (!empty($CFG->reverseproxy)) {
     792          // $CFG->reverseproxy specifies if reverse proxy server used
     793          // Used in load balancing scenarios.
     794          // Do not abuse this to try to solve lan/wan access problems!!!!!
     795  
     796      } else {
     797          if (($rurl['host'] !== $wwwroot['host']) or
     798                  (!empty($wwwroot['port']) and $rurl['port'] != $wwwroot['port']) or
     799                  (strpos($rurl['path'], $wwwroot['path']) !== 0)) {
     800  
     801              // Explain the problem and redirect them to the right URL
     802              if (!defined('NO_MOODLE_COOKIES')) {
     803                  define('NO_MOODLE_COOKIES', true);
     804              }
     805              // The login/token.php script should call the correct url/port.
     806              if (defined('REQUIRE_CORRECT_ACCESS') && REQUIRE_CORRECT_ACCESS) {
     807                  $wwwrootport = empty($wwwroot['port'])?'':$wwwroot['port'];
     808                  $calledurl = $rurl['host'];
     809                  if (!empty($rurl['port'])) {
     810                      $calledurl .=  ':'. $rurl['port'];
     811                  }
     812                  $correcturl = $wwwroot['host'];
     813                  if (!empty($wwwrootport)) {
     814                      $correcturl .=  ':'. $wwwrootport;
     815                  }
     816                  throw new moodle_exception('requirecorrectaccess', 'error', '', null,
     817                      'You called ' . $calledurl .', you should have called ' . $correcturl);
     818              }
     819              redirect($CFG->wwwroot, get_string('wwwrootmismatch', 'error', $CFG->wwwroot), 3);
     820          }
     821      }
     822  
     823      // Check that URL is under $CFG->wwwroot.
     824      if (strpos($rurl['path'], $wwwroot['path']) === 0) {
     825          $SCRIPT = substr($rurl['path'], strlen($wwwroot['path'])-1);
     826      } else {
     827          // Probably some weird external script
     828          $SCRIPT = $FULLSCRIPT = $FULLME = $ME = null;
     829          return;
     830      }
     831  
     832      // $CFG->sslproxy specifies if external SSL appliance is used
     833      // (That is, the Moodle server uses http, with an external box translating everything to https).
     834      if (empty($CFG->sslproxy)) {
     835          if ($rurl['scheme'] === 'http' and $wwwroot['scheme'] === 'https') {
     836              print_error('sslonlyaccess', 'error');
     837          }
     838      } else {
     839          if ($wwwroot['scheme'] !== 'https') {
     840              throw new coding_exception('Must use https address in wwwroot when ssl proxy enabled!');
     841          }
     842          $rurl['scheme'] = 'https'; // make moodle believe it runs on https, squid or something else it doing it
     843          $_SERVER['HTTPS'] = 'on'; // Override $_SERVER to help external libraries with their HTTPS detection.
     844          $_SERVER['SERVER_PORT'] = 443; // Assume default ssl port for the proxy.
     845      }
     846  
     847      // hopefully this will stop all those "clever" admins trying to set up moodle
     848      // with two different addresses in intranet and Internet
     849      if (!empty($CFG->reverseproxy) && $rurl['host'] === $wwwroot['host']) {
     850          print_error('reverseproxyabused', 'error');
     851      }
     852  
     853      $hostandport = $rurl['scheme'] . '://' . $wwwroot['host'];
     854      if (!empty($wwwroot['port'])) {
     855          $hostandport .= ':'.$wwwroot['port'];
     856      }
     857  
     858      $FULLSCRIPT = $hostandport . $rurl['path'];
     859      $FULLME = $hostandport . $rurl['fullpath'];
     860      $ME = $rurl['fullpath'];
     861  }
     862  
     863  /**
     864   * Initialises $FULLME and friends for command line scripts.
     865   * This is a private method for use by initialise_fullme.
     866   */
     867  function initialise_fullme_cli() {
     868      global $CFG, $FULLME, $ME, $SCRIPT, $FULLSCRIPT;
     869  
     870      // Urls do not make much sense in CLI scripts
     871      $backtrace = debug_backtrace();
     872      $topfile = array_pop($backtrace);
     873      $topfile = realpath($topfile['file']);
     874      $dirroot = realpath($CFG->dirroot);
     875  
     876      if (strpos($topfile, $dirroot) !== 0) {
     877          // Probably some weird external script
     878          $SCRIPT = $FULLSCRIPT = $FULLME = $ME = null;
     879      } else {
     880          $relativefile = substr($topfile, strlen($dirroot));
     881          $relativefile = str_replace('\\', '/', $relativefile); // Win fix
     882          $SCRIPT = $FULLSCRIPT = $relativefile;
     883          $FULLME = $ME = null;
     884      }
     885  }
     886  
     887  /**
     888   * Get the URL that PHP/the web server thinks it is serving. Private function
     889   * used by initialise_fullme. In your code, use $PAGE->url, $SCRIPT, etc.
     890   * @return array in the same format that parse_url returns, with the addition of
     891   *      a 'fullpath' element, which includes any slasharguments path.
     892   */
     893  function setup_get_remote_url() {
     894      $rurl = array();
     895      if (isset($_SERVER['HTTP_HOST'])) {
     896          list($rurl['host']) = explode(':', $_SERVER['HTTP_HOST']);
     897      } else {
     898          $rurl['host'] = null;
     899      }
     900      $rurl['port'] = $_SERVER['SERVER_PORT'];
     901      $rurl['path'] = $_SERVER['SCRIPT_NAME']; // Script path without slash arguments
     902      $rurl['scheme'] = (empty($_SERVER['HTTPS']) or $_SERVER['HTTPS'] === 'off' or $_SERVER['HTTPS'] === 'Off' or $_SERVER['HTTPS'] === 'OFF') ? 'http' : 'https';
     903  
     904      if (stripos($_SERVER['SERVER_SOFTWARE'], 'apache') !== false) {
     905          //Apache server
     906          $rurl['fullpath'] = $_SERVER['REQUEST_URI'];
     907  
     908          // Fixing a known issue with:
     909          // - Apache versions lesser than 2.4.11
     910          // - PHP deployed in Apache as PHP-FPM via mod_proxy_fcgi
     911          // - PHP versions lesser than 5.6.3 and 5.5.18.
     912          if (isset($_SERVER['PATH_INFO']) && (php_sapi_name() === 'fpm-fcgi') && isset($_SERVER['SCRIPT_NAME'])) {
     913              $pathinfodec = rawurldecode($_SERVER['PATH_INFO']);
     914              $lenneedle = strlen($pathinfodec);
     915              // Checks whether SCRIPT_NAME ends with PATH_INFO, URL-decoded.
     916              if (substr($_SERVER['SCRIPT_NAME'], -$lenneedle) === $pathinfodec) {
     917                  // This is the "Apache 2.4.10- running PHP-FPM via mod_proxy_fcgi" fingerprint,
     918                  // at least on CentOS 7 (Apache/2.4.6 PHP/5.4.16) and Ubuntu 14.04 (Apache/2.4.7 PHP/5.5.9)
     919                  // => SCRIPT_NAME contains 'slash arguments' data too, which is wrongly exposed via PATH_INFO as URL-encoded.
     920                  // Fix both $_SERVER['PATH_INFO'] and $_SERVER['SCRIPT_NAME'].
     921                  $lenhaystack = strlen($_SERVER['SCRIPT_NAME']);
     922                  $pos = $lenhaystack - $lenneedle;
     923                  // Here $pos is greater than 0 but let's double check it.
     924                  if ($pos > 0) {
     925                      $_SERVER['PATH_INFO'] = $pathinfodec;
     926                      $_SERVER['SCRIPT_NAME'] = substr($_SERVER['SCRIPT_NAME'], 0, $pos);
     927                  }
     928              }
     929          }
     930  
     931      } else if (stripos($_SERVER['SERVER_SOFTWARE'], 'iis') !== false) {
     932          //IIS - needs a lot of tweaking to make it work
     933          $rurl['fullpath'] = $_SERVER['SCRIPT_NAME'];
     934  
     935          // NOTE: we should ignore PATH_INFO because it is incorrectly encoded using 8bit filesystem legacy encoding in IIS.
     936          //       Since 2.0, we rely on IIS rewrite extensions like Helicon ISAPI_rewrite
     937          //         example rule: RewriteRule ^([^\?]+?\.php)(\/.+)$ $1\?file=$2 [QSA]
     938          //       OR
     939          //       we rely on a proper IIS 6.0+ configuration: the 'FastCGIUtf8ServerVariables' registry key.
     940          if (isset($_SERVER['PATH_INFO']) and $_SERVER['PATH_INFO'] !== '') {
     941              // Check that PATH_INFO works == must not contain the script name.
     942              if (strpos($_SERVER['PATH_INFO'], $_SERVER['SCRIPT_NAME']) === false) {
     943                  $rurl['fullpath'] .= clean_param(urldecode($_SERVER['PATH_INFO']), PARAM_PATH);
     944              }
     945          }
     946  
     947          if (isset($_SERVER['QUERY_STRING']) and $_SERVER['QUERY_STRING'] !== '') {
     948              $rurl['fullpath'] .= '?'.$_SERVER['QUERY_STRING'];
     949          }
     950          $_SERVER['REQUEST_URI'] = $rurl['fullpath']; // extra IIS compatibility
     951  
     952  /* NOTE: following servers are not fully tested! */
     953  
     954      } else if (stripos($_SERVER['SERVER_SOFTWARE'], 'lighttpd') !== false) {
     955          //lighttpd - not officially supported
     956          $rurl['fullpath'] = $_SERVER['REQUEST_URI']; // TODO: verify this is always properly encoded
     957  
     958      } else if (stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) {
     959          //nginx - not officially supported
     960          if (!isset($_SERVER['SCRIPT_NAME'])) {
     961              die('Invalid server configuration detected, please try to add "fastcgi_param SCRIPT_NAME $fastcgi_script_name;" to the nginx server configuration.');
     962          }
     963          $rurl['fullpath'] = $_SERVER['REQUEST_URI']; // TODO: verify this is always properly encoded
     964  
     965       } else if (stripos($_SERVER['SERVER_SOFTWARE'], 'cherokee') !== false) {
     966           //cherokee - not officially supported
     967           $rurl['fullpath'] = $_SERVER['REQUEST_URI']; // TODO: verify this is always properly encoded
     968  
     969       } else if (stripos($_SERVER['SERVER_SOFTWARE'], 'zeus') !== false) {
     970           //zeus - not officially supported
     971           $rurl['fullpath'] = $_SERVER['REQUEST_URI']; // TODO: verify this is always properly encoded
     972  
     973      } else if (stripos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false) {
     974          //LiteSpeed - not officially supported
     975          $rurl['fullpath'] = $_SERVER['REQUEST_URI']; // TODO: verify this is always properly encoded
     976  
     977      } else if ($_SERVER['SERVER_SOFTWARE'] === 'HTTPD') {
     978          //obscure name found on some servers - this is definitely not supported
     979          $rurl['fullpath'] = $_SERVER['REQUEST_URI']; // TODO: verify this is always properly encoded
     980  
     981      } else if (strpos($_SERVER['SERVER_SOFTWARE'], 'PHP') === 0) {
     982          // built-in PHP Development Server
     983          $rurl['fullpath'] = $_SERVER['REQUEST_URI'];
     984  
     985      } else {
     986          throw new moodle_exception('unsupportedwebserver', 'error', '', $_SERVER['SERVER_SOFTWARE']);
     987      }
     988  
     989      // sanitize the url a bit more, the encoding style may be different in vars above
     990      $rurl['fullpath'] = str_replace('"', '%22', $rurl['fullpath']);
     991      $rurl['fullpath'] = str_replace('\'', '%27', $rurl['fullpath']);
     992  
     993      return $rurl;
     994  }
     995  
     996  /**
     997   * Try to work around the 'max_input_vars' restriction if necessary.
     998   */
     999  function workaround_max_input_vars() {
    1000      // Make sure this gets executed only once from lib/setup.php!
    1001      static $executed = false;
    1002      if ($executed) {
    1003          debugging('workaround_max_input_vars() must be called only once!');
    1004          return;
    1005      }
    1006      $executed = true;
    1007  
    1008      if (!isset($_SERVER["CONTENT_TYPE"]) or strpos($_SERVER["CONTENT_TYPE"], 'multipart/form-data') !== false) {
    1009          // Not a post or 'multipart/form-data' which is not compatible with "php://input" reading.
    1010          return;
    1011      }
    1012  
    1013      if (!isloggedin() or isguestuser()) {
    1014          // Only real users post huge forms.
    1015          return;
    1016      }
    1017  
    1018      $max = (int)ini_get('max_input_vars');
    1019  
    1020      if ($max <= 0) {
    1021          // Most probably PHP < 5.3.9 that does not implement this limit.
    1022          return;
    1023      }
    1024  
    1025      if ($max >= 200000) {
    1026          // This value should be ok for all our forms, by setting it in php.ini
    1027          // admins may prevent any unexpected regressions caused by this hack.
    1028  
    1029          // Note there is no need to worry about DDoS caused by making this limit very high
    1030          // because there are very many easier ways to DDoS any Moodle server.
    1031          return;
    1032      }
    1033  
    1034      if (count($_POST, COUNT_RECURSIVE) < $max) {
    1035          return;
    1036      }
    1037  
    1038      // Large POST request with enctype supported by php://input.
    1039      // Parse php://input in chunks to bypass max_input_vars limit, which also applies to parse_str().
    1040      $str = file_get_contents("php://input");
    1041      if ($str === false or $str === '') {
    1042          // Some weird error.
    1043          return;
    1044      }
    1045  
    1046      $delim = '&';
    1047      $fun = create_function('$p', 'return implode("'.$delim.'", $p);');
    1048      $chunks = array_map($fun, array_chunk(explode($delim, $str), $max));
    1049  
    1050      foreach ($chunks as $chunk) {
    1051          $values = array();
    1052          parse_str($chunk, $values);
    1053  
    1054          merge_query_params($_POST, $values);
    1055          merge_query_params($_REQUEST, $values);
    1056      }
    1057  }
    1058  
    1059  /**
    1060   * Merge parsed POST chunks.
    1061   *
    1062   * NOTE: this is not perfect, but it should work in most cases hopefully.
    1063   *
    1064   * @param array $target
    1065   * @param array $values
    1066   */
    1067  function merge_query_params(array &$target, array $values) {
    1068      if (isset($values[0]) and isset($target[0])) {
    1069          // This looks like a split [] array, lets verify the keys are continuous starting with 0.
    1070          $keys1 = array_keys($values);
    1071          $keys2 = array_keys($target);
    1072          if ($keys1 === array_keys($keys1) and $keys2 === array_keys($keys2)) {
    1073              foreach ($values as $v) {
    1074                  $target[] = $v;
    1075              }
    1076              return;
    1077          }
    1078      }
    1079      foreach ($values as $k => $v) {
    1080          if (!isset($target[$k])) {
    1081              $target[$k] = $v;
    1082              continue;
    1083          }
    1084          if (is_array($target[$k]) and is_array($v)) {
    1085              merge_query_params($target[$k], $v);
    1086              continue;
    1087          }
    1088          // We should not get here unless there are duplicates in params.
    1089          $target[$k] = $v;
    1090      }
    1091  }
    1092  
    1093  /**
    1094   * Initializes our performance info early.
    1095   *
    1096   * Pairs up with get_performance_info() which is actually
    1097   * in moodlelib.php. This function is here so that we can
    1098   * call it before all the libs are pulled in.
    1099   *
    1100   * @uses $PERF
    1101   */
    1102  function init_performance_info() {
    1103  
    1104      global $PERF, $CFG, $USER;
    1105  
    1106      $PERF = new stdClass();
    1107      $PERF->logwrites = 0;
    1108      if (function_exists('microtime')) {
    1109          $PERF->starttime = microtime();
    1110      }
    1111      if (function_exists('memory_get_usage')) {
    1112          $PERF->startmemory = memory_get_usage();
    1113      }
    1114      if (function_exists('posix_times')) {
    1115          $PERF->startposixtimes = posix_times();
    1116      }
    1117  }
    1118  
    1119  /**
    1120   * Indicates whether we are in the middle of the initial Moodle install.
    1121   *
    1122   * Very occasionally it is necessary avoid running certain bits of code before the
    1123   * Moodle installation has completed. The installed flag is set in admin/index.php
    1124   * after Moodle core and all the plugins have been installed, but just before
    1125   * the person doing the initial install is asked to choose the admin password.
    1126   *
    1127   * @return boolean true if the initial install is not complete.
    1128   */
    1129  function during_initial_install() {
    1130      global $CFG;
    1131      return empty($CFG->rolesactive);
    1132  }
    1133  
    1134  /**
    1135   * Function to raise the memory limit to a new value.
    1136   * Will respect the memory limit if it is higher, thus allowing
    1137   * settings in php.ini, apache conf or command line switches
    1138   * to override it.
    1139   *
    1140   * The memory limit should be expressed with a constant
    1141   * MEMORY_STANDARD, MEMORY_EXTRA or MEMORY_HUGE.
    1142   * It is possible to use strings or integers too (eg:'128M').
    1143   *
    1144   * @param mixed $newlimit the new memory limit
    1145   * @return bool success
    1146   */
    1147  function raise_memory_limit($newlimit) {
    1148      global $CFG;
    1149  
    1150      if ($newlimit == MEMORY_UNLIMITED) {
    1151          ini_set('memory_limit', -1);
    1152          return true;
    1153  
    1154      } else if ($newlimit == MEMORY_STANDARD) {
    1155          if (PHP_INT_SIZE > 4) {
    1156              $newlimit = get_real_size('128M'); // 64bit needs more memory
    1157          } else {
    1158              $newlimit = get_real_size('96M');
    1159          }
    1160  
    1161      } else if ($newlimit == MEMORY_EXTRA) {
    1162          if (PHP_INT_SIZE > 4) {
    1163              $newlimit = get_real_size('384M'); // 64bit needs more memory
    1164          } else {
    1165              $newlimit = get_real_size('256M');
    1166          }
    1167          if (!empty($CFG->extramemorylimit)) {
    1168              $extra = get_real_size($CFG->extramemorylimit);
    1169              if ($extra > $newlimit) {
    1170                  $newlimit = $extra;
    1171              }
    1172          }
    1173  
    1174      } else if ($newlimit == MEMORY_HUGE) {
    1175          // MEMORY_HUGE uses 2G or MEMORY_EXTRA, whichever is bigger.
    1176          $newlimit = get_real_size('2G');
    1177          if (!empty($CFG->extramemorylimit)) {
    1178              $extra = get_real_size($CFG->extramemorylimit);
    1179              if ($extra > $newlimit) {
    1180                  $newlimit = $extra;
    1181              }
    1182          }
    1183  
    1184      } else {
    1185          $newlimit = get_real_size($newlimit);
    1186      }
    1187  
    1188      if ($newlimit <= 0) {
    1189          debugging('Invalid memory limit specified.');
    1190          return false;
    1191      }
    1192  
    1193      $cur = ini_get('memory_limit');
    1194      if (empty($cur)) {
    1195          // if php is compiled without --enable-memory-limits
    1196          // apparently memory_limit is set to ''
    1197          $cur = 0;
    1198      } else {
    1199          if ($cur == -1){
    1200              return true; // unlimited mem!
    1201          }
    1202          $cur = get_real_size($cur);
    1203      }
    1204  
    1205      if ($newlimit > $cur) {
    1206          ini_set('memory_limit', $newlimit);
    1207          return true;
    1208      }
    1209      return false;
    1210  }
    1211  
    1212  /**
    1213   * Function to reduce the memory limit to a new value.
    1214   * Will respect the memory limit if it is lower, thus allowing
    1215   * settings in php.ini, apache conf or command line switches
    1216   * to override it
    1217   *
    1218   * The memory limit should be expressed with a string (eg:'64M')
    1219   *
    1220   * @param string $newlimit the new memory limit
    1221   * @return bool
    1222   */
    1223  function reduce_memory_limit($newlimit) {
    1224      if (empty($newlimit)) {
    1225          return false;
    1226      }
    1227      $cur = ini_get('memory_limit');
    1228      if (empty($cur)) {
    1229          // if php is compiled without --enable-memory-limits
    1230          // apparently memory_limit is set to ''
    1231          $cur = 0;
    1232      } else {
    1233          if ($cur == -1){
    1234              return true; // unlimited mem!
    1235          }
    1236          $cur = get_real_size($cur);
    1237      }
    1238  
    1239      $new = get_real_size($newlimit);
    1240      // -1 is smaller, but it means unlimited
    1241      if ($new < $cur && $new != -1) {
    1242          ini_set('memory_limit', $newlimit);
    1243          return true;
    1244      }
    1245      return false;
    1246  }
    1247  
    1248  /**
    1249   * Converts numbers like 10M into bytes.
    1250   *
    1251   * @param string $size The size to be converted
    1252   * @return int
    1253   */
    1254  function get_real_size($size = 0) {
    1255      if (!$size) {
    1256          return 0;
    1257      }
    1258      $scan = array();
    1259      $scan['GB'] = 1073741824;
    1260      $scan['Gb'] = 1073741824;
    1261      $scan['G'] = 1073741824;
    1262      $scan['MB'] = 1048576;
    1263      $scan['Mb'] = 1048576;
    1264      $scan['M'] = 1048576;
    1265      $scan['m'] = 1048576;
    1266      $scan['KB'] = 1024;
    1267      $scan['Kb'] = 1024;
    1268      $scan['K'] = 1024;
    1269      $scan['k'] = 1024;
    1270  
    1271      while (list($key) = each($scan)) {
    1272          if ((strlen($size)>strlen($key))&&(substr($size, strlen($size) - strlen($key))==$key)) {
    1273              $size = substr($size, 0, strlen($size) - strlen($key)) * $scan[$key];
    1274              break;
    1275          }
    1276      }
    1277      return $size;
    1278  }
    1279  
    1280  /**
    1281   * Try to disable all output buffering and purge
    1282   * all headers.
    1283   *
    1284   * @access private to be called only from lib/setup.php !
    1285   * @return void
    1286   */
    1287  function disable_output_buffering() {
    1288      $olddebug = error_reporting(0);
    1289  
    1290      // disable compression, it would prevent closing of buffers
    1291      if (ini_get_bool('zlib.output_compression')) {
    1292          ini_set('zlib.output_compression', 'Off');
    1293      }
    1294  
    1295      // try to flush everything all the time
    1296      ob_implicit_flush(true);
    1297  
    1298      // close all buffers if possible and discard any existing output
    1299      // this can actually work around some whitespace problems in config.php
    1300      while(ob_get_level()) {
    1301          if (!ob_end_clean()) {
    1302              // prevent infinite loop when buffer can not be closed
    1303              break;
    1304          }
    1305      }
    1306  
    1307      // disable any other output handlers
    1308      ini_set('output_handler', '');
    1309  
    1310      error_reporting($olddebug);
    1311  }
    1312  
    1313  /**
    1314   * Check whether a major upgrade is needed. That is defined as an upgrade that
    1315   * changes something really fundamental in the database, so nothing can possibly
    1316   * work until the database has been updated, and that is defined by the hard-coded
    1317   * version number in this function.
    1318   */
    1319  function redirect_if_major_upgrade_required() {
    1320      global $CFG;
    1321      $lastmajordbchanges = 2014093001.00;
    1322      if (empty($CFG->version) or (float)$CFG->version < $lastmajordbchanges or
    1323              during_initial_install() or !empty($CFG->adminsetuppending)) {
    1324          try {
    1325              @\core\session\manager::terminate_current();
    1326          } catch (Exception $e) {
    1327              // Ignore any errors, redirect to upgrade anyway.
    1328          }
    1329          $url = $CFG->wwwroot . '/' . $CFG->admin . '/index.php';
    1330          @header($_SERVER['SERVER_PROTOCOL'] . ' 303 See Other');
    1331          @header('Location: ' . $url);
    1332          echo bootstrap_renderer::plain_redirect_message(htmlspecialchars($url));
    1333          exit;
    1334      }
    1335  }
    1336  
    1337  /**
    1338   * Makes sure that upgrade process is not running
    1339   *
    1340   * To be inserted in the core functions that can not be called by pluigns during upgrade.
    1341   * Core upgrade should not use any API functions at all.
    1342   * See {@link http://docs.moodle.org/dev/Upgrade_API#Upgrade_code_restrictions}
    1343   *
    1344   * @throws moodle_exception if executed from inside of upgrade script and $warningonly is false
    1345   * @param bool $warningonly if true displays a warning instead of throwing an exception
    1346   * @return bool true if executed from outside of upgrade process, false if from inside upgrade process and function is used for warning only
    1347   */
    1348  function upgrade_ensure_not_running($warningonly = false) {
    1349      global $CFG;
    1350      if (!empty($CFG->upgraderunning)) {
    1351          if (!$warningonly) {
    1352              throw new moodle_exception('cannotexecduringupgrade');
    1353          } else {
    1354              debugging(get_string('cannotexecduringupgrade', 'error'), DEBUG_DEVELOPER);
    1355              return false;
    1356          }
    1357      }
    1358      return true;
    1359  }
    1360  
    1361  /**
    1362   * Function to check if a directory exists and by default create it if not exists.
    1363   *
    1364   * Previously this was accepting paths only from dataroot, but we now allow
    1365   * files outside of dataroot if you supply custom paths for some settings in config.php.
    1366   * This function does not verify that the directory is writable.
    1367   *
    1368   * NOTE: this function uses current file stat cache,
    1369   *       please use clearstatcache() before this if you expect that the
    1370   *       directories may have been removed recently from a different request.
    1371   *
    1372   * @param string $dir absolute directory path
    1373   * @param boolean $create directory if does not exist
    1374   * @param boolean $recursive create directory recursively
    1375   * @return boolean true if directory exists or created, false otherwise
    1376   */
    1377  function check_dir_exists($dir, $create = true, $recursive = true) {
    1378      global $CFG;
    1379  
    1380      umask($CFG->umaskpermissions);
    1381  
    1382      if (is_dir($dir)) {
    1383          return true;
    1384      }
    1385  
    1386      if (!$create) {
    1387          return false;
    1388      }
    1389  
    1390      return mkdir($dir, $CFG->directorypermissions, $recursive);
    1391  }
    1392  
    1393  /**
    1394   * Create a directory and make sure it is writable.
    1395   *
    1396   * @private
    1397   * @param string $dir  the full path of the directory to be created
    1398   * @param bool $exceptiononerror throw exception if error encountered
    1399   * @return string|false Returns full path to directory if successful, false if not; may throw exception
    1400   */
    1401  function make_writable_directory($dir, $exceptiononerror = true) {
    1402      global $CFG;
    1403  
    1404      if (file_exists($dir) and !is_dir($dir)) {
    1405          if ($exceptiononerror) {
    1406              throw new coding_exception($dir.' directory can not be created, file with the same name already exists.');
    1407          } else {
    1408              return false;
    1409          }
    1410      }
    1411  
    1412      umask($CFG->umaskpermissions);
    1413  
    1414      if (!file_exists($dir)) {
    1415          if (!mkdir($dir, $CFG->directorypermissions, true)) {
    1416              clearstatcache();
    1417              // There might be a race condition when creating directory.
    1418              if (!is_dir($dir)) {
    1419                  if ($exceptiononerror) {
    1420                      throw new invalid_dataroot_permissions($dir.' can not be created, check permissions.');
    1421                  } else {
    1422                      debugging('Can not create directory: '.$dir, DEBUG_DEVELOPER);
    1423                      return false;
    1424                  }
    1425              }
    1426          }
    1427      }
    1428  
    1429      if (!is_writable($dir)) {
    1430          if ($exceptiononerror) {
    1431              throw new invalid_dataroot_permissions($dir.' is not writable, check permissions.');
    1432          } else {
    1433              return false;
    1434          }
    1435      }
    1436  
    1437      return $dir;
    1438  }
    1439  
    1440  /**
    1441   * Protect a directory from web access.
    1442   * Could be extended in the future to support other mechanisms (e.g. other webservers).
    1443   *
    1444   * @private
    1445   * @param string $dir  the full path of the directory to be protected
    1446   */
    1447  function protect_directory($dir) {
    1448      global $CFG;
    1449      // Make sure a .htaccess file is here, JUST IN CASE the files area is in the open and .htaccess is supported
    1450      if (!file_exists("$dir/.htaccess")) {
    1451          if ($handle = fopen("$dir/.htaccess", 'w')) {   // For safety
    1452              @fwrite($handle, "deny from all\r\nAllowOverride None\r\nNote: this file is broken intentionally, we do not want anybody to undo it in subdirectory!\r\n");
    1453              @fclose($handle);
    1454              @chmod("$dir/.htaccess", $CFG->filepermissions);
    1455          }
    1456      }
    1457  }
    1458  
    1459  /**
    1460   * Create a directory under dataroot and make sure it is writable.
    1461   * Do not use for temporary and cache files - see make_temp_directory() and make_cache_directory().
    1462   *
    1463   * @param string $directory  the full path of the directory to be created under $CFG->dataroot
    1464   * @param bool $exceptiononerror throw exception if error encountered
    1465   * @return string|false Returns full path to directory if successful, false if not; may throw exception
    1466   */
    1467  function make_upload_directory($directory, $exceptiononerror = true) {
    1468      global $CFG;
    1469  
    1470      if (strpos($directory, 'temp/') === 0 or $directory === 'temp') {
    1471          debugging('Use make_temp_directory() for creation of temporary directory and $CFG->tempdir to get the location.');
    1472  
    1473      } else if (strpos($directory, 'cache/') === 0 or $directory === 'cache') {
    1474          debugging('Use make_cache_directory() for creation of cache directory and $CFG->cachedir to get the location.');
    1475  
    1476      } else if (strpos($directory, 'localcache/') === 0 or $directory === 'localcache') {
    1477          debugging('Use make_localcache_directory() for creation of local cache directory and $CFG->localcachedir to get the location.');
    1478      }
    1479  
    1480      protect_directory($CFG->dataroot);
    1481      return make_writable_directory("$CFG->dataroot/$directory", $exceptiononerror);
    1482  }
    1483  
    1484  /**
    1485   * Create a directory under tempdir and make sure it is writable.
    1486   * Temporary files should be used during the current request only!
    1487   *
    1488   * @param string $directory  the full path of the directory to be created under $CFG->tempdir
    1489   * @param bool $exceptiononerror throw exception if error encountered
    1490   * @return string|false Returns full path to directory if successful, false if not; may throw exception
    1491   */
    1492  function make_temp_directory($directory, $exceptiononerror = true) {
    1493      global $CFG;
    1494      if ($CFG->tempdir !== "$CFG->dataroot/temp") {
    1495          check_dir_exists($CFG->tempdir, true, true);
    1496          protect_directory($CFG->tempdir);
    1497      } else {
    1498          protect_directory($CFG->dataroot);
    1499      }
    1500      return make_writable_directory("$CFG->tempdir/$directory", $exceptiononerror);
    1501  }
    1502  
    1503  /**
    1504   * Create a directory under cachedir and make sure it is writable.
    1505   *
    1506   * Note: this cache directory is shared by all cluster nodes.
    1507   *
    1508   * @param string $directory  the full path of the directory to be created under $CFG->cachedir
    1509   * @param bool $exceptiononerror throw exception if error encountered
    1510   * @return string|false Returns full path to directory if successful, false if not; may throw exception
    1511   */
    1512  function make_cache_directory($directory, $exceptiononerror = true) {
    1513      global $CFG;
    1514      if ($CFG->cachedir !== "$CFG->dataroot/cache") {
    1515          check_dir_exists($CFG->cachedir, true, true);
    1516          protect_directory($CFG->cachedir);
    1517      } else {
    1518          protect_directory($CFG->dataroot);
    1519      }
    1520      return make_writable_directory("$CFG->cachedir/$directory", $exceptiononerror);
    1521  }
    1522  
    1523  /**
    1524   * Create a directory under localcachedir and make sure it is writable.
    1525   * The files in this directory MUST NOT change, use revisions or content hashes to
    1526   * work around this limitation - this means you can only add new files here.
    1527   *
    1528   * The content of this directory gets purged automatically on all cluster nodes
    1529   * after calling purge_all_caches() before new data is written to this directory.
    1530   *
    1531   * Note: this local cache directory does not need to be shared by cluster nodes.
    1532   *
    1533   * @param string $directory the relative path of the directory to be created under $CFG->localcachedir
    1534   * @param bool $exceptiononerror throw exception if error encountered
    1535   * @return string|false Returns full path to directory if successful, false if not; may throw exception
    1536   */
    1537  function make_localcache_directory($directory, $exceptiononerror = true) {
    1538      global $CFG;
    1539  
    1540      make_writable_directory($CFG->localcachedir, $exceptiononerror);
    1541  
    1542      if ($CFG->localcachedir !== "$CFG->dataroot/localcache") {
    1543          protect_directory($CFG->localcachedir);
    1544      } else {
    1545          protect_directory($CFG->dataroot);
    1546      }
    1547  
    1548      if (!isset($CFG->localcachedirpurged)) {
    1549          $CFG->localcachedirpurged = 0;
    1550      }
    1551      $timestampfile = "$CFG->localcachedir/.lastpurged";
    1552  
    1553      if (!file_exists($timestampfile)) {
    1554          touch($timestampfile);
    1555          @chmod($timestampfile, $CFG->filepermissions);
    1556  
    1557      } else if (filemtime($timestampfile) <  $CFG->localcachedirpurged) {
    1558          // This means our local cached dir was not purged yet.
    1559          remove_dir($CFG->localcachedir, true);
    1560          if ($CFG->localcachedir !== "$CFG->dataroot/localcache") {
    1561              protect_directory($CFG->localcachedir);
    1562          }
    1563          touch($timestampfile);
    1564          @chmod($timestampfile, $CFG->filepermissions);
    1565          clearstatcache();
    1566      }
    1567  
    1568      if ($directory === '') {
    1569          return $CFG->localcachedir;
    1570      }
    1571  
    1572      return make_writable_directory("$CFG->localcachedir/$directory", $exceptiononerror);
    1573  }
    1574  
    1575  /**
    1576   * Checks if current user is a web crawler.
    1577   *
    1578   * This list can not be made complete, this is not a security
    1579   * restriction, we make the list only to help these sites
    1580   * especially when automatic guest login is disabled.
    1581   *
    1582   * If admin needs security they should enable forcelogin
    1583   * and disable guest access!!
    1584   *
    1585   * @return bool
    1586   */
    1587  function is_web_crawler() {
    1588      if (!empty($_SERVER['HTTP_USER_AGENT'])) {
    1589          if (strpos($_SERVER['HTTP_USER_AGENT'], 'Googlebot') !== false ) {
    1590              return true;
    1591          } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'google.com') !== false ) { // Google
    1592              return true;
    1593          } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'Yahoo! Slurp') !== false ) {  // Yahoo
    1594              return true;
    1595          } else if (strpos($_SERVER['HTTP_USER_AGENT'], '[ZSEBOT]') !== false ) {  // Zoomspider
    1596              return true;
    1597          } else if (stripos($_SERVER['HTTP_USER_AGENT'], 'msnbot') !== false ) {  // MSN Search
    1598              return true;
    1599          } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'bingbot') !== false ) {  // Bing
    1600              return true;
    1601          } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'Yandex') !== false ) {
    1602              return true;
    1603          } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'AltaVista') !== false ) {
    1604              return true;
    1605          } else if (stripos($_SERVER['HTTP_USER_AGENT'], 'baiduspider') !== false ) {  // Baidu
    1606              return true;
    1607          } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'Teoma') !== false ) {  // Ask.com
    1608              return true;
    1609          }
    1610      }
    1611      return false;
    1612  }
    1613  
    1614  /**
    1615   * This class solves the problem of how to initialise $OUTPUT.
    1616   *
    1617   * The problem is caused be two factors
    1618   * <ol>
    1619   * <li>On the one hand, we cannot be sure when output will start. In particular,
    1620   * an error, which needs to be displayed, could be thrown at any time.</li>
    1621   * <li>On the other hand, we cannot be sure when we will have all the information
    1622   * necessary to correctly initialise $OUTPUT. $OUTPUT depends on the theme, which
    1623   * (potentially) depends on the current course, course categories, and logged in user.
    1624   * It also depends on whether the current page requires HTTPS.</li>
    1625   * </ol>
    1626   *
    1627   * So, it is hard to find a single natural place during Moodle script execution,
    1628   * which we can guarantee is the right time to initialise $OUTPUT. Instead we
    1629   * adopt the following strategy
    1630   * <ol>
    1631   * <li>We will initialise $OUTPUT the first time it is used.</li>
    1632   * <li>If, after $OUTPUT has been initialised, the script tries to change something
    1633   * that $OUTPUT depends on, we throw an exception making it clear that the script
    1634   * did something wrong.
    1635   * </ol>
    1636   *
    1637   * The only problem with that is, how do we initialise $OUTPUT on first use if,
    1638   * it is going to be used like $OUTPUT->somthing(...)? Well that is where this
    1639   * class comes in. Initially, we set up $OUTPUT = new bootstrap_renderer(). Then,
    1640   * when any method is called on that object, we initialise $OUTPUT, and pass the call on.
    1641   *
    1642   * Note that this class is used before lib/outputlib.php has been loaded, so we
    1643   * must be careful referring to classes/functions from there, they may not be
    1644   * defined yet, and we must avoid fatal errors.
    1645   *
    1646   * @copyright 2009 Tim Hunt
    1647   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
    1648   * @since     Moodle 2.0
    1649   */
    1650  class bootstrap_renderer {
    1651      /**
    1652       * Handles re-entrancy. Without this, errors or debugging output that occur
    1653       * during the initialisation of $OUTPUT, cause infinite recursion.
    1654       * @var boolean
    1655       */
    1656      protected $initialising = false;
    1657  
    1658      /**
    1659       * Have we started output yet?
    1660       * @return boolean true if the header has been printed.
    1661       */
    1662      public function has_started() {
    1663          return false;
    1664      }
    1665  
    1666      /**
    1667       * Constructor - to be used by core code only.
    1668       * @param string $method The method to call
    1669       * @param array $arguments Arguments to pass to the method being called
    1670       * @return string
    1671       */
    1672      public function __call($method, $arguments) {
    1673          global $OUTPUT, $PAGE;
    1674  
    1675          $recursing = false;
    1676          if ($method == 'notification') {
    1677              // Catch infinite recursion caused by debugging output during print_header.
    1678              $backtrace = debug_backtrace();
    1679              array_shift($backtrace);
    1680              array_shift($backtrace);
    1681              $recursing = is_early_init($backtrace);
    1682          }
    1683  
    1684          $earlymethods = array(
    1685              'fatal_error' => 'early_error',
    1686              'notification' => 'early_notification',
    1687          );
    1688  
    1689          // If lib/outputlib.php has been loaded, call it.
    1690          if (!empty($PAGE) && !$recursing) {
    1691              if (array_key_exists($method, $earlymethods)) {
    1692                  //prevent PAGE->context warnings - exceptions might appear before we set any context
    1693                  $PAGE->set_context(null);
    1694              }
    1695              $PAGE->initialise_theme_and_output();
    1696              return call_user_func_array(array($OUTPUT, $method), $arguments);
    1697          }
    1698  
    1699          $this->initialising = true;
    1700  
    1701          // Too soon to initialise $OUTPUT, provide a couple of key methods.
    1702          if (array_key_exists($method, $earlymethods)) {
    1703              return call_user_func_array(array('bootstrap_renderer', $earlymethods[$method]), $arguments);
    1704          }
    1705  
    1706          throw new coding_exception('Attempt to start output before enough information is known to initialise the theme.');
    1707      }
    1708  
    1709      /**
    1710       * Returns nicely formatted error message in a div box.
    1711       * @static
    1712       * @param string $message error message
    1713       * @param string $moreinfourl (ignored in early errors)
    1714       * @param string $link (ignored in early errors)
    1715       * @param array $backtrace
    1716       * @param string $debuginfo
    1717       * @return string
    1718       */
    1719      public static function early_error_content($message, $moreinfourl, $link, $backtrace, $debuginfo = null) {
    1720          global $CFG;
    1721  
    1722          $content = '<div style="margin-top: 6em; margin-left:auto; margin-right:auto; color:#990000; text-align:center; font-size:large; border-width:1px;
    1723  border-color:black; background-color:#ffffee; border-style:solid; border-radius: 20px; border-collapse: collapse;
    1724  width: 80%; -moz-border-radius: 20px; padding: 15px">
    1725  ' . $message . '
    1726  </div>';
    1727          // Check whether debug is set.
    1728          $debug = (!empty($CFG->debug) && $CFG->debug >= DEBUG_DEVELOPER);
    1729          // Also check we have it set in the config file. This occurs if the method to read the config table from the
    1730          // database fails, reading from the config table is the first database interaction we have.
    1731          $debug = $debug || (!empty($CFG->config_php_settings['debug'])  && $CFG->config_php_settings['debug'] >= DEBUG_DEVELOPER );
    1732          if ($debug) {
    1733              if (!empty($debuginfo)) {
    1734                  $debuginfo = s($debuginfo); // removes all nasty JS
    1735                  $debuginfo = str_replace("\n", '<br />', $debuginfo); // keep newlines
    1736                  $content .= '<div class="notifytiny">Debug info: ' . $debuginfo . '</div>';
    1737              }
    1738              if (!empty($backtrace)) {
    1739                  $content .= '<div class="notifytiny">Stack trace: ' . format_backtrace($backtrace, false) . '</div>';
    1740              }
    1741          }
    1742  
    1743          return $content;
    1744      }
    1745  
    1746      /**
    1747       * This function should only be called by this class, or from exception handlers
    1748       * @static
    1749       * @param string $message error message
    1750       * @param string $moreinfourl (ignored in early errors)
    1751       * @param string $link (ignored in early errors)
    1752       * @param array $backtrace
    1753       * @param string $debuginfo extra information for developers
    1754       * @return string
    1755       */
    1756      public static function early_error($message, $moreinfourl, $link, $backtrace, $debuginfo = null, $errorcode = null) {
    1757          global $CFG;
    1758  
    1759          if (CLI_SCRIPT) {
    1760              echo "!!! $message !!!\n";
    1761              if (!empty($CFG->debug) and $CFG->debug >= DEBUG_DEVELOPER) {
    1762                  if (!empty($debuginfo)) {
    1763                      echo "\nDebug info: $debuginfo";
    1764                  }
    1765                  if (!empty($backtrace)) {
    1766                      echo "\nStack trace: " . format_backtrace($backtrace, true);
    1767                  }
    1768              }
    1769              return;
    1770  
    1771          } else if (AJAX_SCRIPT) {
    1772              $e = new stdClass();
    1773              $e->error      = $message;
    1774              $e->stacktrace = NULL;
    1775              $e->debuginfo  = NULL;
    1776              if (!empty($CFG->debug) and $CFG->debug >= DEBUG_DEVELOPER) {
    1777                  if (!empty($debuginfo)) {
    1778                      $e->debuginfo = $debuginfo;
    1779                  }
    1780                  if (!empty($backtrace)) {
    1781                      $e->stacktrace = format_backtrace($backtrace, true);
    1782                  }
    1783              }
    1784              $e->errorcode  = $errorcode;
    1785              @header('Content-Type: application/json; charset=utf-8');
    1786              echo json_encode($e);
    1787              return;
    1788          }
    1789  
    1790          // In the name of protocol correctness, monitoring and performance
    1791          // profiling, set the appropriate error headers for machine consumption.
    1792          $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
    1793          @header($protocol . ' 503 Service Unavailable');
    1794  
    1795          // better disable any caching
    1796          @header('Content-Type: text/html; charset=utf-8');
    1797          @header('X-UA-Compatible: IE=edge');
    1798          @header('Cache-Control: no-store, no-cache, must-revalidate');
    1799          @header('Cache-Control: post-check=0, pre-check=0', false);
    1800          @header('Pragma: no-cache');
    1801          @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT');
    1802          @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
    1803  
    1804          if (function_exists('get_string')) {
    1805              $strerror = get_string('error');
    1806          } else {
    1807              $strerror = 'Error';
    1808          }
    1809  
    1810          $content = self::early_error_content($message, $moreinfourl, $link, $backtrace, $debuginfo);
    1811  
    1812          return self::plain_page($strerror, $content);
    1813      }
    1814  
    1815      /**
    1816       * Early notification message
    1817       * @static
    1818       * @param string $message
    1819       * @param string $classes usually notifyproblem or notifysuccess
    1820       * @return string
    1821       */
    1822      public static function early_notification($message, $classes = 'notifyproblem') {
    1823          return '<div class="' . $classes . '">' . $message . '</div>';
    1824      }
    1825  
    1826      /**
    1827       * Page should redirect message.
    1828       * @static
    1829       * @param string $encodedurl redirect url
    1830       * @return string
    1831       */
    1832      public static function plain_redirect_message($encodedurl) {
    1833          $message = '<div style="margin-top: 3em; margin-left:auto; margin-right:auto; text-align:center;">' . get_string('pageshouldredirect') . '<br /><a href="'.
    1834                  $encodedurl .'">'. get_string('continue') .'</a></div>';
    1835          return self::plain_page(get_string('redirect'), $message);
    1836      }
    1837  
    1838      /**
    1839       * Early redirection page, used before full init of $PAGE global
    1840       * @static
    1841       * @param string $encodedurl redirect url
    1842       * @param string $message redirect message
    1843       * @param int $delay time in seconds
    1844       * @return string redirect page
    1845       */
    1846      public static function early_redirect_message($encodedurl, $message, $delay) {
    1847          $meta = '<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />';
    1848          $content = self::early_error_content($message, null, null, null);
    1849          $content .= self::plain_redirect_message($encodedurl);
    1850  
    1851          return self::plain_page(get_string('redirect'), $content, $meta);
    1852      }
    1853  
    1854      /**
    1855       * Output basic html page.
    1856       * @static
    1857       * @param string $title page title
    1858       * @param string $content page content
    1859       * @param string $meta meta tag
    1860       * @return string html page
    1861       */
    1862      public static function plain_page($title, $content, $meta = '') {
    1863          if (function_exists('get_string') && function_exists('get_html_lang')) {
    1864              $htmllang = get_html_lang();
    1865          } else {
    1866              $htmllang = '';
    1867          }
    1868  
    1869          $footer = '';
    1870          if (MDL_PERF_TEST) {
    1871              $perfinfo = get_performance_info();
    1872              $footer = '<footer>' . $perfinfo['html'] . '</footer>';
    1873          }
    1874  
    1875          return '<!DOCTYPE html>
    1876  <html ' . $htmllang . '>
    1877  <head>
    1878  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    1879  '.$meta.'
    1880  <title>' . $title . '</title>
    1881  </head><body>' . $content . $footer . '</body></html>';
    1882      }
    1883  }
    

    Search This Site: