/lib/weblib.php
PHP | 3722 lines | 1906 code | 421 blank | 1395 comment | 423 complexity | 89b73942c37686b4da2edb59f0887bc7 MD5 | raw file
Possible License(s): MIT, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, Apache-2.0, LGPL-2.1, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- <?php
- // This file is part of Moodle - http://moodle.org/
- //
- // Moodle is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // Moodle is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
- /**
- * Library of functions for web output
- *
- * Library of all general-purpose Moodle PHP functions and constants
- * that produce HTML output
- *
- * Other main libraries:
- * - datalib.php - functions that access the database.
- * - moodlelib.php - general-purpose Moodle functions.
- *
- * @package core
- * @subpackage lib
- * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- defined('MOODLE_INTERNAL') || die();
- // Constants.
- // Define text formatting types ... eventually we can add Wiki, BBcode etc.
- /**
- * Does all sorts of transformations and filtering.
- */
- define('FORMAT_MOODLE', '0');
- /**
- * Plain HTML (with some tags stripped).
- */
- define('FORMAT_HTML', '1');
- /**
- * Plain text (even tags are printed in full).
- */
- define('FORMAT_PLAIN', '2');
- /**
- * Wiki-formatted text.
- * Deprecated: left here just to note that '3' is not used (at the moment)
- * and to catch any latent wiki-like text (which generates an error)
- * @deprecated since 2005!
- */
- define('FORMAT_WIKI', '3');
- /**
- * Markdown-formatted text http://daringfireball.net/projects/markdown/
- */
- define('FORMAT_MARKDOWN', '4');
- /**
- * A moodle_url comparison using this flag will return true if the base URLs match, params are ignored.
- */
- define('URL_MATCH_BASE', 0);
- /**
- * A moodle_url comparison using this flag will return true if the base URLs match and the params of url1 are part of url2.
- */
- define('URL_MATCH_PARAMS', 1);
- /**
- * A moodle_url comparison using this flag will return true if the two URLs are identical, except for the order of the params.
- */
- define('URL_MATCH_EXACT', 2);
- // Functions.
- /**
- * Add quotes to HTML characters.
- *
- * Returns $var with HTML characters (like "<", ">", etc.) properly quoted.
- * Related function {@link p()} simply prints the output of this function.
- *
- * @param string $var the string potentially containing HTML characters
- * @return string
- */
- function s($var) {
- if ($var === false) {
- return '0';
- }
- return preg_replace('/&#(\d+|x[0-9a-f]+);/i', '&#$1;',
- htmlspecialchars($var, ENT_QUOTES | ENT_HTML401 | ENT_SUBSTITUTE));
- }
- /**
- * Add quotes to HTML characters.
- *
- * Prints $var with HTML characters (like "<", ">", etc.) properly quoted.
- * This function simply calls & displays {@link s()}.
- * @see s()
- *
- * @param string $var the string potentially containing HTML characters
- * @return string
- */
- function p($var) {
- echo s($var);
- }
- /**
- * Does proper javascript quoting.
- *
- * Do not use addslashes anymore, because it does not work when magic_quotes_sybase is enabled.
- *
- * @param mixed $var String, Array, or Object to add slashes to
- * @return mixed quoted result
- */
- function addslashes_js($var) {
- if (is_string($var)) {
- $var = str_replace('\\', '\\\\', $var);
- $var = str_replace(array('\'', '"', "\n", "\r", "\0"), array('\\\'', '\\"', '\\n', '\\r', '\\0'), $var);
- $var = str_replace('</', '<\/', $var); // XHTML compliance.
- } else if (is_array($var)) {
- $var = array_map('addslashes_js', $var);
- } else if (is_object($var)) {
- $a = get_object_vars($var);
- foreach ($a as $key => $value) {
- $a[$key] = addslashes_js($value);
- }
- $var = (object)$a;
- }
- return $var;
- }
- /**
- * Remove query string from url.
- *
- * Takes in a URL and returns it without the querystring portion.
- *
- * @param string $url the url which may have a query string attached.
- * @return string The remaining URL.
- */
- function strip_querystring($url) {
- if ($commapos = strpos($url, '?')) {
- return substr($url, 0, $commapos);
- } else {
- return $url;
- }
- }
- /**
- * Returns the name of the current script, WITH the querystring portion.
- *
- * This function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
- * return different things depending on a lot of things like your OS, Web
- * server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.)
- * <b>NOTE:</b> This function returns false if the global variables needed are not set.
- *
- * @return mixed String or false if the global variables needed are not set.
- */
- function me() {
- global $ME;
- return $ME;
- }
- /**
- * Guesses the full URL of the current script.
- *
- * This function is using $PAGE->url, but may fall back to $FULLME which
- * is constructed from PHP_SELF and REQUEST_URI or SCRIPT_NAME
- *
- * @return mixed full page URL string or false if unknown
- */
- function qualified_me() {
- global $FULLME, $PAGE, $CFG;
- if (isset($PAGE) and $PAGE->has_set_url()) {
- // This is the only recommended way to find out current page.
- return $PAGE->url->out(false);
- } else {
- if ($FULLME === null) {
- // CLI script most probably.
- return false;
- }
- if (!empty($CFG->sslproxy)) {
- // Return only https links when using SSL proxy.
- return preg_replace('/^http:/', 'https:', $FULLME, 1);
- } else {
- return $FULLME;
- }
- }
- }
- /**
- * Determines whether or not the Moodle site is being served over HTTPS.
- *
- * This is done simply by checking the value of $CFG->wwwroot, which seems
- * to be the only reliable method.
- *
- * @return boolean True if site is served over HTTPS, false otherwise.
- */
- function is_https() {
- global $CFG;
- return (strpos($CFG->wwwroot, 'https://') === 0);
- }
- /**
- * Returns the cleaned local URL of the HTTP_REFERER less the URL query string parameters if required.
- *
- * @param bool $stripquery if true, also removes the query part of the url.
- * @return string The resulting referer or empty string.
- */
- function get_local_referer($stripquery = true) {
- if (isset($_SERVER['HTTP_REFERER'])) {
- $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
- if ($stripquery) {
- return strip_querystring($referer);
- } else {
- return $referer;
- }
- } else {
- return '';
- }
- }
- /**
- * Class for creating and manipulating urls.
- *
- * It can be used in moodle pages where config.php has been included without any further includes.
- *
- * It is useful for manipulating urls with long lists of params.
- * One situation where it will be useful is a page which links to itself to perform various actions
- * and / or to process form data. A moodle_url object :
- * can be created for a page to refer to itself with all the proper get params being passed from page call to
- * page call and methods can be used to output a url including all the params, optionally adding and overriding
- * params and can also be used to
- * - output the url without any get params
- * - and output the params as hidden fields to be output within a form
- *
- * @copyright 2007 jamiesensei
- * @link http://docs.moodle.org/dev/lib/weblib.php_moodle_url See short write up here
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @package core
- */
- class moodle_url {
- /**
- * Scheme, ex.: http, https
- * @var string
- */
- protected $scheme = '';
- /**
- * Hostname.
- * @var string
- */
- protected $host = '';
- /**
- * Port number, empty means default 80 or 443 in case of http.
- * @var int
- */
- protected $port = '';
- /**
- * Username for http auth.
- * @var string
- */
- protected $user = '';
- /**
- * Password for http auth.
- * @var string
- */
- protected $pass = '';
- /**
- * Script path.
- * @var string
- */
- protected $path = '';
- /**
- * Optional slash argument value.
- * @var string
- */
- protected $slashargument = '';
- /**
- * Anchor, may be also empty, null means none.
- * @var string
- */
- protected $anchor = null;
- /**
- * Url parameters as associative array.
- * @var array
- */
- protected $params = array();
- /**
- * Create new instance of moodle_url.
- *
- * @param moodle_url|string $url - moodle_url means make a copy of another
- * moodle_url and change parameters, string means full url or shortened
- * form (ex.: '/course/view.php'). It is strongly encouraged to not include
- * query string because it may result in double encoded values. Use the
- * $params instead. For admin URLs, just use /admin/script.php, this
- * class takes care of the $CFG->admin issue.
- * @param array $params these params override current params or add new
- * @param string $anchor The anchor to use as part of the URL if there is one.
- * @throws moodle_exception
- */
- public function __construct($url, array $params = null, $anchor = null) {
- global $CFG;
- if ($url instanceof moodle_url) {
- $this->scheme = $url->scheme;
- $this->host = $url->host;
- $this->port = $url->port;
- $this->user = $url->user;
- $this->pass = $url->pass;
- $this->path = $url->path;
- $this->slashargument = $url->slashargument;
- $this->params = $url->params;
- $this->anchor = $url->anchor;
- } else {
- // Detect if anchor used.
- $apos = strpos($url, '#');
- if ($apos !== false) {
- $anchor = substr($url, $apos);
- $anchor = ltrim($anchor, '#');
- $this->set_anchor($anchor);
- $url = substr($url, 0, $apos);
- }
- // Normalise shortened form of our url ex.: '/course/view.php'.
- if (strpos($url, '/') === 0) {
- $url = $CFG->wwwroot.$url;
- }
- if ($CFG->admin !== 'admin') {
- if (strpos($url, "$CFG->wwwroot/admin/") === 0) {
- $url = str_replace("$CFG->wwwroot/admin/", "$CFG->wwwroot/$CFG->admin/", $url);
- }
- }
- // Parse the $url.
- $parts = parse_url($url);
- if ($parts === false) {
- throw new moodle_exception('invalidurl');
- }
- if (isset($parts['query'])) {
- // Note: the values may not be correctly decoded, url parameters should be always passed as array.
- parse_str(str_replace('&', '&', $parts['query']), $this->params);
- }
- unset($parts['query']);
- foreach ($parts as $key => $value) {
- $this->$key = $value;
- }
- // Detect slashargument value from path - we do not support directory names ending with .php.
- $pos = strpos($this->path, '.php/');
- if ($pos !== false) {
- $this->slashargument = substr($this->path, $pos + 4);
- $this->path = substr($this->path, 0, $pos + 4);
- }
- }
- $this->params($params);
- if ($anchor !== null) {
- $this->anchor = (string)$anchor;
- }
- }
- /**
- * Add an array of params to the params for this url.
- *
- * The added params override existing ones if they have the same name.
- *
- * @param array $params Defaults to null. If null then returns all params.
- * @return array Array of Params for url.
- * @throws coding_exception
- */
- public function params(array $params = null) {
- $params = (array)$params;
- foreach ($params as $key => $value) {
- if (is_int($key)) {
- throw new coding_exception('Url parameters can not have numeric keys!');
- }
- if (!is_string($value)) {
- if (is_array($value)) {
- throw new coding_exception('Url parameters values can not be arrays!');
- }
- if (is_object($value) and !method_exists($value, '__toString')) {
- throw new coding_exception('Url parameters values can not be objects, unless __toString() is defined!');
- }
- }
- $this->params[$key] = (string)$value;
- }
- return $this->params;
- }
- /**
- * Remove all params if no arguments passed.
- * Remove selected params if arguments are passed.
- *
- * Can be called as either remove_params('param1', 'param2')
- * or remove_params(array('param1', 'param2')).
- *
- * @param string[]|string $params,... either an array of param names, or 1..n string params to remove as args.
- * @return array url parameters
- */
- public function remove_params($params = null) {
- if (!is_array($params)) {
- $params = func_get_args();
- }
- foreach ($params as $param) {
- unset($this->params[$param]);
- }
- return $this->params;
- }
- /**
- * Remove all url parameters.
- *
- * @todo remove the unused param.
- * @param array $params Unused param
- * @return void
- */
- public function remove_all_params($params = null) {
- $this->params = array();
- $this->slashargument = '';
- }
- /**
- * Add a param to the params for this url.
- *
- * The added param overrides existing one if they have the same name.
- *
- * @param string $paramname name
- * @param string $newvalue Param value. If new value specified current value is overriden or parameter is added
- * @return mixed string parameter value, null if parameter does not exist
- */
- public function param($paramname, $newvalue = '') {
- if (func_num_args() > 1) {
- // Set new value.
- $this->params(array($paramname => $newvalue));
- }
- if (isset($this->params[$paramname])) {
- return $this->params[$paramname];
- } else {
- return null;
- }
- }
- /**
- * Merges parameters and validates them
- *
- * @param array $overrideparams
- * @return array merged parameters
- * @throws coding_exception
- */
- protected function merge_overrideparams(array $overrideparams = null) {
- $overrideparams = (array)$overrideparams;
- $params = $this->params;
- foreach ($overrideparams as $key => $value) {
- if (is_int($key)) {
- throw new coding_exception('Overridden parameters can not have numeric keys!');
- }
- if (is_array($value)) {
- throw new coding_exception('Overridden parameters values can not be arrays!');
- }
- if (is_object($value) and !method_exists($value, '__toString')) {
- throw new coding_exception('Overridden parameters values can not be objects, unless __toString() is defined!');
- }
- $params[$key] = (string)$value;
- }
- return $params;
- }
- /**
- * Get the params as as a query string.
- *
- * This method should not be used outside of this method.
- *
- * @param bool $escaped Use & as params separator instead of plain &
- * @param array $overrideparams params to add to the output params, these
- * override existing ones with the same name.
- * @return string query string that can be added to a url.
- */
- public function get_query_string($escaped = true, array $overrideparams = null) {
- $arr = array();
- if ($overrideparams !== null) {
- $params = $this->merge_overrideparams($overrideparams);
- } else {
- $params = $this->params;
- }
- foreach ($params as $key => $val) {
- if (is_array($val)) {
- foreach ($val as $index => $value) {
- $arr[] = rawurlencode($key.'['.$index.']')."=".rawurlencode($value);
- }
- } else {
- if (isset($val) && $val !== '') {
- $arr[] = rawurlencode($key)."=".rawurlencode($val);
- } else {
- $arr[] = rawurlencode($key);
- }
- }
- }
- if ($escaped) {
- return implode('&', $arr);
- } else {
- return implode('&', $arr);
- }
- }
- /**
- * Shortcut for printing of encoded URL.
- *
- * @return string
- */
- public function __toString() {
- return $this->out(true);
- }
- /**
- * Output url.
- *
- * If you use the returned URL in HTML code, you want the escaped ampersands. If you use
- * the returned URL in HTTP headers, you want $escaped=false.
- *
- * @param bool $escaped Use & as params separator instead of plain &
- * @param array $overrideparams params to add to the output url, these override existing ones with the same name.
- * @return string Resulting URL
- */
- public function out($escaped = true, array $overrideparams = null) {
- global $CFG;
- if (!is_bool($escaped)) {
- debugging('Escape parameter must be of type boolean, '.gettype($escaped).' given instead.');
- }
- $url = $this;
- // Allow url's to be rewritten by a plugin.
- if (isset($CFG->urlrewriteclass) && !isset($CFG->upgraderunning)) {
- $class = $CFG->urlrewriteclass;
- $pluginurl = $class::url_rewrite($url);
- if ($pluginurl instanceof moodle_url) {
- $url = $pluginurl;
- }
- }
- return $url->raw_out($escaped, $overrideparams);
- }
- /**
- * Output url without any rewrites
- *
- * This is identical in signature and use to out() but doesn't call the rewrite handler.
- *
- * @param bool $escaped Use & as params separator instead of plain &
- * @param array $overrideparams params to add to the output url, these override existing ones with the same name.
- * @return string Resulting URL
- */
- public function raw_out($escaped = true, array $overrideparams = null) {
- if (!is_bool($escaped)) {
- debugging('Escape parameter must be of type boolean, '.gettype($escaped).' given instead.');
- }
- $uri = $this->out_omit_querystring().$this->slashargument;
- $querystring = $this->get_query_string($escaped, $overrideparams);
- if ($querystring !== '') {
- $uri .= '?' . $querystring;
- }
- if (!is_null($this->anchor)) {
- $uri .= '#'.$this->anchor;
- }
- return $uri;
- }
- /**
- * Returns url without parameters, everything before '?'.
- *
- * @param bool $includeanchor if {@link self::anchor} is defined, should it be returned?
- * @return string
- */
- public function out_omit_querystring($includeanchor = false) {
- $uri = $this->scheme ? $this->scheme.':'.((strtolower($this->scheme) == 'mailto') ? '':'//'): '';
- $uri .= $this->user ? $this->user.($this->pass? ':'.$this->pass:'').'@':'';
- $uri .= $this->host ? $this->host : '';
- $uri .= $this->port ? ':'.$this->port : '';
- $uri .= $this->path ? $this->path : '';
- if ($includeanchor and !is_null($this->anchor)) {
- $uri .= '#' . $this->anchor;
- }
- return $uri;
- }
- /**
- * Compares this moodle_url with another.
- *
- * See documentation of constants for an explanation of the comparison flags.
- *
- * @param moodle_url $url The moodle_url object to compare
- * @param int $matchtype The type of comparison (URL_MATCH_BASE, URL_MATCH_PARAMS, URL_MATCH_EXACT)
- * @return bool
- */
- public function compare(moodle_url $url, $matchtype = URL_MATCH_EXACT) {
- $baseself = $this->out_omit_querystring();
- $baseother = $url->out_omit_querystring();
- // Append index.php if there is no specific file.
- if (substr($baseself, -1) == '/') {
- $baseself .= 'index.php';
- }
- if (substr($baseother, -1) == '/') {
- $baseother .= 'index.php';
- }
- // Compare the two base URLs.
- if ($baseself != $baseother) {
- return false;
- }
- if ($matchtype == URL_MATCH_BASE) {
- return true;
- }
- $urlparams = $url->params();
- foreach ($this->params() as $param => $value) {
- if ($param == 'sesskey') {
- continue;
- }
- if (!array_key_exists($param, $urlparams) || $urlparams[$param] != $value) {
- return false;
- }
- }
- if ($matchtype == URL_MATCH_PARAMS) {
- return true;
- }
- foreach ($urlparams as $param => $value) {
- if ($param == 'sesskey') {
- continue;
- }
- if (!array_key_exists($param, $this->params()) || $this->param($param) != $value) {
- return false;
- }
- }
- if ($url->anchor !== $this->anchor) {
- return false;
- }
- return true;
- }
- /**
- * Sets the anchor for the URI (the bit after the hash)
- *
- * @param string $anchor null means remove previous
- */
- public function set_anchor($anchor) {
- if (is_null($anchor)) {
- // Remove.
- $this->anchor = null;
- } else if ($anchor === '') {
- // Special case, used as empty link.
- $this->anchor = '';
- } else if (preg_match('|[a-zA-Z\_\:][a-zA-Z0-9\_\-\.\:]*|', $anchor)) {
- // Match the anchor against the NMTOKEN spec.
- $this->anchor = $anchor;
- } else {
- // Bad luck, no valid anchor found.
- $this->anchor = null;
- }
- }
- /**
- * Sets the scheme for the URI (the bit before ://)
- *
- * @param string $scheme
- */
- public function set_scheme($scheme) {
- // See http://www.ietf.org/rfc/rfc3986.txt part 3.1.
- if (preg_match('/^[a-zA-Z][a-zA-Z0-9+.-]*$/', $scheme)) {
- $this->scheme = $scheme;
- } else {
- throw new coding_exception('Bad URL scheme.');
- }
- }
- /**
- * Sets the url slashargument value.
- *
- * @param string $path usually file path
- * @param string $parameter name of page parameter if slasharguments not supported
- * @param bool $supported usually null, then it depends on $CFG->slasharguments, use true or false for other servers
- * @return void
- */
- public function set_slashargument($path, $parameter = 'file', $supported = null) {
- global $CFG;
- if (is_null($supported)) {
- $supported = !empty($CFG->slasharguments);
- }
- if ($supported) {
- $parts = explode('/', $path);
- $parts = array_map('rawurlencode', $parts);
- $path = implode('/', $parts);
- $this->slashargument = $path;
- unset($this->params[$parameter]);
- } else {
- $this->slashargument = '';
- $this->params[$parameter] = $path;
- }
- }
- // Static factory methods.
- /**
- * General moodle file url.
- *
- * @param string $urlbase the script serving the file
- * @param string $path
- * @param bool $forcedownload
- * @return moodle_url
- */
- public static function make_file_url($urlbase, $path, $forcedownload = false) {
- $params = array();
- if ($forcedownload) {
- $params['forcedownload'] = 1;
- }
- $url = new moodle_url($urlbase, $params);
- $url->set_slashargument($path);
- return $url;
- }
- /**
- * Factory method for creation of url pointing to plugin file.
- *
- * Please note this method can be used only from the plugins to
- * create urls of own files, it must not be used outside of plugins!
- *
- * @param int $contextid
- * @param string $component
- * @param string $area
- * @param int $itemid
- * @param string $pathname
- * @param string $filename
- * @param bool $forcedownload
- * @param mixed $includetoken Whether to use a user token when displaying this group image.
- * True indicates to generate a token for current user, and integer value indicates to generate a token for the
- * user whose id is the value indicated.
- * If the group picture is included in an e-mail or some other location where the audience is a specific
- * user who will not be logged in when viewing, then we use a token to authenticate the user.
- * @return moodle_url
- */
- public static function make_pluginfile_url($contextid, $component, $area, $itemid, $pathname, $filename,
- $forcedownload = false, $includetoken = false) {
- global $CFG, $USER;
- $path = [];
- if ($includetoken) {
- $urlbase = "$CFG->wwwroot/tokenpluginfile.php";
- $userid = $includetoken === true ? $USER->id : $includetoken;
- $token = get_user_key('core_files', $userid);
- if ($CFG->slasharguments) {
- $path[] = $token;
- }
- } else {
- $urlbase = "$CFG->wwwroot/pluginfile.php";
- }
- $path[] = $contextid;
- $path[] = $component;
- $path[] = $area;
- if ($itemid !== null) {
- $path[] = $itemid;
- }
- $path = "/" . implode('/', $path) . "{$pathname}{$filename}";
- $url = self::make_file_url($urlbase, $path, $forcedownload, $includetoken);
- if ($includetoken && empty($CFG->slasharguments)) {
- $url->param('token', $token);
- }
- return $url;
- }
- /**
- * Factory method for creation of url pointing to plugin file.
- * This method is the same that make_pluginfile_url but pointing to the webservice pluginfile.php script.
- * It should be used only in external functions.
- *
- * @since 2.8
- * @param int $contextid
- * @param string $component
- * @param string $area
- * @param int $itemid
- * @param string $pathname
- * @param string $filename
- * @param bool $forcedownload
- * @return moodle_url
- */
- public static function make_webservice_pluginfile_url($contextid, $component, $area, $itemid, $pathname, $filename,
- $forcedownload = false) {
- global $CFG;
- $urlbase = "$CFG->wwwroot/webservice/pluginfile.php";
- if ($itemid === null) {
- return self::make_file_url($urlbase, "/$contextid/$component/$area".$pathname.$filename, $forcedownload);
- } else {
- return self::make_file_url($urlbase, "/$contextid/$component/$area/$itemid".$pathname.$filename, $forcedownload);
- }
- }
- /**
- * Factory method for creation of url pointing to draft file of current user.
- *
- * @param int $draftid draft item id
- * @param string $pathname
- * @param string $filename
- * @param bool $forcedownload
- * @return moodle_url
- */
- public static function make_draftfile_url($draftid, $pathname, $filename, $forcedownload = false) {
- global $CFG, $USER;
- $urlbase = "$CFG->wwwroot/draftfile.php";
- $context = context_user::instance($USER->id);
- return self::make_file_url($urlbase, "/$context->id/user/draft/$draftid".$pathname.$filename, $forcedownload);
- }
- /**
- * Factory method for creating of links to legacy course files.
- *
- * @param int $courseid
- * @param string $filepath
- * @param bool $forcedownload
- * @return moodle_url
- */
- public static function make_legacyfile_url($courseid, $filepath, $forcedownload = false) {
- global $CFG;
- $urlbase = "$CFG->wwwroot/file.php";
- return self::make_file_url($urlbase, '/'.$courseid.'/'.$filepath, $forcedownload);
- }
- /**
- * Returns URL a relative path from $CFG->wwwroot
- *
- * Can be used for passing around urls with the wwwroot stripped
- *
- * @param boolean $escaped Use & as params separator instead of plain &
- * @param array $overrideparams params to add to the output url, these override existing ones with the same name.
- * @return string Resulting URL
- * @throws coding_exception if called on a non-local url
- */
- public function out_as_local_url($escaped = true, array $overrideparams = null) {
- global $CFG;
- $url = $this->out($escaped, $overrideparams);
- // Url should be equal to wwwroot. If not then throw exception.
- if (($url === $CFG->wwwroot) || (strpos($url, $CFG->wwwroot.'/') === 0)) {
- $localurl = substr($url, strlen($CFG->wwwroot));
- return !empty($localurl) ? $localurl : '';
- } else {
- throw new coding_exception('out_as_local_url called on a non-local URL');
- }
- }
- /**
- * Returns the 'path' portion of a URL. For example, if the URL is
- * http://www.example.org:447/my/file/is/here.txt?really=1 then this will
- * return '/my/file/is/here.txt'.
- *
- * By default the path includes slash-arguments (for example,
- * '/myfile.php/extra/arguments') so it is what you would expect from a
- * URL path. If you don't want this behaviour, you can opt to exclude the
- * slash arguments. (Be careful: if the $CFG variable slasharguments is
- * disabled, these URLs will have a different format and you may need to
- * look at the 'file' parameter too.)
- *
- * @param bool $includeslashargument If true, includes slash arguments
- * @return string Path of URL
- */
- public function get_path($includeslashargument = true) {
- return $this->path . ($includeslashargument ? $this->slashargument : '');
- }
- /**
- * Returns a given parameter value from the URL.
- *
- * @param string $name Name of parameter
- * @return string Value of parameter or null if not set
- */
- public function get_param($name) {
- if (array_key_exists($name, $this->params)) {
- return $this->params[$name];
- } else {
- return null;
- }
- }
- /**
- * Returns the 'scheme' portion of a URL. For example, if the URL is
- * http://www.example.org:447/my/file/is/here.txt?really=1 then this will
- * return 'http' (without the colon).
- *
- * @return string Scheme of the URL.
- */
- public function get_scheme() {
- return $this->scheme;
- }
- /**
- * Returns the 'host' portion of a URL. For example, if the URL is
- * http://www.example.org:447/my/file/is/here.txt?really=1 then this will
- * return 'www.example.org'.
- *
- * @return string Host of the URL.
- */
- public function get_host() {
- return $this->host;
- }
- /**
- * Returns the 'port' portion of a URL. For example, if the URL is
- * http://www.example.org:447/my/file/is/here.txt?really=1 then this will
- * return '447'.
- *
- * @return string Port of the URL.
- */
- public function get_port() {
- return $this->port;
- }
- }
- /**
- * Determine if there is data waiting to be processed from a form
- *
- * Used on most forms in Moodle to check for data
- * Returns the data as an object, if it's found.
- * This object can be used in foreach loops without
- * casting because it's cast to (array) automatically
- *
- * Checks that submitted POST data exists and returns it as object.
- *
- * @return mixed false or object
- */
- function data_submitted() {
- if (empty($_POST)) {
- return false;
- } else {
- return (object)fix_utf8($_POST);
- }
- }
- /**
- * Given some normal text this function will break up any
- * long words to a given size by inserting the given character
- *
- * It's multibyte savvy and doesn't change anything inside html tags.
- *
- * @param string $string the string to be modified
- * @param int $maxsize maximum length of the string to be returned
- * @param string $cutchar the string used to represent word breaks
- * @return string
- */
- function break_up_long_words($string, $maxsize=20, $cutchar=' ') {
- // First of all, save all the tags inside the text to skip them.
- $tags = array();
- filter_save_tags($string, $tags);
- // Process the string adding the cut when necessary.
- $output = '';
- $length = core_text::strlen($string);
- $wordlength = 0;
- for ($i=0; $i<$length; $i++) {
- $char = core_text::substr($string, $i, 1);
- if ($char == ' ' or $char == "\t" or $char == "\n" or $char == "\r" or $char == "<" or $char == ">") {
- $wordlength = 0;
- } else {
- $wordlength++;
- if ($wordlength > $maxsize) {
- $output .= $cutchar;
- $wordlength = 0;
- }
- }
- $output .= $char;
- }
- // Finally load the tags back again.
- if (!empty($tags)) {
- $output = str_replace(array_keys($tags), $tags, $output);
- }
- return $output;
- }
- /**
- * Try and close the current window using JavaScript, either immediately, or after a delay.
- *
- * Echo's out the resulting XHTML & javascript
- *
- * @param integer $delay a delay in seconds before closing the window. Default 0.
- * @param boolean $reloadopener if true, we will see if this window was a pop-up, and try
- * to reload the parent window before this one closes.
- */
- function close_window($delay = 0, $reloadopener = false) {
- global $PAGE, $OUTPUT;
- if (!$PAGE->headerprinted) {
- $PAGE->set_title(get_string('closewindow'));
- echo $OUTPUT->header();
- } else {
- $OUTPUT->container_end_all(false);
- }
- if ($reloadopener) {
- // Trigger the reload immediately, even if the reload is after a delay.
- $PAGE->requires->js_function_call('window.opener.location.reload', array(true));
- }
- $OUTPUT->notification(get_string('windowclosing'), 'notifysuccess');
- $PAGE->requires->js_function_call('close_window', array(new stdClass()), false, $delay);
- echo $OUTPUT->footer();
- exit;
- }
- /**
- * Returns a string containing a link to the user documentation for the current page.
- *
- * Also contains an icon by default. Shown to teachers and admin only.
- *
- * @param string $text The text to be displayed for the link
- * @return string The link to user documentation for this current page
- */
- function page_doc_link($text='') {
- global $OUTPUT, $PAGE;
- $path = page_get_doc_link_path($PAGE);
- if (!$path) {
- return '';
- }
- return $OUTPUT->doc_link($path, $text);
- }
- /**
- * Returns the path to use when constructing a link to the docs.
- *
- * @since Moodle 2.5.1 2.6
- * @param moodle_page $page
- * @return string
- */
- function page_get_doc_link_path(moodle_page $page) {
- global $CFG;
- if (empty($CFG->docroot) || during_initial_install()) {
- return '';
- }
- if (!has_capability('moodle/site:doclinks', $page->context)) {
- return '';
- }
- $path = $page->docspath;
- if (!$path) {
- return '';
- }
- return $path;
- }
- /**
- * Validates an email to make sure it makes sense.
- *
- * @param string $address The email address to validate.
- * @return boolean
- */
- function validate_email($address) {
- global $CFG;
- require_once($CFG->libdir.'/phpmailer/moodle_phpmailer.php');
- return moodle_phpmailer::validateAddress($address) && !preg_match('/[<>]/', $address);
- }
- /**
- * Extracts file argument either from file parameter or PATH_INFO
- *
- * Note: $scriptname parameter is not needed anymore
- *
- * @return string file path (only safe characters)
- */
- function get_file_argument() {
- global $SCRIPT;
- $relativepath = false;
- $hasforcedslashargs = false;
- if (isset($_SERVER['REQUEST_URI']) && !empty($_SERVER['REQUEST_URI'])) {
- // Checks whether $_SERVER['REQUEST_URI'] contains '/pluginfile.php/'
- // instead of '/pluginfile.php?', when serving a file from e.g. mod_imscp or mod_scorm.
- if ((strpos($_SERVER['REQUEST_URI'], '/pluginfile.php/') !== false)
- && isset($_SERVER['PATH_INFO']) && !empty($_SERVER['PATH_INFO'])) {
- // Exclude edge cases like '/pluginfile.php/?file='.
- $args = explode('/', ltrim($_SERVER['PATH_INFO'], '/'));
- $hasforcedslashargs = (count($args) > 2); // Always at least: context, component and filearea.
- }
- }
- if (!$hasforcedslashargs) {
- $relativepath = optional_param('file', false, PARAM_PATH);
- }
- if ($relativepath !== false and $relativepath !== '') {
- return $relativepath;
- }
- $relativepath = false;
- // Then try extract file from the slasharguments.
- if (stripos($_SERVER['SERVER_SOFTWARE'], 'iis') !== false) {
- // NOTE: IIS tends to convert all file paths to single byte DOS encoding,
- // we can not use other methods because they break unicode chars,
- // the only ways are to use URL rewriting
- // OR
- // to properly set the 'FastCGIUtf8ServerVariables' registry key.
- if (isset($_SERVER['PATH_INFO']) and $_SERVER['PATH_INFO'] !== '') {
- // Check that PATH_INFO works == must not contain the script name.
- if (strpos($_SERVER['PATH_INFO'], $SCRIPT) === false) {
- $relativepath = clean_param(urldecode($_SERVER['PATH_INFO']), PARAM_PATH);
- }
- }
- } else {
- // All other apache-like servers depend on PATH_INFO.
- if (isset($_SERVER['PATH_INFO'])) {
- if (isset($_SERVER['SCRIPT_NAME']) and strpos($_SERVER['PATH_INFO'], $_SERVER['SCRIPT_NAME']) === 0) {
- $relativepath = substr($_SERVER['PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
- } else {
- $relativepath = $_SERVER['PATH_INFO'];
- }
- $relativepath = clean_param($relativepath, PARAM_PATH);
- }
- }
- return $relativepath;
- }
- /**
- * Just returns an array of text formats suitable for a popup menu
- *
- * @return array
- */
- function format_text_menu() {
- return array (FORMAT_MOODLE => get_string('formattext'),
- FORMAT_HTML => get_string('formathtml'),
- FORMAT_PLAIN => get_string('formatplain'),
- FORMAT_MARKDOWN => get_string('formatmarkdown'));
- }
- /**
- * Given text in a variety of format codings, this function returns the text as safe HTML.
- *
- * This function should mainly be used for long strings like posts,
- * answers, glossary items etc. For short strings {@link format_string()}.
- *
- * <pre>
- * Options:
- * trusted : If true the string won't be cleaned. Default false required noclean=true.
- * noclean : If true the string won't be cleaned, unless $CFG->forceclean is set. Default false required trusted=true.
- * nocache : If true the strign will not be cached and will be formatted every call. Default false.
- * filter : If true the string will be run through applicable filters as well. Default true.
- * para : If true then the returned string will be wrapped in div tags. Default true.
- * newlines : If true then lines newline breaks will be converted to HTML newline breaks. Default true.
- * context : The context that will be used for filtering.
- * overflowdiv : If set to true the formatted text will be encased in a div
- * with the class no-overflow before being returned. Default false.
- * allowid : If true then id attributes will not be removed, even when
- * using htmlpurifier. Default false.
- * blanktarget : If true all <a> tags will have target="_blank" added unless target is explicitly specified.
- * </pre>
- *
- * @staticvar array $croncache
- * @param string $text The text to be formatted. This is raw text originally from user input.
- * @param int $format Identifier of the text format to be used
- * [FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_MARKDOWN]
- * @param object/array $options text formatting options
- * @param int $courseiddonotuse deprecated course id, use context option instead
- * @return string
- */
- function format_text($text, $format = FORMAT_MOODLE, $options = null, $courseiddonotuse = null) {
- global $CFG, $DB, $PAGE;
- if ($text === '' || is_null($text)) {
- // No need to do any filters and cleaning.
- return '';
- }
- // Detach object, we can not modify it.
- $options = (array)$options;
- if (!isset($options['trusted'])) {
- $options['trusted'] = false;
- }
- if (!isset($options['noclean'])) {
- if ($options['trusted'] and trusttext_active()) {
- // No cleaning if text trusted and noclean not specified.
- $options['noclean'] = true;
- } else {
- $options['noclean'] = false;
- }
- }
- if (!empty($CFG->forceclean)) {
- // Whatever the caller claims, the admin wants all content cleaned anyway.
- $options['noclean'] = false;
- }
- if (!isset($options['nocache'])) {
- $options['nocache'] = false;
- }
- if (!isset($options['filter'])) {
- $options['filter'] = true;
- }
- if (!isset($options['para'])) {
- $options['para'] = true;
- }
- if (!isset($options['newlines'])) {
- $options['newlines'] = true;
- }
- if (!isset($options['overflowdiv'])) {
- $options['overflowdiv'] = false;
- }
- $options['blanktarget'] = !empty($options['blanktarget']);
- // Calculate best context.
- if (empty($CFG->version) or $CFG->version < 2013051400 or during_initial_install()) {
- // Do not filter anything during installation or before upgrade completes.
- $context = null;
- } else if (isset($options['context'])) { // First by explicit passed context option.
- if (is_object($options['context'])) {
- $context = $options['context'];
- } else {
- $context = context::instance_by_id($options['context']);
- }
- } else if ($courseiddonotuse) {
- // Legacy courseid.
- $context = context_course::instance($courseiddonotuse);
- } else {
- // Fallback to $PAGE->context this may be problematic in CLI and other non-standard pages :-(.
- $context = $PAGE->context;
- }
- if (!$context) {
- // Either install/upgrade or something has gone really wrong because context does not exist (yet?).
- $options['nocache'] = true;
- $options['filter'] = false;
- }
- if ($options['filter']) {
- $filtermanager = filter_manager::instance();
- $filtermanager->setup_page_for_filters($PAGE, $context); // Setup global stuff filters may have.
- $filteroptions = array(
- 'originalformat' => $format,
- 'noclean' => $options['noclean'],
- );
- } else {
- $filtermanager = new null_filter_manager();
- $filteroptions = array();
- }
- switch ($format) {
- case FORMAT_HTML:
- if (!$options['noclean']) {
- $text = clean_text($text, FORMAT_HTML, $options);
- }
- $text = $filtermanager->filter_text($text, $context, $filteroptions);
- break;
- case FORMAT_PLAIN:
- $text = s($text); // Cleans dangerous JS.
- $text = rebuildnolinktag($text);
- $text = str_replace(' ', ' ', $text);
- $text = nl2br($text);
- break;
- case FORMAT_WIKI:
- // This format is deprecated.
- $text = '<p>NOTICE: Wiki-like formatting has been removed from Moodle. You should not be seeing
- this message as all texts should have been converted to Markdown format instead.
- Please post a bug report to http://moodle.org/bugs with information about where you
- saw this message.</p>'.s($text);
- break;
- case FORMAT_MARKDOWN:
- $text = markdown_to_html($text);
- if (!$options['noclean']) {
- $text = clean_text($text, FORMAT_HTML, $options);
- }
- $text = $filtermanager->filter_text($text, $context, $filteroptions);
- break;
- default: // FORMAT_MOODLE or anything else.
- $text = text_to_html($text, null, $options['para'], $options['newlines']);
- if (!$options['noclean']) {
- $text = clean_text($text, FORMAT_HTML, $options);
- }
- $text = $filtermanager->filter_text($text, $context, $filteroptions);
- break;
- }
- if ($options['filter']) {
- // At this point there should not be any draftfile links any more,
- // this happens when developers forget to post process the text.
- // The only potential problem is that somebody might try to format
- // the text before storing into database which would be itself big bug..
- $text = str_replace("\"$CFG->wwwroot/draftfile.php", "\"$CFG->wwwroot/brokenfile.php#", $text);
- if ($CFG->debugdeveloper) {
- if (strpos($text, '@@PLUGINFILE@@/') !== false) {
- debugging('Before calling format_text(), the content must be processed with file_rewrite_pluginfile_urls()',
- DEBUG_DEVELOPER);
- }
- }
- }
- if (!empty($options['overflowdiv'])) {
- $text = html_writer::tag('div', $text, array('class' => 'no-overflow'));
- }
- if ($options['blanktarget']) {
- $domdoc = new DOMDocument();
- libxml_use_internal_errors(true);
- $domdoc->loadHTML('<?xml version="1.0" encoding="UTF-8" ?>' . $text);
- libxml_clear_errors();
- foreach ($domdoc->getElementsByTagName('a') as $link) {
- if ($link->hasAttribute('target') && strpos($link->getAttribute('target'), '_blank') === false) {
- continue;
- }
- $link->setAttribute('target', '_blank');
- if (strpos($link->getAttribute('rel'), 'noreferrer') === false) {
- $link->setAttribute('rel', trim($link->getAttribute('rel') . ' noreferrer'));
- }
- }
- // This regex is nasty and I don't like it. The correct way to solve this is by loading the HTML like so:
- // $domdoc->loadHTML($text, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); however it seems like the libxml
- // version that travis uses doesn't work properly and ends up leaving <html><body>, so I'm forced to use
- // this regex to remove those tags.
- $text = trim(preg_replace('~<(?:!DOCTYPE|/?(?:html|body))[^>]*>\s*~i', '', $domdoc->saveHTML($domdoc->documentElement)));
- }
- return $text;
- }
- /**
- * Resets some data related to filters, called during upgrade or when general filter settings change.
- *
- * @param bool $phpunitreset true means called from our PHPUnit integration test reset
- * @return void
- */
- function reset_text_filters_cache($phpunitreset = false) {
- global $CFG, $DB;
- if ($phpunitreset) {
- // HTMLPurifier does not change, DB is already reset to defaults,
- // nothing to do here, the dataroot was cleared too.
- return;
- }
- // The purge_all_caches() deals with cachedir and localcachedir purging,
- // the individual filter caches are invalidated as necessary elsewhere.
- // Update $CFG->filterall cache flag.
- if (empty($CFG->stringfilters)) {
- set_config('filterall', 0);
- return;
- }
- $installedfilters = core_component::get_plugin_list('filter');
- $filters = explode(',', $CFG->stringfilters);
- foreach ($filters as $filter) {
- if (isset($installedfilters[$filter])) {
- set_config('filterall', 1);
- return;
- }
- }
- set_config('filterall', 0);
- }
- /**
- * Given a simple string, this function returns the string
- * processed by enabled string filters if $CFG->filterall is enabled
- *
- * This function should be used to print short strings (non html) that
- * need filter processing e.g. activity titles, post subjects,
- * glossary concepts.
- *
- * @staticvar bool $strcache
- * @param string $string The string to be filtered. Should be plain text, expect
- * possibly for multilang tags.
- * @param boolean $striplinks To strip any link in the result text. Moodle 1.8 default changed from false to true! MDL-8713
- * @param array $options options array/object or courseid
- * @return string
- */
- function format_string($string, $striplinks = true, $options = null) {
- global $CFG, $PAGE;
- // We'll use a in-memory cache here to speed up repeated strings.
- static $strcache = false;
- if (empty($CFG->version) or $CFG->version < 2013051400 or during_initial_install()) {
- // Do not filter anything during installation or before upgrade completes.
- return $string = strip_tags($string);
- }
- if ($strcache === false or count($strcache) > 2000) {
- // This number might need some tuning to limit memory usage in cron.
- $strcache = array();
- }
- if (is_numeric($options)) {
- // Legacy courseid usage.
- $options = array('context' => context_course::instance($options));
- } else {
- // Detach object, we can not modify it.
- $options = (array)$options;
- }
- if (empty($options['context'])) {
- // Fallback to $PAGE->context this may be problematic in CLI and other non-standard pages :-(.
- $options['context'] = $PAGE->context;
- } else if (is_numeric($options['context'])) {
- $options['context'] = context::instance_by_id($options['context']);
- }
- if (!isset($options['filter'])) {
- $options['filter'] = true;
- }
- $option…
Large files files are truncated, but you can click here to view the full file