2009-05-22 03:26:07 +00:00
|
|
|
<?php
|
2009-05-26 06:26:11 +00:00
|
|
|
// This file is part of Moodle - http://moodle.org/
|
|
|
|
//
|
2009-05-22 03:26:07 +00:00
|
|
|
// 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.
|
2009-05-26 06:26:11 +00:00
|
|
|
//
|
2009-05-22 03:26:07 +00:00
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
2001-11-22 06:23:56 +00:00
|
|
|
|
2004-09-23 02:48:41 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2010-07-25 13:35:05 +00:00
|
|
|
* @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
|
2004-09-23 02:48:41 +00:00
|
|
|
*/
|
2005-01-26 15:57:00 +00:00
|
|
|
|
2023-10-25 14:10:13 +08:00
|
|
|
use Psr\Http\Message\UriInterface;
|
|
|
|
|
2010-07-25 13:35:05 +00:00
|
|
|
defined('MOODLE_INTERNAL') || die();
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Constants.
|
2002-10-10 07:26:10 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Define text formatting types ... eventually we can add Wiki, BBcode etc.
|
2004-09-23 02:48:41 +00:00
|
|
|
|
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Does all sorts of transformations and filtering.
|
2004-09-23 02:48:41 +00:00
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
define('FORMAT_MOODLE', '0');
|
2004-09-23 02:48:41 +00:00
|
|
|
|
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Plain HTML (with some tags stripped).
|
2004-09-23 02:48:41 +00:00
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
define('FORMAT_HTML', '1');
|
2004-09-23 02:48:41 +00:00
|
|
|
|
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Plain text (even tags are printed in full).
|
2004-09-23 02:48:41 +00:00
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
define('FORMAT_PLAIN', '2');
|
2004-09-23 02:48:41 +00:00
|
|
|
|
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Wiki-formatted text.
|
2005-04-11 13:46:06 +00:00
|
|
|
* 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)
|
2013-08-05 09:06:56 +12:00
|
|
|
* @deprecated since 2005!
|
2004-09-23 02:48:41 +00:00
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
define('FORMAT_WIKI', '3');
|
2004-09-23 02:48:41 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Markdown-formatted text http://daringfireball.net/projects/markdown/
|
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
define('FORMAT_MARKDOWN', '4');
|
2002-10-10 07:26:10 +00:00
|
|
|
|
2009-08-10 03:04:01 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* A moodle_url comparison using this flag will return true if the base URLs match, params are ignored.
|
2009-08-10 03:04:01 +00:00
|
|
|
*/
|
|
|
|
define('URL_MATCH_BASE', 0);
|
2013-08-05 09:06:56 +12:00
|
|
|
|
2009-08-10 03:04:01 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* A moodle_url comparison using this flag will return true if the base URLs match and the params of url1 are part of url2.
|
2009-08-10 03:04:01 +00:00
|
|
|
*/
|
|
|
|
define('URL_MATCH_PARAMS', 1);
|
2013-08-05 09:06:56 +12:00
|
|
|
|
2009-08-10 03:04:01 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* A moodle_url comparison using this flag will return true if the two URLs are identical, except for the order of the params.
|
2009-08-10 03:04:01 +00:00
|
|
|
*/
|
|
|
|
define('URL_MATCH_EXACT', 2);
|
2004-09-23 02:48:41 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Functions.
|
2002-10-10 07:26:10 +00:00
|
|
|
|
2004-09-23 02:48:41 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Add quotes to HTML characters.
|
2004-09-23 02:48:41 +00:00
|
|
|
*
|
|
|
|
* Returns $var with HTML characters (like "<", ">", etc.) properly quoted.
|
2015-05-21 19:12:40 +02:00
|
|
|
* Related function {@link p()} simply prints the output of this function.
|
2004-09-23 02:48:41 +00:00
|
|
|
*
|
|
|
|
* @param string $var the string potentially containing HTML characters
|
|
|
|
* @return string
|
|
|
|
*/
|
2013-04-26 15:59:53 +01:00
|
|
|
function s($var) {
|
|
|
|
if ($var === false) {
|
2005-07-09 07:20:52 +00:00
|
|
|
return '0';
|
2003-05-26 14:43:19 +00:00
|
|
|
}
|
2006-04-12 17:39:23 +00:00
|
|
|
|
2023-01-06 22:37:07 +08:00
|
|
|
if ($var === null || $var === '') {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
return preg_replace(
|
|
|
|
'/&#(\d+|x[0-9a-f]+);/i', '&#$1;',
|
|
|
|
htmlspecialchars($var, ENT_QUOTES | ENT_HTML401 | ENT_SUBSTITUTE)
|
|
|
|
);
|
2001-11-22 06:23:56 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 02:48:41 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Add quotes to HTML characters.
|
2004-09-23 02:48:41 +00:00
|
|
|
*
|
2004-09-23 04:36:43 +00:00
|
|
|
* Prints $var with HTML characters (like "<", ">", etc.) properly quoted.
|
2015-05-21 19:12:40 +02:00
|
|
|
* This function simply calls & displays {@link s()}.
|
2009-05-22 03:26:07 +00:00
|
|
|
* @see s()
|
|
|
|
*
|
2004-09-23 02:48:41 +00:00
|
|
|
* @param string $var the string potentially containing HTML characters
|
|
|
|
*/
|
2015-05-21 19:12:40 +02:00
|
|
|
function p($var) {
|
|
|
|
echo s($var);
|
2001-11-22 06:23:56 +00:00
|
|
|
}
|
|
|
|
|
2006-12-30 22:45:40 +00:00
|
|
|
/**
|
|
|
|
* Does proper javascript quoting.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2007-01-04 10:23:06 +00:00
|
|
|
* Do not use addslashes anymore, because it does not work when magic_quotes_sybase is enabled.
|
|
|
|
*
|
2009-05-22 03:26:07 +00:00
|
|
|
* @param mixed $var String, Array, or Object to add slashes to
|
2006-12-30 22:45:40 +00:00
|
|
|
* @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);
|
2013-08-05 09:06:56 +12:00
|
|
|
$var = str_replace('</', '<\/', $var); // XHTML compliance.
|
2006-12-30 22:45:40 +00:00
|
|
|
} else if (is_array($var)) {
|
|
|
|
$var = array_map('addslashes_js', $var);
|
|
|
|
} else if (is_object($var)) {
|
|
|
|
$a = get_object_vars($var);
|
2013-08-05 09:06:56 +12:00
|
|
|
foreach ($a as $key => $value) {
|
|
|
|
$a[$key] = addslashes_js($value);
|
2006-12-30 22:45:40 +00:00
|
|
|
}
|
|
|
|
$var = (object)$a;
|
|
|
|
}
|
|
|
|
return $var;
|
|
|
|
}
|
2004-09-23 02:48:41 +00:00
|
|
|
|
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Remove query string from url.
|
2004-09-23 02:48:41 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* Takes in a URL and returns it without the querystring portion.
|
2004-09-23 02:48:41 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param string $url the url which may have a query string attached.
|
|
|
|
* @return string The remaining URL.
|
2004-09-23 02:48:41 +00:00
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
function strip_querystring($url) {
|
2023-01-06 22:36:54 +08:00
|
|
|
if ($url === null || $url === '') {
|
|
|
|
return '';
|
|
|
|
}
|
2001-11-22 06:23:56 +00:00
|
|
|
|
2023-01-06 22:36:54 +08:00
|
|
|
if ($commapos = strpos($url, '?')) {
|
2002-12-30 03:39:42 +00:00
|
|
|
return substr($url, 0, $commapos);
|
|
|
|
} else {
|
|
|
|
return $url;
|
|
|
|
}
|
2001-11-22 06:23:56 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 02:48:41 +00:00
|
|
|
/**
|
|
|
|
* Returns the name of the current script, WITH the querystring portion.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
|
|
|
* This function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
|
2004-09-23 02:48:41 +00:00
|
|
|
* 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.)
|
2004-09-23 04:36:43 +00:00
|
|
|
* <b>NOTE:</b> This function returns false if the global variables needed are not set.
|
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @return mixed String or false if the global variables needed are not set.
|
2004-09-23 02:48:41 +00:00
|
|
|
*/
|
2009-06-17 08:50:16 +00:00
|
|
|
function me() {
|
|
|
|
global $ME;
|
|
|
|
return $ME;
|
2001-11-22 06:23:56 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 02:48:41 +00:00
|
|
|
/**
|
2012-04-22 17:17:27 +02:00
|
|
|
* Guesses the full URL of the current script.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2012-04-22 17:17:27 +02:00
|
|
|
* This function is using $PAGE->url, but may fall back to $FULLME which
|
|
|
|
* is constructed from PHP_SELF and REQUEST_URI or SCRIPT_NAME
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2012-04-22 17:17:27 +02:00
|
|
|
* @return mixed full page URL string or false if unknown
|
2004-09-23 02:48:41 +00:00
|
|
|
*/
|
2001-11-22 06:23:56 +00:00
|
|
|
function qualified_me() {
|
2012-04-22 17:17:27 +02:00
|
|
|
global $FULLME, $PAGE, $CFG;
|
|
|
|
|
|
|
|
if (isset($PAGE) and $PAGE->has_set_url()) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// This is the only recommended way to find out current page.
|
2012-04-22 17:17:27 +02:00
|
|
|
return $PAGE->url->out(false);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if ($FULLME === null) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// CLI script most probably.
|
2012-04-22 17:17:27 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!empty($CFG->sslproxy)) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Return only https links when using SSL proxy.
|
2012-04-22 17:17:27 +02:00
|
|
|
return preg_replace('/^http:/', 'https:', $FULLME, 1);
|
|
|
|
} else {
|
|
|
|
return $FULLME;
|
|
|
|
}
|
|
|
|
}
|
2001-11-22 06:23:56 +00:00
|
|
|
}
|
|
|
|
|
2014-08-15 15:41:56 +01:00
|
|
|
/**
|
|
|
|
* Determines whether or not the Moodle site is being served over HTTPS.
|
|
|
|
*
|
2017-09-15 10:09:01 +08:00
|
|
|
* This is done simply by checking the value of $CFG->wwwroot, which seems
|
2014-08-15 15:41:56 +01:00
|
|
|
* to be the only reliable method.
|
|
|
|
*
|
|
|
|
* @return boolean True if site is served over HTTPS, false otherwise.
|
|
|
|
*/
|
|
|
|
function is_https() {
|
|
|
|
global $CFG;
|
|
|
|
|
2017-09-15 10:09:01 +08:00
|
|
|
return (strpos($CFG->wwwroot, 'https://') === 0);
|
2014-08-15 15:41:56 +01:00
|
|
|
}
|
|
|
|
|
2015-06-12 14:27:55 +08:00
|
|
|
/**
|
|
|
|
* 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 '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-03 04:34:53 +00:00
|
|
|
/**
|
|
|
|
* Class for creating and manipulating urls.
|
2007-06-19 14:44:02 +00:00
|
|
|
*
|
2009-05-22 03:26:07 +00:00
|
|
|
* It can be used in moodle pages where config.php has been included without any further includes.
|
|
|
|
*
|
2009-08-04 02:05:32 +00:00
|
|
|
* It is useful for manipulating urls with long lists of params.
|
2010-05-22 20:31:11 +00:00
|
|
|
* One situation where it will be useful is a page which links to itself to perform various actions
|
2009-05-22 03:26:07 +00:00
|
|
|
* and / or to process form data. A moodle_url object :
|
2009-08-04 02:05:32 +00:00
|
|
|
* 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
|
2009-05-22 03:26:07 +00:00
|
|
|
* params and can also be used to
|
|
|
|
* - output the url without any get params
|
2009-08-04 02:05:32 +00:00
|
|
|
* - and output the params as hidden fields to be output within a form
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @copyright 2007 jamiesensei
|
2009-05-22 03:26:07 +00:00
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2013-08-05 09:06:56 +12:00
|
|
|
* @package core
|
2007-05-03 04:34:53 +00:00
|
|
|
*/
|
|
|
|
class moodle_url {
|
2013-08-05 09:06:56 +12:00
|
|
|
|
2009-05-22 03:26:07 +00:00
|
|
|
/**
|
2010-01-16 15:39:56 +00:00
|
|
|
* Scheme, ex.: http, https
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $scheme = '';
|
2013-08-05 09:06:56 +12:00
|
|
|
|
2010-01-16 15:39:56 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Hostname.
|
2009-05-22 03:26:07 +00:00
|
|
|
* @var string
|
|
|
|
*/
|
2009-05-06 08:49:12 +00:00
|
|
|
protected $host = '';
|
2013-08-05 09:06:56 +12:00
|
|
|
|
2010-01-16 15:39:56 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Port number, empty means default 80 or 443 in case of http.
|
|
|
|
* @var int
|
2010-01-16 15:39:56 +00:00
|
|
|
*/
|
2009-05-06 08:49:12 +00:00
|
|
|
protected $port = '';
|
2013-08-05 09:06:56 +12:00
|
|
|
|
2010-01-16 15:39:56 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Username for http auth.
|
2010-01-16 15:39:56 +00:00
|
|
|
* @var string
|
|
|
|
*/
|
2009-05-06 08:49:12 +00:00
|
|
|
protected $user = '';
|
2013-08-05 09:06:56 +12:00
|
|
|
|
2010-01-16 15:39:56 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Password for http auth.
|
2010-01-16 15:39:56 +00:00
|
|
|
* @var string
|
|
|
|
*/
|
2009-05-06 08:49:12 +00:00
|
|
|
protected $pass = '';
|
2013-08-05 09:06:56 +12:00
|
|
|
|
2010-01-16 15:39:56 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Script path.
|
2010-01-16 15:39:56 +00:00
|
|
|
* @var string
|
|
|
|
*/
|
2009-05-06 08:49:12 +00:00
|
|
|
protected $path = '';
|
2013-08-05 09:06:56 +12:00
|
|
|
|
2010-01-17 21:53:11 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Optional slash argument value.
|
2010-01-17 21:53:11 +00:00
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $slashargument = '';
|
2013-08-05 09:06:56 +12:00
|
|
|
|
2009-05-22 03:26:07 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Anchor, may be also empty, null means none.
|
2010-01-16 15:39:56 +00:00
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $anchor = null;
|
2013-08-05 09:06:56 +12:00
|
|
|
|
2010-01-16 15:39:56 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Url parameters as associative array.
|
2009-08-04 02:05:32 +00:00
|
|
|
* @var array
|
2009-05-22 03:26:07 +00:00
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
protected $params = array();
|
2007-06-19 14:44:02 +00:00
|
|
|
|
2007-05-03 04:34:53 +00:00
|
|
|
/**
|
2010-01-16 15:39:56 +00:00
|
|
|
* Create new instance of moodle_url.
|
2007-06-19 14:44:02 +00:00
|
|
|
*
|
2010-01-16 15:39:56 +00:00
|
|
|
* @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
|
2010-11-08 13:33:08 +00:00
|
|
|
* 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.
|
2010-01-16 15:39:56 +00:00
|
|
|
* @param array $params these params override current params or add new
|
2013-07-12 14:02:19 +12:00
|
|
|
* @param string $anchor The anchor to use as part of the URL if there is one.
|
2013-08-05 09:06:56 +12:00
|
|
|
* @throws moodle_exception
|
2007-05-03 04:34:53 +00:00
|
|
|
*/
|
2013-07-12 14:02:19 +12:00
|
|
|
public function __construct($url, array $params = null, $anchor = null) {
|
2010-01-16 15:39:56 +00:00
|
|
|
global $CFG;
|
2009-12-16 21:31:47 +00:00
|
|
|
|
2010-01-16 15:39:56 +00:00
|
|
|
if ($url instanceof moodle_url) {
|
2009-05-06 08:50:32 +00:00
|
|
|
$this->scheme = $url->scheme;
|
|
|
|
$this->host = $url->host;
|
|
|
|
$this->port = $url->port;
|
|
|
|
$this->user = $url->user;
|
|
|
|
$this->pass = $url->pass;
|
2009-05-06 08:55:53 +00:00
|
|
|
$this->path = $url->path;
|
2010-01-17 21:53:11 +00:00
|
|
|
$this->slashargument = $url->slashargument;
|
2009-05-06 08:50:32 +00:00
|
|
|
$this->params = $url->params;
|
2010-01-16 15:39:56 +00:00
|
|
|
$this->anchor = $url->anchor;
|
2009-12-16 21:31:47 +00:00
|
|
|
|
2009-05-06 08:50:32 +00:00
|
|
|
} else {
|
2022-11-17 16:04:24 +01:00
|
|
|
$url = $url ?? '';
|
2013-08-05 09:06:56 +12:00
|
|
|
// Detect if anchor used.
|
2010-01-16 15:39:56 +00:00
|
|
|
$apos = strpos($url, '#');
|
|
|
|
if ($apos !== false) {
|
|
|
|
$anchor = substr($url, $apos);
|
|
|
|
$anchor = ltrim($anchor, '#');
|
|
|
|
$this->set_anchor($anchor);
|
|
|
|
$url = substr($url, 0, $apos);
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
2010-01-16 15:39:56 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Normalise shortened form of our url ex.: '/course/view.php'.
|
2010-01-16 15:39:56 +00:00
|
|
|
if (strpos($url, '/') === 0) {
|
|
|
|
$url = $CFG->wwwroot.$url;
|
2009-05-06 08:50:32 +00:00
|
|
|
}
|
2010-01-16 15:39:56 +00:00
|
|
|
|
|
|
|
if ($CFG->admin !== 'admin') {
|
|
|
|
if (strpos($url, "$CFG->wwwroot/admin/") === 0) {
|
|
|
|
$url = str_replace("$CFG->wwwroot/admin/", "$CFG->wwwroot/$CFG->admin/", $url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Parse the $url.
|
2010-01-16 15:39:56 +00:00
|
|
|
$parts = parse_url($url);
|
|
|
|
if ($parts === false) {
|
2009-05-06 08:50:32 +00:00
|
|
|
throw new moodle_exception('invalidurl');
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
2009-05-06 08:49:12 +00:00
|
|
|
if (isset($parts['query'])) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Note: the values may not be correctly decoded, url parameters should be always passed as array.
|
2007-05-29 06:14:09 +00:00
|
|
|
parse_str(str_replace('&', '&', $parts['query']), $this->params);
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
|
|
|
unset($parts['query']);
|
2009-05-06 08:49:12 +00:00
|
|
|
foreach ($parts as $key => $value) {
|
2007-05-03 04:34:53 +00:00
|
|
|
$this->$key = $value;
|
|
|
|
}
|
2010-01-17 21:53:11 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Detect slashargument value from path - we do not support directory names ending with .php.
|
2010-01-17 21:53:11 +00:00
|
|
|
$pos = strpos($this->path, '.php/');
|
|
|
|
if ($pos !== false) {
|
|
|
|
$this->slashargument = substr($this->path, $pos + 4);
|
|
|
|
$this->path = substr($this->path, 0, $pos + 4);
|
|
|
|
}
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
2009-12-16 21:31:47 +00:00
|
|
|
|
2009-05-06 08:50:32 +00:00
|
|
|
$this->params($params);
|
2013-07-12 14:02:19 +12:00
|
|
|
if ($anchor !== null) {
|
|
|
|
$this->anchor = (string)$anchor;
|
|
|
|
}
|
2007-06-19 14:44:02 +00:00
|
|
|
}
|
2009-05-06 08:49:12 +00:00
|
|
|
|
2007-05-03 04:34:53 +00:00
|
|
|
/**
|
2009-12-16 21:31:47 +00:00
|
|
|
* Add an array of params to the params for this url.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
|
|
|
* The added params override existing ones if they have the same name.
|
2007-05-03 04:34:53 +00:00
|
|
|
*
|
2009-07-27 10:33:00 +00:00
|
|
|
* @param array $params Defaults to null. If null then returns all params.
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return array Array of Params for url.
|
2013-08-05 09:06:56 +12:00
|
|
|
* @throws coding_exception
|
2007-05-03 04:34:53 +00:00
|
|
|
*/
|
2009-12-16 21:31:47 +00:00
|
|
|
public function params(array $params = null) {
|
|
|
|
$params = (array)$params;
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
foreach ($params as $key => $value) {
|
2009-12-16 21:31:47 +00:00
|
|
|
if (is_int($key)) {
|
2009-12-23 02:45:22 +00:00
|
|
|
throw new coding_exception('Url parameters can not have numeric keys!');
|
2009-12-16 21:31:47 +00:00
|
|
|
}
|
2011-01-18 12:39:51 +00:00
|
|
|
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!');
|
|
|
|
}
|
2009-12-16 21:31:47 +00:00
|
|
|
}
|
|
|
|
$this->params[$key] = (string)$value;
|
2008-07-24 15:22:31 +00:00
|
|
|
}
|
2009-12-16 21:31:47 +00:00
|
|
|
return $this->params;
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
2007-06-19 14:44:02 +00:00
|
|
|
|
2007-05-03 04:34:53 +00:00
|
|
|
/**
|
2009-08-04 02:05:32 +00:00
|
|
|
* Remove all params if no arguments passed.
|
|
|
|
* Remove selected params if arguments are passed.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
|
|
|
* Can be called as either remove_params('param1', 'param2')
|
2009-05-06 08:50:32 +00:00
|
|
|
* or remove_params(array('param1', 'param2')).
|
2007-05-03 04:34:53 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param string[]|string $params,... either an array of param names, or 1..n string params to remove as args.
|
2009-12-16 21:31:47 +00:00
|
|
|
* @return array url parameters
|
2007-05-03 04:34:53 +00:00
|
|
|
*/
|
2009-12-16 21:31:47 +00:00
|
|
|
public function remove_params($params = null) {
|
2009-05-06 08:50:32 +00:00
|
|
|
if (!is_array($params)) {
|
|
|
|
$params = func_get_args();
|
|
|
|
}
|
|
|
|
foreach ($params as $param) {
|
2009-12-16 21:31:47 +00:00
|
|
|
unset($this->params[$param]);
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
2009-12-16 21:31:47 +00:00
|
|
|
return $this->params;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Remove all url parameters.
|
|
|
|
*
|
|
|
|
* @todo remove the unused param.
|
|
|
|
* @param array $params Unused param
|
2009-12-16 21:31:47 +00:00
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function remove_all_params($params = null) {
|
|
|
|
$this->params = array();
|
2010-01-17 21:53:11 +00:00
|
|
|
$this->slashargument = '';
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-12-16 21:31:47 +00:00
|
|
|
* Add a param to the params for this url.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2009-12-16 21:31:47 +00:00
|
|
|
* The added param overrides existing one if they have the same name.
|
2007-05-03 04:34:53 +00:00
|
|
|
*
|
|
|
|
* @param string $paramname name
|
2009-12-16 21:31:47 +00:00
|
|
|
* @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
|
2007-05-03 04:34:53 +00:00
|
|
|
*/
|
2009-12-16 21:31:47 +00:00
|
|
|
public function param($paramname, $newvalue = '') {
|
|
|
|
if (func_num_args() > 1) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Set new value.
|
|
|
|
$this->params(array($paramname => $newvalue));
|
2009-12-16 21:31:47 +00:00
|
|
|
}
|
|
|
|
if (isset($this->params[$paramname])) {
|
2008-07-25 16:20:46 +00:00
|
|
|
return $this->params[$paramname];
|
ajaxlib/require_js: MDL-16693 $PAGE->requires->... deprecates require_js etc.
There is a new implementation of require_js in lib/deprecatedlib.php,
based on $PAGE->requires.
There were a few other recently introduced functions in lib/weblib.php,
namely print_js_call, print_delayed_js_call, print_js_config and
standard_js_config. These have been removed, since they were never in
a stable branch, and all the places that used them have been changed
to use the newer $PAGE->requires->... methods.
get_require_js_code is also gone, and the evil places that were calling
it, even though it is an internal function, have been fixed.
Also, I made some minor improvements to the code I committed yesterday
for MDL-16695.
All that remains is to update all the places in core code that are
still using require_js.
(This commit also fixes the problem where the admin tree would not
start with the right categories expanded.)
2009-06-12 12:13:07 +00:00
|
|
|
} else {
|
|
|
|
return null;
|
2008-07-24 15:22:31 +00:00
|
|
|
}
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
|
|
|
|
2009-12-16 21:31:47 +00:00
|
|
|
/**
|
|
|
|
* Merges parameters and validates them
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2009-12-16 21:31:47 +00:00
|
|
|
* @param array $overrideparams
|
|
|
|
* @return array merged parameters
|
2013-08-05 09:06:56 +12:00
|
|
|
* @throws coding_exception
|
2009-12-16 21:31:47 +00:00
|
|
|
*/
|
|
|
|
protected function merge_overrideparams(array $overrideparams = null) {
|
|
|
|
$overrideparams = (array)$overrideparams;
|
|
|
|
$params = $this->params;
|
2013-08-05 09:06:56 +12:00
|
|
|
foreach ($overrideparams as $key => $value) {
|
2009-12-16 21:31:47 +00:00
|
|
|
if (is_int($key)) {
|
2010-07-14 16:40:30 +00:00
|
|
|
throw new coding_exception('Overridden parameters can not have numeric keys!');
|
2009-12-16 21:31:47 +00:00
|
|
|
}
|
|
|
|
if (is_array($value)) {
|
2010-07-14 16:40:30 +00:00
|
|
|
throw new coding_exception('Overridden parameters values can not be arrays!');
|
2009-12-16 21:31:47 +00:00
|
|
|
}
|
|
|
|
if (is_object($value) and !method_exists($value, '__toString')) {
|
2010-07-14 16:40:30 +00:00
|
|
|
throw new coding_exception('Overridden parameters values can not be objects, unless __toString() is defined!');
|
2009-12-16 21:31:47 +00:00
|
|
|
}
|
|
|
|
$params[$key] = (string)$value;
|
|
|
|
}
|
|
|
|
return $params;
|
|
|
|
}
|
|
|
|
|
2009-05-06 08:49:12 +00:00
|
|
|
/**
|
|
|
|
* Get the params as as a query string.
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2010-01-17 10:54:13 +00:00
|
|
|
* This method should not be used outside of this method.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param bool $escaped Use & as params separator instead of plain &
|
2009-05-06 08:49:12 +00:00
|
|
|
* @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.
|
|
|
|
*/
|
2010-01-17 10:54:13 +00:00
|
|
|
public function get_query_string($escaped = true, array $overrideparams = null) {
|
2007-05-03 04:34:53 +00:00
|
|
|
$arr = array();
|
2011-01-18 12:39:51 +00:00
|
|
|
if ($overrideparams !== null) {
|
|
|
|
$params = $this->merge_overrideparams($overrideparams);
|
|
|
|
} else {
|
|
|
|
$params = $this->params;
|
|
|
|
}
|
2009-05-06 08:49:12 +00:00
|
|
|
foreach ($params as $key => $val) {
|
2012-02-22 20:12:08 +00:00
|
|
|
if (is_array($val)) {
|
|
|
|
foreach ($val as $index => $value) {
|
|
|
|
$arr[] = rawurlencode($key.'['.$index.']')."=".rawurlencode($value);
|
|
|
|
}
|
|
|
|
} else {
|
2013-04-19 09:49:44 +12:00
|
|
|
if (isset($val) && $val !== '') {
|
|
|
|
$arr[] = rawurlencode($key)."=".rawurlencode($val);
|
|
|
|
} else {
|
|
|
|
$arr[] = rawurlencode($key);
|
|
|
|
}
|
2012-02-22 20:12:08 +00:00
|
|
|
}
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
2009-07-05 14:31:58 +00:00
|
|
|
if ($escaped) {
|
|
|
|
return implode('&', $arr);
|
|
|
|
} else {
|
|
|
|
return implode('&', $arr);
|
|
|
|
}
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
2009-05-06 08:49:12 +00:00
|
|
|
|
2023-02-13 13:53:49 +00:00
|
|
|
/**
|
|
|
|
* Get the url params as an array of key => value pairs.
|
|
|
|
*
|
|
|
|
* This helps in handling cases where url params contain arrays.
|
|
|
|
*
|
|
|
|
* @return array params array for templates.
|
|
|
|
*/
|
|
|
|
public function export_params_for_template(): array {
|
|
|
|
$data = [];
|
|
|
|
foreach ($this->params as $key => $val) {
|
|
|
|
if (is_array($val)) {
|
|
|
|
foreach ($val as $index => $value) {
|
|
|
|
$data[] = ['name' => $key.'['.$index.']', 'value' => $value];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$data[] = ['name' => $key, 'value' => $val];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
2009-12-16 21:31:47 +00:00
|
|
|
/**
|
|
|
|
* Shortcut for printing of encoded URL.
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2009-12-16 21:31:47 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function __toString() {
|
2010-01-17 09:50:55 +00:00
|
|
|
return $this->out(true);
|
2009-12-16 21:31:47 +00:00
|
|
|
}
|
|
|
|
|
2007-05-03 04:34:53 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Output url.
|
2007-06-19 14:44:02 +00:00
|
|
|
*
|
2009-07-05 14:31:58 +00:00
|
|
|
* 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.
|
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param bool $escaped Use & as params separator instead of plain &
|
2010-01-17 09:50:55 +00:00
|
|
|
* @param array $overrideparams params to add to the output url, these override existing ones with the same name.
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return string Resulting URL
|
2007-05-03 04:34:53 +00:00
|
|
|
*/
|
2010-01-17 09:50:55 +00:00
|
|
|
public function out($escaped = true, array $overrideparams = null) {
|
2016-02-05 19:45:00 +11:00
|
|
|
|
|
|
|
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) {
|
2010-01-17 09:50:55 +00:00
|
|
|
if (!is_bool($escaped)) {
|
|
|
|
debugging('Escape parameter must be of type boolean, '.gettype($escaped).' given instead.');
|
|
|
|
}
|
|
|
|
|
2010-01-17 21:53:11 +00:00
|
|
|
$uri = $this->out_omit_querystring().$this->slashargument;
|
2009-12-29 17:26:29 +00:00
|
|
|
|
2010-01-17 10:54:13 +00:00
|
|
|
$querystring = $this->get_query_string($escaped, $overrideparams);
|
2010-01-17 21:53:11 +00:00
|
|
|
if ($querystring !== '') {
|
2010-01-17 09:37:30 +00:00
|
|
|
$uri .= '?' . $querystring;
|
|
|
|
}
|
2024-03-21 12:07:43 +08:00
|
|
|
|
|
|
|
$uri .= $this->get_encoded_anchor();
|
2010-01-16 15:39:56 +00:00
|
|
|
|
2007-06-19 14:44:02 +00:00
|
|
|
return $uri;
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
2009-05-06 08:49:12 +00:00
|
|
|
|
2024-03-21 12:07:43 +08:00
|
|
|
/**
|
|
|
|
* Encode the anchor according to RFC 3986.
|
|
|
|
*
|
|
|
|
* @return string The encoded anchor
|
|
|
|
*/
|
|
|
|
public function get_encoded_anchor(): string {
|
|
|
|
if (is_null($this->anchor)) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
// RFC 3986 allows the following characters in a fragment without them being encoded:
|
|
|
|
// pct-encoded: "%" HEXDIG HEXDIG
|
|
|
|
// unreserved: ALPHA / DIGIT / "-" / "." / "_" / "~" /
|
|
|
|
// sub-delims: "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" / ":" / "@"
|
|
|
|
// fragment: "/" / "?"
|
|
|
|
//
|
|
|
|
// All other characters should be encoded.
|
|
|
|
// These should not be encoded in the fragment unless they were already encoded.
|
|
|
|
|
|
|
|
// The following characters are allowed in the fragment without encoding.
|
|
|
|
// In addition to this list is pct-encoded, but we can't easily handle this with a regular expression.
|
|
|
|
$allowed = 'a-zA-Z0-9\\-._~!$&\'()*+,;=:@\/?';
|
|
|
|
$anchor = '#';
|
|
|
|
|
|
|
|
$remainder = $this->anchor;
|
|
|
|
do {
|
|
|
|
// Split the string on any %.
|
|
|
|
$parts = explode('%', $remainder, 2);
|
|
|
|
$anchorparts = array_shift($parts);
|
|
|
|
|
|
|
|
// The first part can go through our preg_replace_callback to quote any relevant characters.
|
|
|
|
$anchor .= preg_replace_callback(
|
|
|
|
'/[^' . $allowed . ']/',
|
|
|
|
fn ($matches) => rawurlencode($matches[0]),
|
|
|
|
$anchorparts,
|
|
|
|
);
|
|
|
|
|
|
|
|
// The second part _might_ be a valid pct-encoded character.
|
|
|
|
if (count($parts) === 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the second part is a valid pct-encoded character, append it to the anchor.
|
|
|
|
$remainder = array_shift($parts);
|
|
|
|
if (preg_match('/^[a-fA-F0-9]{2}/', $remainder, $matches)) {
|
|
|
|
$anchor .= "%{$matches[0]}";
|
|
|
|
$remainder = substr($remainder, 2);
|
|
|
|
} else {
|
|
|
|
// This was not a valid pct-encoded character. Encode the % and continue with the next part.
|
|
|
|
$anchor .= rawurlencode('%');
|
|
|
|
}
|
|
|
|
} while (strlen($remainder) > 0);
|
|
|
|
|
|
|
|
return $anchor;
|
|
|
|
}
|
|
|
|
|
2010-01-17 09:37:30 +00:00
|
|
|
/**
|
|
|
|
* Returns url without parameters, everything before '?'.
|
2011-03-24 13:30:46 +01:00
|
|
|
*
|
|
|
|
* @param bool $includeanchor if {@link self::anchor} is defined, should it be returned?
|
2010-01-17 09:37:30 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
2011-03-24 13:30:46 +01:00
|
|
|
public function out_omit_querystring($includeanchor = false) {
|
|
|
|
|
2010-01-17 09:37:30 +00:00
|
|
|
$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 : '';
|
2024-03-21 12:07:43 +08:00
|
|
|
if ($includeanchor) {
|
|
|
|
$uri .= $this->get_encoded_anchor();
|
2011-03-24 13:30:46 +01:00
|
|
|
}
|
|
|
|
|
2010-01-17 09:37:30 +00:00
|
|
|
return $uri;
|
2009-12-16 21:50:45 +00:00
|
|
|
}
|
|
|
|
|
2009-08-10 03:04:01 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Compares this moodle_url with another.
|
|
|
|
*
|
2009-08-10 03:04:01 +00:00
|
|
|
* See documentation of constants for an explanation of the comparison flags.
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2009-08-10 03:04:01 +00:00
|
|
|
* @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)
|
2013-08-05 09:06:56 +12:00
|
|
|
* @return bool
|
2009-08-10 03:04:01 +00:00
|
|
|
*/
|
|
|
|
public function compare(moodle_url $url, $matchtype = URL_MATCH_EXACT) {
|
2009-10-01 02:31:42 +00:00
|
|
|
|
2010-01-17 09:37:30 +00:00
|
|
|
$baseself = $this->out_omit_querystring();
|
|
|
|
$baseother = $url->out_omit_querystring();
|
2009-09-23 06:05:36 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Append index.php if there is no specific file.
|
|
|
|
if (substr($baseself, -1) == '/') {
|
2009-09-23 06:05:36 +00:00
|
|
|
$baseself .= 'index.php';
|
|
|
|
}
|
2013-08-05 09:06:56 +12:00
|
|
|
if (substr($baseother, -1) == '/') {
|
2009-09-23 06:05:36 +00:00
|
|
|
$baseother .= 'index.php';
|
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Compare the two base URLs.
|
2009-09-23 06:05:36 +00:00
|
|
|
if ($baseself != $baseother) {
|
2009-08-10 03:04:01 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-20 15:38:34 +13:00
|
|
|
if ($url->anchor !== $this->anchor) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-08-10 03:04:01 +00:00
|
|
|
return true;
|
|
|
|
}
|
2009-10-30 06:20:59 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the anchor for the URI (the bit after the hash)
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2010-01-16 15:39:56 +00:00
|
|
|
* @param string $anchor null means remove previous
|
2009-10-30 06:20:59 +00:00
|
|
|
*/
|
|
|
|
public function set_anchor($anchor) {
|
2010-01-16 15:39:56 +00:00
|
|
|
if (is_null($anchor)) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Remove.
|
2010-01-16 15:39:56 +00:00
|
|
|
$this->anchor = null;
|
|
|
|
} else {
|
2024-03-21 12:07:43 +08:00
|
|
|
$this->anchor = $anchor;
|
2009-10-30 06:20:59 +00:00
|
|
|
}
|
|
|
|
}
|
2015-10-12 10:40:50 +11:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.');
|
|
|
|
}
|
|
|
|
}
|
2010-01-17 21:53:11 +00:00
|
|
|
|
2010-01-18 12:39:44 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Sets the url slashargument value.
|
|
|
|
*
|
2010-01-18 12:39:44 +00:00
|
|
|
* @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
|
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
public function set_slashargument($path, $parameter = 'file', $supported = null) {
|
2010-01-18 12:39:44 +00:00
|
|
|
global $CFG;
|
|
|
|
if (is_null($supported)) {
|
2015-02-25 11:28:24 +08:00
|
|
|
$supported = !empty($CFG->slasharguments);
|
2010-01-18 12:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Static factory methods.
|
2010-01-17 21:53:11 +00:00
|
|
|
|
2023-10-25 14:10:13 +08:00
|
|
|
/**
|
|
|
|
* Create a new moodle_url instance from a UriInterface.
|
|
|
|
*
|
|
|
|
* @param UriInterface $uri
|
|
|
|
* @return self
|
|
|
|
*/
|
|
|
|
public static function from_uri(UriInterface $uri): self {
|
|
|
|
$url = new self(
|
|
|
|
url: $uri->getScheme() . '://' . $uri->getAuthority() . $uri->getPath(),
|
|
|
|
anchor: $uri->getFragment() ?: null,
|
|
|
|
);
|
|
|
|
|
|
|
|
$params = $uri->getQuery();
|
|
|
|
foreach (explode('&', $params) as $param) {
|
|
|
|
$url->param(...explode('=', $param, 2));
|
|
|
|
}
|
|
|
|
|
|
|
|
return $url;
|
|
|
|
}
|
|
|
|
|
2010-01-17 21:53:11 +00:00
|
|
|
/**
|
2010-01-18 08:50:46 +00:00
|
|
|
* General moodle file url.
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2010-01-18 08:50:46 +00:00
|
|
|
* @param string $urlbase the script serving the file
|
|
|
|
* @param string $path
|
2010-01-17 21:53:11 +00:00
|
|
|
* @param bool $forcedownload
|
|
|
|
* @return moodle_url
|
|
|
|
*/
|
2010-07-11 09:20:20 +00:00
|
|
|
public static function make_file_url($urlbase, $path, $forcedownload = false) {
|
2010-01-17 21:53:11 +00:00
|
|
|
$params = array();
|
|
|
|
if ($forcedownload) {
|
|
|
|
$params['forcedownload'] = 1;
|
|
|
|
}
|
2010-01-18 12:39:44 +00:00
|
|
|
$url = new moodle_url($urlbase, $params);
|
|
|
|
$url->set_slashargument($path);
|
|
|
|
return $url;
|
2010-01-17 21:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Factory method for creation of url pointing to plugin file.
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2010-01-17 21:53:11 +00:00
|
|
|
* 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!
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2010-01-17 21:53:11 +00:00
|
|
|
* @param int $contextid
|
2010-07-11 09:20:20 +00:00
|
|
|
* @param string $component
|
2010-01-17 21:53:11 +00:00
|
|
|
* @param string $area
|
2024-02-05 15:20:28 +00:00
|
|
|
* @param ?int $itemid
|
2010-01-17 21:53:11 +00:00
|
|
|
* @param string $pathname
|
|
|
|
* @param string $filename
|
|
|
|
* @param bool $forcedownload
|
2019-03-22 11:48:12 +01:00
|
|
|
* @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.
|
2018-06-03 21:15:35 +08:00
|
|
|
* 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.
|
2010-01-17 21:53:11 +00:00
|
|
|
* @return moodle_url
|
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
public static function make_pluginfile_url($contextid, $component, $area, $itemid, $pathname, $filename,
|
2018-06-03 21:15:35 +08:00
|
|
|
$forcedownload = false, $includetoken = false) {
|
|
|
|
global $CFG, $USER;
|
|
|
|
|
|
|
|
$path = [];
|
|
|
|
|
|
|
|
if ($includetoken) {
|
|
|
|
$urlbase = "$CFG->wwwroot/tokenpluginfile.php";
|
2019-03-22 11:48:12 +01:00
|
|
|
$userid = $includetoken === true ? $USER->id : $includetoken;
|
|
|
|
$token = get_user_key('core_files', $userid);
|
2018-06-03 21:15:35 +08:00
|
|
|
if ($CFG->slasharguments) {
|
|
|
|
$path[] = $token;
|
|
|
|
}
|
2010-07-11 09:20:20 +00:00
|
|
|
} else {
|
2018-06-03 21:15:35 +08:00
|
|
|
$urlbase = "$CFG->wwwroot/pluginfile.php";
|
|
|
|
}
|
|
|
|
$path[] = $contextid;
|
|
|
|
$path[] = $component;
|
|
|
|
$path[] = $area;
|
|
|
|
|
|
|
|
if ($itemid !== null) {
|
|
|
|
$path[] = $itemid;
|
2010-07-11 09:20:20 +00:00
|
|
|
}
|
2018-06-03 21:15:35 +08:00
|
|
|
|
|
|
|
$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;
|
2010-01-17 21:53:11 +00:00
|
|
|
}
|
|
|
|
|
2014-09-29 15:07:04 +02:00
|
|
|
/**
|
|
|
|
* 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;
|
2017-09-15 10:09:01 +08:00
|
|
|
$urlbase = "$CFG->wwwroot/webservice/pluginfile.php";
|
2014-09-29 15:07:04 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-17 21:53:11 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Factory method for creation of url pointing to draft file of current user.
|
|
|
|
*
|
2010-07-11 09:21:51 +00:00
|
|
|
* @param int $draftid draft item id
|
2010-01-17 21:53:11 +00:00
|
|
|
* @param string $pathname
|
|
|
|
* @param string $filename
|
|
|
|
* @param bool $forcedownload
|
|
|
|
* @return moodle_url
|
|
|
|
*/
|
2010-07-11 09:21:51 +00:00
|
|
|
public static function make_draftfile_url($draftid, $pathname, $filename, $forcedownload = false) {
|
2010-01-17 21:53:11 +00:00
|
|
|
global $CFG, $USER;
|
2017-09-15 10:09:01 +08:00
|
|
|
$urlbase = "$CFG->wwwroot/draftfile.php";
|
2012-07-25 16:25:55 +08:00
|
|
|
$context = context_user::instance($USER->id);
|
2010-01-17 21:53:11 +00:00
|
|
|
|
2010-07-11 09:21:51 +00:00
|
|
|
return self::make_file_url($urlbase, "/$context->id/user/draft/$draftid".$pathname.$filename, $forcedownload);
|
2010-01-17 21:53:11 +00:00
|
|
|
}
|
2010-01-17 22:12:31 +00:00
|
|
|
|
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Factory method for creating of links to legacy course files.
|
|
|
|
*
|
2010-01-17 22:12:31 +00:00
|
|
|
* @param int $courseid
|
|
|
|
* @param string $filepath
|
|
|
|
* @param bool $forcedownload
|
|
|
|
* @return moodle_url
|
|
|
|
*/
|
2010-07-11 09:20:20 +00:00
|
|
|
public static function make_legacyfile_url($courseid, $filepath, $forcedownload = false) {
|
2010-01-17 22:12:31 +00:00
|
|
|
global $CFG;
|
|
|
|
|
2010-01-18 08:50:46 +00:00
|
|
|
$urlbase = "$CFG->wwwroot/file.php";
|
|
|
|
return self::make_file_url($urlbase, '/'.$courseid.'/'.$filepath, $forcedownload);
|
2010-01-17 22:12:31 +00:00
|
|
|
}
|
2011-08-24 15:20:46 +01:00
|
|
|
|
|
|
|
/**
|
2022-10-29 18:49:05 +02:00
|
|
|
* Checks if URL is relative to $CFG->wwwroot.
|
|
|
|
*
|
|
|
|
* @return bool True if URL is relative to $CFG->wwwroot; otherwise, false.
|
|
|
|
*/
|
2024-02-28 18:38:20 +01:00
|
|
|
public function is_local_url(): bool {
|
2022-10-29 18:49:05 +02:00
|
|
|
global $CFG;
|
|
|
|
|
|
|
|
$url = $this->out();
|
|
|
|
// Does URL start with wwwroot? Otherwise, URL isn't relative to wwwroot.
|
|
|
|
return ( ($url === $CFG->wwwroot) || (strpos($url, $CFG->wwwroot.'/') === 0) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns URL as relative path from $CFG->wwwroot
|
2011-08-24 15:20:46 +01:00
|
|
|
*
|
|
|
|
* 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;
|
|
|
|
|
2022-10-29 18:49:05 +02:00
|
|
|
// URL should be relative to wwwroot. If not then throw exception.
|
|
|
|
if ($this->is_local_url()) {
|
|
|
|
$url = $this->out($escaped, $overrideparams);
|
2012-11-19 11:52:15 +08:00
|
|
|
$localurl = substr($url, strlen($CFG->wwwroot));
|
|
|
|
return !empty($localurl) ? $localurl : '';
|
|
|
|
} else {
|
2011-08-24 15:20:46 +01:00
|
|
|
throw new coding_exception('out_as_local_url called on a non-local URL');
|
|
|
|
}
|
|
|
|
}
|
2012-04-19 16:59:56 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2012-05-21 12:55:32 +01:00
|
|
|
* 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.)
|
2012-04-19 16:59:56 +01:00
|
|
|
*
|
|
|
|
* @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 : '');
|
|
|
|
}
|
2012-05-21 12:55:32 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
}
|
2013-09-16 16:14:29 +12:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
2007-05-03 04:34:53 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 02:48:41 +00:00
|
|
|
/**
|
|
|
|
* 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
|
2005-01-26 15:57:00 +00:00
|
|
|
*
|
2006-12-04 09:13:51 +00:00
|
|
|
* Checks that submitted POST data exists and returns it as object.
|
2004-09-23 04:36:43 +00:00
|
|
|
*
|
2006-12-04 09:13:51 +00:00
|
|
|
* @return mixed false or object
|
2004-09-23 02:48:41 +00:00
|
|
|
*/
|
2008-06-09 16:53:30 +00:00
|
|
|
function data_submitted() {
|
2004-09-23 04:36:43 +00:00
|
|
|
|
2003-01-05 06:45:20 +00:00
|
|
|
if (empty($_POST)) {
|
2003-01-02 14:49:23 +00:00
|
|
|
return false;
|
|
|
|
} else {
|
2011-07-15 15:00:49 +02:00
|
|
|
return (object)fix_utf8($_POST);
|
2003-01-02 14:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-23 02:48:41 +00:00
|
|
|
/**
|
2004-09-23 04:36:43 +00:00
|
|
|
* Given some normal text this function will break up any
|
|
|
|
* long words to a given size by inserting the given character
|
|
|
|
*
|
2006-01-04 08:23:42 +00:00
|
|
|
* It's multibyte savvy and doesn't change anything inside html tags.
|
|
|
|
*
|
2004-09-23 02:48:41 +00:00
|
|
|
* @param string $string the string to be modified
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param int $maxsize maximum length of the string to be returned
|
2004-09-23 02:48:41 +00:00
|
|
|
* @param string $cutchar the string used to represent word breaks
|
|
|
|
* @return string
|
|
|
|
*/
|
2004-03-10 02:19:17 +00:00
|
|
|
function break_up_long_words($string, $maxsize=20, $cutchar=' ') {
|
2005-04-03 12:15:45 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// First of all, save all the tags inside the text to skip them.
|
2006-01-04 08:23:42 +00:00
|
|
|
$tags = array();
|
2013-08-05 09:06:56 +12:00
|
|
|
filter_save_tags($string, $tags);
|
2004-07-07 17:45:42 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Process the string adding the cut when necessary.
|
2004-03-10 02:19:17 +00:00
|
|
|
$output = '';
|
2013-08-06 20:58:28 +02:00
|
|
|
$length = core_text::strlen($string);
|
2004-03-10 02:19:17 +00:00
|
|
|
$wordlength = 0;
|
|
|
|
|
|
|
|
for ($i=0; $i<$length; $i++) {
|
2013-08-06 20:58:28 +02:00
|
|
|
$char = core_text::substr($string, $i, 1);
|
2006-01-04 08:23:42 +00:00
|
|
|
if ($char == ' ' or $char == "\t" or $char == "\n" or $char == "\r" or $char == "<" or $char == ">") {
|
2004-03-10 02:19:17 +00:00
|
|
|
$wordlength = 0;
|
|
|
|
} else {
|
|
|
|
$wordlength++;
|
|
|
|
if ($wordlength > $maxsize) {
|
|
|
|
$output .= $cutchar;
|
|
|
|
$wordlength = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$output .= $char;
|
|
|
|
}
|
2006-01-04 08:23:42 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Finally load the tags back again.
|
2006-01-04 08:23:42 +00:00
|
|
|
if (!empty($tags)) {
|
|
|
|
$output = str_replace(array_keys($tags), $tags, $output);
|
|
|
|
}
|
|
|
|
|
2004-03-10 02:19:17 +00:00
|
|
|
return $output;
|
|
|
|
}
|
|
|
|
|
2009-09-03 06:59:25 +00:00
|
|
|
/**
|
2008-12-10 08:57:50 +00:00
|
|
|
* Try and close the current window using JavaScript, either immediately, or after a delay.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
|
|
|
* Echo's out the resulting XHTML & javascript
|
|
|
|
*
|
2008-12-10 08:57:50 +00:00
|
|
|
* @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.
|
2005-03-22 17:31:04 +00:00
|
|
|
*/
|
2008-12-10 08:57:50 +00:00
|
|
|
function close_window($delay = 0, $reloadopener = false) {
|
2009-12-23 18:05:58 +00:00
|
|
|
global $PAGE, $OUTPUT;
|
2005-03-22 17:31:04 +00:00
|
|
|
|
2009-05-06 08:29:22 +00:00
|
|
|
if (!$PAGE->headerprinted) {
|
2009-09-03 06:59:25 +00:00
|
|
|
$PAGE->set_title(get_string('closewindow'));
|
|
|
|
echo $OUTPUT->header();
|
2008-12-10 08:57:50 +00:00
|
|
|
} else {
|
2009-12-23 18:05:58 +00:00
|
|
|
$OUTPUT->container_end_all(false);
|
2008-12-10 08:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($reloadopener) {
|
2011-02-09 18:21:26 +00:00
|
|
|
// Trigger the reload immediately, even if the reload is after a delay.
|
|
|
|
$PAGE->requires->js_function_call('window.opener.location.reload', array(true));
|
2008-12-10 08:57:50 +00:00
|
|
|
}
|
2011-02-09 18:21:26 +00:00
|
|
|
$OUTPUT->notification(get_string('windowclosing'), 'notifysuccess');
|
ajaxlib/require_js: MDL-16693 $PAGE->requires->... deprecates require_js etc.
There is a new implementation of require_js in lib/deprecatedlib.php,
based on $PAGE->requires.
There were a few other recently introduced functions in lib/weblib.php,
namely print_js_call, print_delayed_js_call, print_js_config and
standard_js_config. These have been removed, since they were never in
a stable branch, and all the places that used them have been changed
to use the newer $PAGE->requires->... methods.
get_require_js_code is also gone, and the evil places that were calling
it, even though it is an internal function, have been fixed.
Also, I made some minor improvements to the code I committed yesterday
for MDL-16695.
All that remains is to update all the places in core code that are
still using require_js.
(This commit also fixes the problem where the admin tree would not
start with the right categories expanded.)
2009-06-12 12:13:07 +00:00
|
|
|
|
2011-02-09 18:21:26 +00:00
|
|
|
$PAGE->requires->js_function_call('close_window', array(new stdClass()), false, $delay);
|
2008-12-10 08:57:50 +00:00
|
|
|
|
2009-08-06 14:21:34 +00:00
|
|
|
echo $OUTPUT->footer();
|
2008-12-10 08:57:50 +00:00
|
|
|
exit;
|
|
|
|
}
|
2005-03-22 17:31:04 +00:00
|
|
|
|
2009-08-05 08:49:56 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* 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.
|
2009-08-05 08:49:56 +00:00
|
|
|
*
|
|
|
|
* @param string $text The text to be displayed for the link
|
|
|
|
* @return string The link to user documentation for this current page
|
|
|
|
*/
|
2010-01-02 13:17:54 +00:00
|
|
|
function page_doc_link($text='') {
|
2013-06-07 10:38:39 +12:00
|
|
|
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.
|
|
|
|
*
|
2014-05-19 17:03:04 +01:00
|
|
|
* @since Moodle 2.5.1 2.6
|
2013-06-07 10:38:39 +12:00
|
|
|
* @param moodle_page $page
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function page_get_doc_link_path(moodle_page $page) {
|
|
|
|
global $CFG;
|
2009-08-05 08:49:56 +00:00
|
|
|
|
|
|
|
if (empty($CFG->docroot) || during_initial_install()) {
|
|
|
|
return '';
|
|
|
|
}
|
2013-06-07 10:38:39 +12:00
|
|
|
if (!has_capability('moodle/site:doclinks', $page->context)) {
|
2009-08-05 08:49:56 +00:00
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
2013-06-07 10:38:39 +12:00
|
|
|
$path = $page->docspath;
|
2009-08-05 08:49:56 +00:00
|
|
|
if (!$path) {
|
|
|
|
return '';
|
|
|
|
}
|
2013-06-07 10:38:39 +12:00
|
|
|
return $path;
|
2009-08-05 08:49:56 +00:00
|
|
|
}
|
|
|
|
|
2006-01-11 02:22:16 +00:00
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
|
|
|
* Validates an email to make sure it makes sense.
|
|
|
|
*
|
|
|
|
* @param string $address The email address to validate.
|
|
|
|
* @return boolean
|
|
|
|
*/
|
2004-09-25 05:29:21 +00:00
|
|
|
function validate_email($address) {
|
2019-02-18 11:30:32 +10:00
|
|
|
global $CFG;
|
2022-12-03 20:56:16 +08:00
|
|
|
|
2022-12-07 21:40:01 +08:00
|
|
|
if ($address === null || $address === false || $address === '') {
|
2022-12-03 20:56:16 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
require_once("{$CFG->libdir}/phpmailer/moodle_phpmailer.php");
|
2004-09-23 04:36:43 +00:00
|
|
|
|
2022-11-17 16:04:24 +01:00
|
|
|
return moodle_phpmailer::validateAddress($address ?? '') && !preg_match('/[<>]/', $address);
|
2001-11-22 06:23:56 +00:00
|
|
|
}
|
|
|
|
|
2004-11-30 19:44:08 +00:00
|
|
|
/**
|
|
|
|
* Extracts file argument either from file parameter or PATH_INFO
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2009-01-05 21:37:20 +00:00
|
|
|
* Note: $scriptname parameter is not needed anymore
|
2004-11-30 19:44:08 +00:00
|
|
|
*
|
|
|
|
* @return string file path (only safe characters)
|
|
|
|
*/
|
2009-01-05 21:37:20 +00:00
|
|
|
function get_file_argument() {
|
|
|
|
global $SCRIPT;
|
2004-11-30 19:44:08 +00:00
|
|
|
|
2017-01-08 21:29:47 +01:00
|
|
|
$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);
|
|
|
|
}
|
2004-11-30 19:44:08 +00:00
|
|
|
|
2010-10-24 08:21:40 +00:00
|
|
|
if ($relativepath !== false and $relativepath !== '') {
|
|
|
|
return $relativepath;
|
|
|
|
}
|
|
|
|
$relativepath = false;
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Then try extract file from the slasharguments.
|
2010-10-24 08:21:40 +00:00
|
|
|
if (stripos($_SERVER['SERVER_SOFTWARE'], 'iis') !== false) {
|
2014-10-04 14:14:44 +02:00
|
|
|
// NOTE: IIS tends to convert all file paths to single byte DOS encoding,
|
2010-10-24 08:21:40 +00:00
|
|
|
// we can not use other methods because they break unicode chars,
|
2014-10-04 14:14:44 +02:00
|
|
|
// the only ways are to use URL rewriting
|
|
|
|
// OR
|
|
|
|
// to properly set the 'FastCGIUtf8ServerVariables' registry key.
|
2010-10-24 08:21:40 +00:00
|
|
|
if (isset($_SERVER['PATH_INFO']) and $_SERVER['PATH_INFO'] !== '') {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Check that PATH_INFO works == must not contain the script name.
|
2010-10-24 08:21:40 +00:00
|
|
|
if (strpos($_SERVER['PATH_INFO'], $SCRIPT) === false) {
|
|
|
|
$relativepath = clean_param(urldecode($_SERVER['PATH_INFO']), PARAM_PATH);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2013-08-05 09:06:56 +12:00
|
|
|
// All other apache-like servers depend on PATH_INFO.
|
2010-10-24 08:21:40 +00:00
|
|
|
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);
|
2004-11-30 19:44:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $relativepath;
|
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
2004-09-25 05:29:21 +00:00
|
|
|
* Just returns an array of text formats suitable for a popup menu
|
2004-09-23 04:36:43 +00:00
|
|
|
*
|
2004-09-25 05:29:21 +00:00
|
|
|
* @return array
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2002-10-10 07:26:10 +00:00
|
|
|
function format_text_menu() {
|
2004-09-22 14:39:15 +00:00
|
|
|
return array (FORMAT_MOODLE => get_string('formattext'),
|
2013-08-05 09:06:56 +12:00
|
|
|
FORMAT_HTML => get_string('formathtml'),
|
|
|
|
FORMAT_PLAIN => get_string('formatplain'),
|
|
|
|
FORMAT_MARKDOWN => get_string('formatmarkdown'));
|
2002-10-10 07:26:10 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Given text in a variety of format codings, this function returns the text as safe HTML.
|
2004-09-23 04:36:43 +00:00
|
|
|
*
|
2008-01-13 08:30:39 +00:00
|
|
|
* This function should mainly be used for long strings like posts,
|
2013-08-05 09:06:56 +12:00
|
|
|
* answers, glossary items etc. For short strings {@link format_string()}.
|
2007-12-15 18:42:49 +00:00
|
|
|
*
|
2010-11-05 02:53:47 +00:00
|
|
|
* <pre>
|
|
|
|
* Options:
|
|
|
|
* trusted : If true the string won't be cleaned. Default false required noclean=true.
|
2017-12-01 00:22:59 +01:00
|
|
|
* noclean : If true the string won't be cleaned, unless $CFG->forceclean is set. Default false required trusted=true.
|
2010-11-05 02:53:47 +00:00
|
|
|
* 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.
|
2011-02-28 11:19:58 +00:00
|
|
|
* allowid : If true then id attributes will not be removed, even when
|
|
|
|
* using htmlpurifier. Default false.
|
2016-05-27 10:25:40 +08:00
|
|
|
* blanktarget : If true all <a> tags will have target="_blank" added unless target is explicitly specified.
|
2010-11-05 02:53:47 +00:00
|
|
|
* </pre>
|
|
|
|
*
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param string $text The text to be formatted. This is raw text originally from user input.
|
2005-01-26 15:57:00 +00:00
|
|
|
* @param int $format Identifier of the text format to be used
|
2010-07-30 20:51:01 +00:00
|
|
|
* [FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_MARKDOWN]
|
2023-02-28 13:13:42 +00:00
|
|
|
* @param stdClass|array $options text formatting options
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param int $courseiddonotuse deprecated course id, use context option instead
|
2004-09-25 05:29:21 +00:00
|
|
|
* @return string
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
function format_text($text, $format = FORMAT_MOODLE, $options = null, $courseiddonotuse = null) {
|
2023-11-10 14:56:31 +08:00
|
|
|
global $CFG;
|
2009-01-31 20:07:32 +00:00
|
|
|
|
2023-11-10 14:56:31 +08:00
|
|
|
// Manually include the formatting class for now until after the release after 4.5 LTS.
|
|
|
|
require_once("{$CFG->libdir}/classes/formatting.php");
|
|
|
|
|
2023-11-13 09:01:24 +08:00
|
|
|
if ($format === FORMAT_WIKI) {
|
|
|
|
// This format was deprecated in Moodle 1.5.
|
|
|
|
throw new \coding_exception(
|
|
|
|
'Wiki-like formatting is not supported.'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($options instanceof \core\context) {
|
|
|
|
// A common mistake has been to call this function with a context object.
|
|
|
|
// This has never been expected, or nor supported.
|
|
|
|
debugging(
|
|
|
|
'The options argument should not be a context object directly. ' .
|
|
|
|
' Please pass an array with a context key instead.',
|
|
|
|
DEBUG_DEVELOPER,
|
|
|
|
);
|
MDL-80072 core: Promote all formatting options to parameters
Now that PHP has support for named parameters, and we can use them in
Moodle, we should ditch `$options` arrays and use first-class,
documented, parameters.
Whilst this may seem scary, dumb, overwhelming, please note that you do
not need to supply all args, for example, to change the last parameter
of `format_text` you no longer need to do this:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
false,
null,
true,
true,
true,
false,
false,
true,
);
Instead you can do:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
allowid: true,
);
Or better still:
return \core\container::get(\core\formatting::class)->format_text(
text: $text,
format: FORMAT_MOODLE,
context: $context,
allowid: true,
);
This means that we can get defaults in the function signature, improves
our typing, and allows for deprecation and changes to options. It also
sets us up for success in the future.
2023-12-06 23:25:15 +08:00
|
|
|
$params['context'] = $options;
|
|
|
|
$options = [];
|
2023-11-13 09:01:24 +08:00
|
|
|
}
|
|
|
|
|
2023-11-10 14:56:31 +08:00
|
|
|
if ($options) {
|
|
|
|
$options = (array) $options;
|
2006-10-24 22:19:41 +00:00
|
|
|
}
|
2009-07-24 02:44:44 +00:00
|
|
|
|
2023-11-10 14:56:31 +08:00
|
|
|
if (empty($CFG->version) || $CFG->version < 2013051400 || during_initial_install()) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Do not filter anything during installation or before upgrade completes.
|
MDL-80072 core: Promote all formatting options to parameters
Now that PHP has support for named parameters, and we can use them in
Moodle, we should ditch `$options` arrays and use first-class,
documented, parameters.
Whilst this may seem scary, dumb, overwhelming, please note that you do
not need to supply all args, for example, to change the last parameter
of `format_text` you no longer need to do this:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
false,
null,
true,
true,
true,
false,
false,
true,
);
Instead you can do:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
allowid: true,
);
Or better still:
return \core\container::get(\core\formatting::class)->format_text(
text: $text,
format: FORMAT_MOODLE,
context: $context,
allowid: true,
);
This means that we can get defaults in the function signature, improves
our typing, and allows for deprecation and changes to options. It also
sets us up for success in the future.
2023-12-06 23:25:15 +08:00
|
|
|
$params['context'] = null;
|
2023-11-10 14:56:31 +08:00
|
|
|
} else if ($options && isset($options['context'])) { // First by explicit passed context option.
|
MDL-80072 core: Promote all formatting options to parameters
Now that PHP has support for named parameters, and we can use them in
Moodle, we should ditch `$options` arrays and use first-class,
documented, parameters.
Whilst this may seem scary, dumb, overwhelming, please note that you do
not need to supply all args, for example, to change the last parameter
of `format_text` you no longer need to do this:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
false,
null,
true,
true,
true,
false,
false,
true,
);
Instead you can do:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
allowid: true,
);
Or better still:
return \core\container::get(\core\formatting::class)->format_text(
text: $text,
format: FORMAT_MOODLE,
context: $context,
allowid: true,
);
This means that we can get defaults in the function signature, improves
our typing, and allows for deprecation and changes to options. It also
sets us up for success in the future.
2023-12-06 23:25:15 +08:00
|
|
|
if (is_numeric($options['context'])) {
|
|
|
|
// A contextid was passed.
|
|
|
|
$params['context'] = \core\context::instance_by_id($options['context']);
|
|
|
|
} else if ($options['context'] instanceof \core\context) {
|
|
|
|
$params['context'] = $options['context'];
|
|
|
|
} else {
|
|
|
|
debugging(
|
|
|
|
'Unknown context passed to format_text(). Content will not be filtered.',
|
|
|
|
DEBUG_DEVELOPER,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unset the context from $options to prevent it overriding the configured value.
|
|
|
|
unset($options['context']);
|
2013-08-05 09:06:56 +12:00
|
|
|
} else if ($courseiddonotuse) {
|
|
|
|
// Legacy courseid.
|
MDL-80072 core: Promote all formatting options to parameters
Now that PHP has support for named parameters, and we can use them in
Moodle, we should ditch `$options` arrays and use first-class,
documented, parameters.
Whilst this may seem scary, dumb, overwhelming, please note that you do
not need to supply all args, for example, to change the last parameter
of `format_text` you no longer need to do this:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
false,
null,
true,
true,
true,
false,
false,
true,
);
Instead you can do:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
allowid: true,
);
Or better still:
return \core\container::get(\core\formatting::class)->format_text(
text: $text,
format: FORMAT_MOODLE,
context: $context,
allowid: true,
);
This means that we can get defaults in the function signature, improves
our typing, and allows for deprecation and changes to options. It also
sets us up for success in the future.
2023-12-06 23:25:15 +08:00
|
|
|
$params['context'] = \core\context\course::instance($courseiddonotuse);
|
2023-11-10 14:56:31 +08:00
|
|
|
debugging(
|
|
|
|
"Passing a courseid to format_text() is deprecated, please pass a context instead.",
|
|
|
|
DEBUG_DEVELOPER,
|
2015-06-05 15:58:18 +01:00
|
|
|
);
|
2010-11-05 02:53:47 +00:00
|
|
|
}
|
|
|
|
|
MDL-80072 core: Promote all formatting options to parameters
Now that PHP has support for named parameters, and we can use them in
Moodle, we should ditch `$options` arrays and use first-class,
documented, parameters.
Whilst this may seem scary, dumb, overwhelming, please note that you do
not need to supply all args, for example, to change the last parameter
of `format_text` you no longer need to do this:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
false,
null,
true,
true,
true,
false,
false,
true,
);
Instead you can do:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
allowid: true,
);
Or better still:
return \core\container::get(\core\formatting::class)->format_text(
text: $text,
format: FORMAT_MOODLE,
context: $context,
allowid: true,
);
This means that we can get defaults in the function signature, improves
our typing, and allows for deprecation and changes to options. It also
sets us up for success in the future.
2023-12-06 23:25:15 +08:00
|
|
|
$params['text'] = $text;
|
2023-11-13 09:01:24 +08:00
|
|
|
|
|
|
|
if ($options) {
|
2023-12-06 23:46:14 +08:00
|
|
|
// The smiley option was deprecated in Moodle 2.0.
|
|
|
|
if (array_key_exists('smiley', $options)) {
|
|
|
|
unset($options['smiley']);
|
|
|
|
debugging(
|
|
|
|
'The smiley option is deprecated and no longer used.',
|
|
|
|
DEBUG_DEVELOPER,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-12-07 15:34:51 +08:00
|
|
|
// The nocache option was deprecated in Moodle 2.3 in MDL-34347.
|
|
|
|
if (array_key_exists('nocache', $options)) {
|
|
|
|
unset($options['nocache']);
|
|
|
|
debugging(
|
|
|
|
'The nocache option is deprecated and no longer used.',
|
|
|
|
DEBUG_DEVELOPER,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
MDL-80072 core: Promote all formatting options to parameters
Now that PHP has support for named parameters, and we can use them in
Moodle, we should ditch `$options` arrays and use first-class,
documented, parameters.
Whilst this may seem scary, dumb, overwhelming, please note that you do
not need to supply all args, for example, to change the last parameter
of `format_text` you no longer need to do this:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
false,
null,
true,
true,
true,
false,
false,
true,
);
Instead you can do:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
allowid: true,
);
Or better still:
return \core\container::get(\core\formatting::class)->format_text(
text: $text,
format: FORMAT_MOODLE,
context: $context,
allowid: true,
);
This means that we can get defaults in the function signature, improves
our typing, and allows for deprecation and changes to options. It also
sets us up for success in the future.
2023-12-06 23:25:15 +08:00
|
|
|
$validoptions = [
|
|
|
|
'text',
|
|
|
|
'format',
|
|
|
|
'context',
|
|
|
|
'trusted',
|
|
|
|
'clean',
|
|
|
|
'filter',
|
|
|
|
'para',
|
|
|
|
'newlines',
|
|
|
|
'overflowdiv',
|
|
|
|
'blanktarget',
|
|
|
|
'allowid',
|
|
|
|
'noclean',
|
|
|
|
];
|
|
|
|
|
|
|
|
$invalidoptions = array_diff(array_keys($options), $validoptions);
|
|
|
|
if ($invalidoptions) {
|
|
|
|
debugging(sprintf(
|
|
|
|
'The following options are not valid: %s',
|
|
|
|
implode(', ', $invalidoptions),
|
|
|
|
), DEBUG_DEVELOPER);
|
|
|
|
foreach ($invalidoptions as $option) {
|
|
|
|
unset($options[$option]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($options as $option => $value) {
|
|
|
|
$params[$option] = $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The noclean option has been renamed to clean.
|
|
|
|
if (array_key_exists('noclean', $params)) {
|
|
|
|
$params['clean'] = !$params['noclean'];
|
|
|
|
unset($params['noclean']);
|
|
|
|
}
|
2023-11-13 09:01:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($format !== null) {
|
|
|
|
$params['format'] = $format;
|
|
|
|
}
|
|
|
|
|
|
|
|
return \core\di::get(\core\formatting::class)->format_text(...$params);
|
2002-10-10 07:26:10 +00:00
|
|
|
}
|
|
|
|
|
2007-12-25 10:03:59 +00:00
|
|
|
/**
|
2013-12-31 15:33:59 +08:00
|
|
|
* Resets some data related to filters, called during upgrade or when general filter settings change.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2012-09-09 11:55:31 +02:00
|
|
|
* @param bool $phpunitreset true means called from our PHPUnit integration test reset
|
2007-12-25 10:03:59 +00:00
|
|
|
* @return void
|
|
|
|
*/
|
2012-09-09 11:55:31 +02:00
|
|
|
function reset_text_filters_cache($phpunitreset = false) {
|
2008-06-02 21:52:27 +00:00
|
|
|
global $CFG, $DB;
|
2007-12-25 10:03:59 +00:00
|
|
|
|
2013-10-23 20:20:56 +02:00
|
|
|
if ($phpunitreset) {
|
|
|
|
// HTMLPurifier does not change, DB is already reset to defaults,
|
2013-12-31 15:33:59 +08:00
|
|
|
// nothing to do here, the dataroot was cleared too.
|
2013-10-23 20:20:56 +02:00
|
|
|
return;
|
2012-09-09 11:55:31 +02:00
|
|
|
}
|
|
|
|
|
2013-12-31 15:33:59 +08:00
|
|
|
// The purge_all_caches() deals with cachedir and localcachedir purging,
|
|
|
|
// the individual filter caches are invalidated as necessary elsewhere.
|
2013-10-23 20:20:56 +02:00
|
|
|
|
|
|
|
// 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);
|
2007-12-25 10:03:59 +00:00
|
|
|
}
|
2007-02-23 20:10:11 +00:00
|
|
|
|
2009-08-04 02:05:32 +00:00
|
|
|
/**
|
2009-05-22 03:26:07 +00:00
|
|
|
* Given a simple string, this function returns the string
|
|
|
|
* processed by enabled string filters if $CFG->filterall is enabled
|
2007-12-15 18:42:49 +00:00
|
|
|
*
|
2009-05-22 03:26:07 +00:00
|
|
|
* This function should be used to print short strings (non html) that
|
|
|
|
* need filter processing e.g. activity titles, post subjects,
|
|
|
|
* glossary concepts.
|
2005-03-25 16:24:43 +00:00
|
|
|
*
|
2009-05-22 03:26:07 +00:00
|
|
|
* @staticvar bool $strcache
|
2012-01-10 14:32:41 +00:00
|
|
|
* @param string $string The string to be filtered. Should be plain text, expect
|
|
|
|
* possibly for multilang tags.
|
2024-02-05 15:20:28 +00:00
|
|
|
* @param ?bool $striplinks To strip any link in the result text. Moodle 1.8 default changed from false to true! MDL-8713
|
2010-07-30 20:51:01 +00:00
|
|
|
* @param array $options options array/object or courseid
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return string
|
2005-03-25 16:24:43 +00:00
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
function format_string($string, $striplinks = true, $options = null) {
|
2023-11-10 12:22:10 +08:00
|
|
|
global $CFG;
|
2007-03-04 22:52:33 +00:00
|
|
|
|
2023-11-10 12:22:10 +08:00
|
|
|
// Manually include the formatting class for now until after the release after 4.5 LTS.
|
|
|
|
require_once("{$CFG->libdir}/classes/formatting.php");
|
2022-11-26 14:02:32 +01:00
|
|
|
|
2023-11-10 12:22:10 +08:00
|
|
|
$params = [
|
|
|
|
'string' => $string,
|
|
|
|
'striplinks' => (bool) $striplinks,
|
|
|
|
];
|
2007-06-19 14:44:02 +00:00
|
|
|
|
2023-11-11 16:36:46 +08:00
|
|
|
// This method only expects either:
|
|
|
|
// - an array of options;
|
|
|
|
// - a stdClass of options to be cast to an array; or
|
|
|
|
// - an integer courseid.
|
2023-11-10 12:22:10 +08:00
|
|
|
if ($options instanceof \core\context) {
|
2023-11-11 16:36:46 +08:00
|
|
|
// A common mistake has been to call this function with a context object.
|
|
|
|
// This has never been expected, or nor supported.
|
|
|
|
debugging(
|
|
|
|
'The options argument should not be a context object directly. ' .
|
|
|
|
' Please pass an array with a context key instead.',
|
|
|
|
DEBUG_DEVELOPER,
|
|
|
|
);
|
MDL-80072 core: Promote all formatting options to parameters
Now that PHP has support for named parameters, and we can use them in
Moodle, we should ditch `$options` arrays and use first-class,
documented, parameters.
Whilst this may seem scary, dumb, overwhelming, please note that you do
not need to supply all args, for example, to change the last parameter
of `format_text` you no longer need to do this:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
false,
null,
true,
true,
true,
false,
false,
true,
);
Instead you can do:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
allowid: true,
);
Or better still:
return \core\container::get(\core\formatting::class)->format_text(
text: $text,
format: FORMAT_MOODLE,
context: $context,
allowid: true,
);
This means that we can get defaults in the function signature, improves
our typing, and allows for deprecation and changes to options. It also
sets us up for success in the future.
2023-12-06 23:25:15 +08:00
|
|
|
$params['context'] = $options;
|
|
|
|
$options = [];
|
|
|
|
} else if (is_numeric($options)) {
|
|
|
|
// Legacy courseid usage.
|
|
|
|
$params['context'] = \core\context\course::instance($options);
|
|
|
|
$options = [];
|
|
|
|
} else if (is_array($options) || is_a($options, \stdClass::class)) {
|
|
|
|
$options = (array) $options;
|
|
|
|
if (isset($options['context'])) {
|
|
|
|
if (is_numeric($options['context'])) {
|
|
|
|
// A contextid was passed usage.
|
|
|
|
$params['context'] = \core\context::instance_by_id($options['context']);
|
|
|
|
} else if ($options['context'] instanceof \core\context) {
|
|
|
|
$params['context'] = $options['context'];
|
|
|
|
} else {
|
|
|
|
debugging(
|
|
|
|
'An invalid value for context was provided.',
|
|
|
|
DEBUG_DEVELOPER,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ($options !== null) {
|
2023-11-11 16:36:46 +08:00
|
|
|
// Something else was passed, so we'll just use an empty array.
|
|
|
|
debugging(sprintf(
|
|
|
|
'The options argument should be an Array, or stdclass. %s passed.',
|
|
|
|
gettype($options),
|
|
|
|
), DEBUG_DEVELOPER);
|
MDL-80072 core: Promote all formatting options to parameters
Now that PHP has support for named parameters, and we can use them in
Moodle, we should ditch `$options` arrays and use first-class,
documented, parameters.
Whilst this may seem scary, dumb, overwhelming, please note that you do
not need to supply all args, for example, to change the last parameter
of `format_text` you no longer need to do this:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
false,
null,
true,
true,
true,
false,
false,
true,
);
Instead you can do:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
allowid: true,
);
Or better still:
return \core\container::get(\core\formatting::class)->format_text(
text: $text,
format: FORMAT_MOODLE,
context: $context,
allowid: true,
);
This means that we can get defaults in the function signature, improves
our typing, and allows for deprecation and changes to options. It also
sets us up for success in the future.
2023-12-06 23:25:15 +08:00
|
|
|
|
|
|
|
// Attempt to cast to array since we always used to, but throw in some debugging.
|
|
|
|
$options = array_filter(
|
|
|
|
(array) $options,
|
|
|
|
fn ($key) => !is_numeric($key),
|
|
|
|
ARRAY_FILTER_USE_KEY,
|
|
|
|
);
|
2010-07-30 20:51:01 +00:00
|
|
|
}
|
|
|
|
|
MDL-80072 core: Promote all formatting options to parameters
Now that PHP has support for named parameters, and we can use them in
Moodle, we should ditch `$options` arrays and use first-class,
documented, parameters.
Whilst this may seem scary, dumb, overwhelming, please note that you do
not need to supply all args, for example, to change the last parameter
of `format_text` you no longer need to do this:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
false,
null,
true,
true,
true,
false,
false,
true,
);
Instead you can do:
return \core\container::get(\core\formatting::class)->format_text(
$text,
FORMAT_MOODLE,
$context,
allowid: true,
);
Or better still:
return \core\container::get(\core\formatting::class)->format_text(
text: $text,
format: FORMAT_MOODLE,
context: $context,
allowid: true,
);
This means that we can get defaults in the function signature, improves
our typing, and allows for deprecation and changes to options. It also
sets us up for success in the future.
2023-12-06 23:25:15 +08:00
|
|
|
if (isset($options['filter'])) {
|
|
|
|
$params['filter'] = (bool) $options['filter'];
|
|
|
|
} else {
|
|
|
|
$params['filter'] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($options['escape'])) {
|
|
|
|
$params['escape'] = (bool) $options['escape'];
|
|
|
|
} else {
|
|
|
|
$params['escape'] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
$validoptions = [
|
|
|
|
'string',
|
|
|
|
'striplinks',
|
|
|
|
'context',
|
|
|
|
'filter',
|
|
|
|
'escape',
|
|
|
|
];
|
|
|
|
|
|
|
|
if ($options) {
|
|
|
|
$invalidoptions = array_diff(array_keys($options), $validoptions);
|
|
|
|
if ($invalidoptions) {
|
|
|
|
debugging(sprintf(
|
|
|
|
'The following options are not valid: %s',
|
|
|
|
implode(', ', $invalidoptions),
|
|
|
|
), DEBUG_DEVELOPER);
|
|
|
|
}
|
2005-03-25 16:24:43 +00:00
|
|
|
}
|
2007-06-19 14:44:02 +00:00
|
|
|
|
2023-11-10 12:22:10 +08:00
|
|
|
return \core\di::get(\core\formatting::class)->format_string(
|
|
|
|
...$params,
|
|
|
|
);
|
2005-03-25 16:24:43 +00:00
|
|
|
}
|
|
|
|
|
2009-06-22 01:22:37 +00:00
|
|
|
/**
|
|
|
|
* Given a string, performs a negative lookahead looking for any ampersand character
|
|
|
|
* that is not followed by a proper HTML entity. If any is found, it is replaced
|
|
|
|
* by &. The string is then returned.
|
|
|
|
*
|
|
|
|
* @param string $string
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function replace_ampersands_not_followed_by_entity($string) {
|
2022-11-17 16:04:24 +01:00
|
|
|
return preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&", $string ?? '');
|
2009-06-22 01:22:37 +00:00
|
|
|
}
|
|
|
|
|
2009-06-22 06:07:56 +00:00
|
|
|
/**
|
|
|
|
* Given a string, replaces all <a>.*</a> by .* and returns the string.
|
2009-08-04 02:05:32 +00:00
|
|
|
*
|
2009-06-22 06:07:56 +00:00
|
|
|
* @param string $string
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function strip_links($string) {
|
2013-08-05 09:06:56 +12:00
|
|
|
return preg_replace('/(<a\s[^>]+?>)(.+?)(<\/a>)/is', '$2', $string);
|
2009-06-22 06:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This expression turns links into something nice in a text format. (Russell Jungwirth)
|
|
|
|
*
|
|
|
|
* @param string $string
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function wikify_links($string) {
|
2013-08-05 09:06:56 +12:00
|
|
|
return preg_replace('~(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)~i', '$3 [ $2 ]', $string);
|
2009-06-22 06:07:56 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Given text in a variety of format codings, this function returns the text as plain text suitable for plain email.
|
2004-09-23 04:36:43 +00:00
|
|
|
*
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param string $text The text to be formatted. This is raw text originally from user input.
|
2005-01-26 15:57:00 +00:00
|
|
|
* @param int $format Identifier of the text format to be used
|
2009-05-22 03:26:07 +00:00
|
|
|
* [FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN]
|
2004-09-25 05:29:21 +00:00
|
|
|
* @return string
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2003-05-04 04:07:36 +00:00
|
|
|
function format_text_email($text, $format) {
|
|
|
|
|
|
|
|
switch ($format) {
|
|
|
|
|
|
|
|
case FORMAT_PLAIN:
|
|
|
|
return $text;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FORMAT_WIKI:
|
2013-08-05 09:06:56 +12:00
|
|
|
// There should not be any of these any more!
|
2009-06-22 06:07:56 +00:00
|
|
|
$text = wikify_links($text);
|
2013-08-06 20:58:28 +02:00
|
|
|
return core_text::entities_to_utf8(strip_tags($text), true);
|
2003-05-04 04:07:36 +00:00
|
|
|
break;
|
|
|
|
|
2003-11-07 03:27:21 +00:00
|
|
|
case FORMAT_HTML:
|
|
|
|
return html_to_text($text);
|
|
|
|
break;
|
|
|
|
|
2004-07-30 04:02:58 +00:00
|
|
|
case FORMAT_MOODLE:
|
|
|
|
case FORMAT_MARKDOWN:
|
2004-08-21 14:21:09 +00:00
|
|
|
default:
|
2009-06-22 06:07:56 +00:00
|
|
|
$text = wikify_links($text);
|
2013-08-06 20:58:28 +02:00
|
|
|
return core_text::entities_to_utf8(strip_tags($text), true);
|
2003-05-04 04:07:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2002-10-10 07:26:10 +00:00
|
|
|
|
2009-04-21 21:17:21 +00:00
|
|
|
/**
|
|
|
|
* Formats activity intro text
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2009-04-21 21:17:21 +00:00
|
|
|
* @param string $module name of module
|
|
|
|
* @param object $activity instance of activity
|
|
|
|
* @param int $cmid course module id
|
2009-04-22 07:14:19 +00:00
|
|
|
* @param bool $filter filter resulting html text
|
2013-08-05 09:06:56 +12:00
|
|
|
* @return string
|
2009-04-21 21:17:21 +00:00
|
|
|
*/
|
2009-04-22 07:14:19 +00:00
|
|
|
function format_module_intro($module, $activity, $cmid, $filter=true) {
|
2009-04-22 05:10:08 +00:00
|
|
|
global $CFG;
|
|
|
|
require_once("$CFG->libdir/filelib.php");
|
2012-07-25 16:25:55 +08:00
|
|
|
$context = context_module::instance($cmid);
|
2013-08-05 09:06:56 +12:00
|
|
|
$options = array('noclean' => true, 'para' => false, 'filter' => $filter, 'context' => $context, 'overflowdiv' => true);
|
2010-07-03 13:37:13 +00:00
|
|
|
$intro = file_rewrite_pluginfile_urls($activity->intro, 'pluginfile.php', $context->id, 'mod_'.$module, 'intro', null);
|
2010-07-30 20:51:01 +00:00
|
|
|
return trim(format_text($intro, $activity->introformat, $options, null));
|
2009-04-21 21:17:21 +00:00
|
|
|
}
|
2007-03-15 06:08:46 +00:00
|
|
|
|
2013-12-19 10:19:42 +01:00
|
|
|
/**
|
|
|
|
* Removes the usage of Moodle files from a text.
|
|
|
|
*
|
|
|
|
* In some rare cases we need to re-use a text that already has embedded links
|
|
|
|
* to some files hosted within Moodle. But the new area in which we will push
|
|
|
|
* this content does not support files... therefore we need to remove those files.
|
|
|
|
*
|
|
|
|
* @param string $source The text
|
|
|
|
* @return string The stripped text
|
|
|
|
*/
|
|
|
|
function strip_pluginfile_content($source) {
|
|
|
|
$baseurl = '@@PLUGINFILE@@';
|
|
|
|
// Looking for something like < .* "@@pluginfile@@.*" .* >
|
|
|
|
$pattern = '$<[^<>]+["\']' . $baseurl . '[^"\']*["\'][^<>]*>$';
|
|
|
|
$stripped = preg_replace($pattern, '', $source);
|
|
|
|
// Use purify html to rebalence potentially mismatched tags and generally cleanup.
|
|
|
|
return purify_html($stripped);
|
|
|
|
}
|
|
|
|
|
2006-08-26 13:00:07 +00:00
|
|
|
/**
|
2009-04-20 10:05:50 +00:00
|
|
|
* Legacy function, used for cleaning of old forum and glossary text only.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2010-10-02 16:34:42 +00:00
|
|
|
* @param string $text text that may contain legacy TRUSTTEXT marker
|
2013-08-05 09:06:56 +12:00
|
|
|
* @return string text without legacy TRUSTTEXT marker
|
2006-08-26 13:00:07 +00:00
|
|
|
*/
|
|
|
|
function trusttext_strip($text) {
|
2016-08-25 17:04:11 +01:00
|
|
|
if (!is_string($text)) {
|
|
|
|
// This avoids the potential for an endless loop below.
|
|
|
|
throw new coding_exception('trusttext_strip parameter must be a string');
|
|
|
|
}
|
2013-08-05 09:06:56 +12:00
|
|
|
while (true) { // Removing nested TRUSTTEXT.
|
2007-01-04 10:23:06 +00:00
|
|
|
$orig = $text;
|
2009-04-20 10:05:50 +00:00
|
|
|
$text = str_replace('#####TRUSTTEXT#####', '', $text);
|
2006-08-26 13:00:07 +00:00
|
|
|
if (strcmp($orig, $text) === 0) {
|
|
|
|
return $text;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-20 10:05:50 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Must be called before editing of all texts with trust flag. Removes all XSS nasties from texts stored in database if needed.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param stdClass $object data object with xxx, xxxformat and xxxtrust fields
|
2009-04-20 10:05:50 +00:00
|
|
|
* @param string $field name of text field
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param context $context active context
|
|
|
|
* @return stdClass updated $object
|
2009-04-20 10:05:50 +00:00
|
|
|
*/
|
|
|
|
function trusttext_pre_edit($object, $field, $context) {
|
|
|
|
$trustfield = $field.'trust';
|
2009-08-04 02:05:32 +00:00
|
|
|
$formatfield = $field.'format';
|
|
|
|
|
2023-08-07 09:28:14 +02:00
|
|
|
if ($object->$formatfield == FORMAT_MARKDOWN) {
|
|
|
|
// We do not have a way to sanitise Markdown texts,
|
|
|
|
// luckily editors for this format should not have XSS problems.
|
|
|
|
return $object;
|
|
|
|
}
|
|
|
|
|
2009-04-20 10:05:50 +00:00
|
|
|
if (!$object->$trustfield or !trusttext_trusted($context)) {
|
|
|
|
$object->$field = clean_text($object->$field, $object->$formatfield);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $object;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-05-22 03:26:07 +00:00
|
|
|
* Is current user trusted to enter no dangerous XSS in this context?
|
|
|
|
*
|
2009-04-20 10:05:50 +00:00
|
|
|
* Please note the user must be in fact trusted everywhere on this server!!
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param context $context
|
2009-04-20 10:05:50 +00:00
|
|
|
* @return bool true if user trusted
|
|
|
|
*/
|
|
|
|
function trusttext_trusted($context) {
|
2009-08-04 02:05:32 +00:00
|
|
|
return (trusttext_active() and has_capability('moodle/site:trustcontent', $context));
|
2009-04-20 10:05:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Is trusttext feature active?
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2009-04-20 10:05:50 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
function trusttext_active() {
|
|
|
|
global $CFG;
|
|
|
|
|
2009-08-04 02:05:32 +00:00
|
|
|
return !empty($CFG->enabletrusttext);
|
2009-04-20 10:05:50 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Cleans raw text removing nasties.
|
|
|
|
*
|
|
|
|
* Given raw text (eg typed in by a user) this function cleans it up and removes any nasty tags that could mess up
|
|
|
|
* Moodle pages through XSS attacks.
|
2011-11-19 13:22:33 +01:00
|
|
|
*
|
|
|
|
* The result must be used as a HTML text fragment, this function can not cleanup random
|
|
|
|
* parts of html tags such as url or src attributes.
|
2004-09-23 04:36:43 +00:00
|
|
|
*
|
2010-10-24 11:48:45 +00:00
|
|
|
* NOTE: the format parameter was deprecated because we can safely clean only HTML.
|
|
|
|
*
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param string $text The text to be cleaned
|
2011-11-19 13:22:33 +01:00
|
|
|
* @param int|string $format deprecated parameter, should always contain FORMAT_HTML or FORMAT_MOODLE
|
2011-02-28 11:19:58 +00:00
|
|
|
* @param array $options Array of options; currently only option supported is 'allowid' (if true,
|
|
|
|
* does not remove id attributes when cleaning)
|
2004-09-25 05:29:21 +00:00
|
|
|
* @return string The cleaned up text
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2011-02-28 11:19:58 +00:00
|
|
|
function clean_text($text, $format = FORMAT_HTML, $options = array()) {
|
2012-03-19 14:02:28 +01:00
|
|
|
$text = (string)$text;
|
2002-10-18 09:09:19 +00:00
|
|
|
|
2010-10-24 11:48:45 +00:00
|
|
|
if ($format != FORMAT_HTML and $format != FORMAT_HTML) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// TODO: we need to standardise cleanup of text when loading it into editor first.
|
|
|
|
// debugging('clean_text() is designed to work only with html');.
|
2010-10-24 11:48:45 +00:00
|
|
|
}
|
2004-07-30 04:02:58 +00:00
|
|
|
|
2010-10-24 11:48:45 +00:00
|
|
|
if ($format == FORMAT_PLAIN) {
|
|
|
|
return $text;
|
|
|
|
}
|
2004-07-30 04:02:58 +00:00
|
|
|
|
2012-03-19 14:02:28 +01:00
|
|
|
if (is_purify_html_necessary($text)) {
|
|
|
|
$text = purify_html($text, $options);
|
|
|
|
}
|
2005-01-29 13:02:28 +00:00
|
|
|
|
2011-11-19 13:22:33 +01:00
|
|
|
// Originally we tried to neutralise some script events here, it was a wrong approach because
|
|
|
|
// it was trivial to work around that (for example using style based XSS exploits).
|
|
|
|
// We must not give false sense of security here - all developers MUST understand how to use
|
|
|
|
// rawurlencode(), htmlentities(), htmlspecialchars(), p(), s(), moodle_url, html_writer and friends!!!
|
2003-04-27 10:46:16 +00:00
|
|
|
|
2010-10-24 11:48:45 +00:00
|
|
|
return $text;
|
2002-03-26 12:58:54 +00:00
|
|
|
}
|
2001-11-22 06:23:56 +00:00
|
|
|
|
2012-03-19 14:02:28 +01:00
|
|
|
/**
|
|
|
|
* Is it necessary to use HTMLPurifier?
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2012-03-19 14:02:28 +01:00
|
|
|
* @private
|
|
|
|
* @param string $text
|
|
|
|
* @return bool false means html is safe and valid, true means use HTMLPurifier
|
|
|
|
*/
|
|
|
|
function is_purify_html_necessary($text) {
|
|
|
|
if ($text === '') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($text === (string)((int)$text)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strpos($text, '&') !== false or preg_match('|<[^pesb/]|', $text)) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// We need to normalise entities or other tags except p, em, strong and br present.
|
2012-03-19 14:02:28 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
$altered = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8', true);
|
|
|
|
if ($altered === $text) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// No < > or other special chars means this must be safe.
|
2012-03-19 14:02:28 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Let's try to convert back some safe html tags.
|
2012-03-19 14:02:28 +01:00
|
|
|
$altered = preg_replace('|<p>(.*?)</p>|m', '<p>$1</p>', $altered);
|
|
|
|
if ($altered === $text) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
$altered = preg_replace('|<em>([^<>]+?)</em>|m', '<em>$1</em>', $altered);
|
|
|
|
if ($altered === $text) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
$altered = preg_replace('|<strong>([^<>]+?)</strong>|m', '<strong>$1</strong>', $altered);
|
|
|
|
if ($altered === $text) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
$altered = str_replace('<br />', '<br />', $altered);
|
|
|
|
if ($altered === $text) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-04-18 21:52:03 +00:00
|
|
|
/**
|
|
|
|
* KSES replacement cleaning function - uses HTML Purifier.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
|
|
|
* @param string $text The (X)HTML string to purify
|
2011-02-28 11:19:58 +00:00
|
|
|
* @param array $options Array of options; currently only option supported is 'allowid' (if set,
|
|
|
|
* does not remove id attributes when cleaning)
|
2011-10-22 09:25:06 +02:00
|
|
|
* @return string
|
2007-04-18 21:52:03 +00:00
|
|
|
*/
|
2011-02-28 11:19:58 +00:00
|
|
|
function purify_html($text, $options = array()) {
|
2007-04-18 21:52:03 +00:00
|
|
|
global $CFG;
|
|
|
|
|
2013-08-03 10:48:15 +02:00
|
|
|
$text = (string)$text;
|
|
|
|
|
2011-02-28 11:19:58 +00:00
|
|
|
static $purifiers = array();
|
2012-11-05 09:36:54 +13:00
|
|
|
static $caches = array();
|
|
|
|
|
2013-08-03 10:48:15 +02:00
|
|
|
// Purifier code can change only during major version upgrade.
|
|
|
|
$version = empty($CFG->version) ? 0 : $CFG->version;
|
|
|
|
$cachedir = "$CFG->localcachedir/htmlpurifier/$version";
|
|
|
|
if (!file_exists($cachedir)) {
|
|
|
|
// Purging of caches may remove the cache dir at any time,
|
|
|
|
// luckily file_exists() results should be cached for all existing directories.
|
|
|
|
$purifiers = array();
|
|
|
|
$caches = array();
|
|
|
|
gc_collect_cycles();
|
|
|
|
|
|
|
|
make_localcache_directory('htmlpurifier', false);
|
|
|
|
check_dir_exists($cachedir);
|
|
|
|
}
|
|
|
|
|
|
|
|
$allowid = empty($options['allowid']) ? 0 : 1;
|
|
|
|
$allowobjectembed = empty($CFG->allowobjectembed) ? 0 : 1;
|
|
|
|
|
|
|
|
$type = 'type_'.$allowid.'_'.$allowobjectembed;
|
2012-11-05 09:36:54 +13:00
|
|
|
|
|
|
|
if (!array_key_exists($type, $caches)) {
|
|
|
|
$caches[$type] = cache::make('core', 'htmlpurifier', array('type' => $type));
|
|
|
|
}
|
|
|
|
$cache = $caches[$type];
|
|
|
|
|
2013-08-03 10:48:15 +02:00
|
|
|
// Add revision number and all options to the text key so that it is compatible with local cluster node caches.
|
|
|
|
$key = "|$version|$allowobjectembed|$allowid|$text";
|
|
|
|
$filteredtext = $cache->get($key);
|
|
|
|
|
|
|
|
if ($filteredtext === true) {
|
|
|
|
// The filtering did not change the text last time, no need to filter anything again.
|
|
|
|
return $text;
|
|
|
|
} else if ($filteredtext !== false) {
|
2012-11-05 09:36:54 +13:00
|
|
|
return $filteredtext;
|
|
|
|
}
|
|
|
|
|
2011-02-28 11:19:58 +00:00
|
|
|
if (empty($purifiers[$type])) {
|
2008-06-16 16:39:09 +00:00
|
|
|
require_once $CFG->libdir.'/htmlpurifier/HTMLPurifier.safe-includes.php';
|
2012-04-23 10:24:46 +02:00
|
|
|
require_once $CFG->libdir.'/htmlpurifier/locallib.php';
|
2007-04-18 21:52:03 +00:00
|
|
|
$config = HTMLPurifier_Config::createDefault();
|
2010-09-16 20:02:54 +00:00
|
|
|
|
|
|
|
$config->set('HTML.DefinitionID', 'moodlehtml');
|
2023-05-15 17:21:19 +02:00
|
|
|
$config->set('HTML.DefinitionRev', 7);
|
2010-09-16 20:02:54 +00:00
|
|
|
$config->set('Cache.SerializerPath', $cachedir);
|
2011-04-09 10:27:51 +02:00
|
|
|
$config->set('Cache.SerializerPermissions', $CFG->directorypermissions);
|
2010-09-16 20:02:54 +00:00
|
|
|
$config->set('Core.NormalizeNewlines', false);
|
2009-07-19 12:17:48 +00:00
|
|
|
$config->set('Core.ConvertDocumentToFragment', true);
|
|
|
|
$config->set('Core.Encoding', 'UTF-8');
|
|
|
|
$config->set('HTML.Doctype', 'XHTML 1.0 Transitional');
|
2013-08-05 09:06:56 +12:00
|
|
|
$config->set('URI.AllowedSchemes', array(
|
|
|
|
'http' => true,
|
|
|
|
'https' => true,
|
|
|
|
'ftp' => true,
|
|
|
|
'irc' => true,
|
|
|
|
'nntp' => true,
|
|
|
|
'news' => true,
|
|
|
|
'rtsp' => true,
|
2014-07-07 17:21:08 +01:00
|
|
|
'rtmp' => true,
|
2013-08-05 09:06:56 +12:00
|
|
|
'teamspeak' => true,
|
|
|
|
'gopher' => true,
|
|
|
|
'mms' => true,
|
|
|
|
'mailto' => true
|
|
|
|
));
|
2009-07-19 12:17:48 +00:00
|
|
|
$config->set('Attr.AllowedFrameTargets', array('_blank'));
|
2010-09-16 20:02:54 +00:00
|
|
|
|
2013-08-03 10:48:15 +02:00
|
|
|
if ($allowobjectembed) {
|
2010-09-21 07:20:40 +00:00
|
|
|
$config->set('HTML.SafeObject', true);
|
|
|
|
$config->set('Output.FlashCompat', true);
|
2010-09-21 07:51:09 +00:00
|
|
|
$config->set('HTML.SafeEmbed', true);
|
2010-09-21 07:20:40 +00:00
|
|
|
}
|
|
|
|
|
2013-08-03 10:48:15 +02:00
|
|
|
if ($allowid) {
|
2011-02-28 11:19:58 +00:00
|
|
|
$config->set('Attr.EnableID', true);
|
|
|
|
}
|
|
|
|
|
2011-04-09 10:27:51 +02:00
|
|
|
if ($def = $config->maybeGetRawHTMLDefinition()) {
|
2019-07-08 16:09:40 +02:00
|
|
|
$def->addElement('nolink', 'Inline', 'Flow', array()); // Skip our filters inside.
|
2013-08-03 10:48:15 +02:00
|
|
|
$def->addElement('tex', 'Inline', 'Inline', array()); // Tex syntax, equivalent to $$xx$$.
|
|
|
|
$def->addElement('algebra', 'Inline', 'Inline', array()); // Algebra syntax, equivalent to @@xx@@.
|
|
|
|
$def->addElement('lang', 'Block', 'Flow', array(), array('lang'=>'CDATA')); // Original multilang style - only our hacked lang attribute.
|
|
|
|
$def->addAttribute('span', 'xxxlang', 'CDATA'); // Current very problematic multilang.
|
2023-07-02 09:05:27 +03:00
|
|
|
// Enable the bidirectional isolate element and its span equivalent.
|
|
|
|
$def->addElement('bdi', 'Inline', 'Flow', 'Common');
|
|
|
|
$def->addAttribute('span', 'dir', 'Enum#ltr,rtl,auto');
|
2015-07-17 22:23:18 +09:00
|
|
|
|
2016-07-21 16:04:29 +08:00
|
|
|
// Media elements.
|
|
|
|
// https://html.spec.whatwg.org/#the-video-element
|
2023-05-15 17:21:19 +02:00
|
|
|
$def->addElement('video', 'Inline', 'Optional: #PCDATA | Flow | source | track', 'Common', [
|
2016-07-21 16:04:29 +08:00
|
|
|
'src' => 'URI',
|
|
|
|
'crossorigin' => 'Enum#anonymous,use-credentials',
|
|
|
|
'poster' => 'URI',
|
|
|
|
'preload' => 'Enum#auto,metadata,none',
|
|
|
|
'autoplay' => 'Bool',
|
|
|
|
'playsinline' => 'Bool',
|
|
|
|
'loop' => 'Bool',
|
|
|
|
'muted' => 'Bool',
|
|
|
|
'controls' => 'Bool',
|
|
|
|
'width' => 'Length',
|
|
|
|
'height' => 'Length',
|
|
|
|
]);
|
|
|
|
// https://html.spec.whatwg.org/#the-audio-element
|
2023-05-15 17:21:19 +02:00
|
|
|
$def->addElement('audio', 'Inline', 'Optional: #PCDATA | Flow | source | track', 'Common', [
|
2016-07-21 16:04:29 +08:00
|
|
|
'src' => 'URI',
|
|
|
|
'crossorigin' => 'Enum#anonymous,use-credentials',
|
|
|
|
'preload' => 'Enum#auto,metadata,none',
|
|
|
|
'autoplay' => 'Bool',
|
|
|
|
'loop' => 'Bool',
|
|
|
|
'muted' => 'Bool',
|
|
|
|
'controls' => 'Bool'
|
|
|
|
]);
|
|
|
|
// https://html.spec.whatwg.org/#the-source-element
|
2016-08-16 13:44:53 +08:00
|
|
|
$def->addElement('source', false, 'Empty', null, [
|
2016-07-21 16:04:29 +08:00
|
|
|
'src' => 'URI',
|
|
|
|
'type' => 'Text'
|
|
|
|
]);
|
2016-08-16 13:44:53 +08:00
|
|
|
// https://html.spec.whatwg.org/#the-track-element
|
|
|
|
$def->addElement('track', false, 'Empty', null, [
|
|
|
|
'src' => 'URI',
|
|
|
|
'kind' => 'Enum#subtitles,captions,descriptions,chapters,metadata',
|
|
|
|
'srclang' => 'Text',
|
|
|
|
'label' => 'Text',
|
|
|
|
'default' => 'Bool',
|
|
|
|
]);
|
2016-07-21 16:04:29 +08:00
|
|
|
|
2015-07-17 22:23:18 +09:00
|
|
|
// Use the built-in Ruby module to add annotation support.
|
|
|
|
$def->manager->addModule(new HTMLPurifier_HTMLModule_Ruby());
|
2011-04-09 10:27:51 +02:00
|
|
|
}
|
2010-09-16 20:02:54 +00:00
|
|
|
|
2007-04-18 21:52:03 +00:00
|
|
|
$purifier = new HTMLPurifier($config);
|
2011-02-28 11:19:58 +00:00
|
|
|
$purifiers[$type] = $purifier;
|
|
|
|
} else {
|
|
|
|
$purifier = $purifiers[$type];
|
2007-04-18 21:52:03 +00:00
|
|
|
}
|
2010-09-16 20:02:54 +00:00
|
|
|
|
|
|
|
$multilang = (strpos($text, 'class="multilang"') !== false);
|
|
|
|
|
2012-11-05 09:36:54 +13:00
|
|
|
$filteredtext = $text;
|
2010-09-16 20:02:54 +00:00
|
|
|
if ($multilang) {
|
2013-08-05 09:06:56 +12:00
|
|
|
$filteredtextregex = '/<span(\s+lang="([a-zA-Z0-9_-]+)"|\s+class="multilang"){2}\s*>/';
|
|
|
|
$filteredtext = preg_replace($filteredtextregex, '<span xxxlang="${2}">', $filteredtext);
|
2010-09-16 20:02:54 +00:00
|
|
|
}
|
2013-08-03 10:48:15 +02:00
|
|
|
$filteredtext = (string)$purifier->purify($filteredtext);
|
2010-09-16 20:02:54 +00:00
|
|
|
if ($multilang) {
|
2012-11-05 09:36:54 +13:00
|
|
|
$filteredtext = preg_replace('/<span xxxlang="([a-zA-Z0-9_-]+)">/', '<span lang="${1}" class="multilang">', $filteredtext);
|
2010-09-16 20:02:54 +00:00
|
|
|
}
|
2013-08-03 10:48:15 +02:00
|
|
|
|
|
|
|
if ($text === $filteredtext) {
|
|
|
|
// No need to store the filtered text, next time we will just return unfiltered text
|
|
|
|
// because it was not changed by purifying.
|
|
|
|
$cache->set($key, true);
|
|
|
|
} else {
|
|
|
|
$cache->set($key, $filteredtext);
|
|
|
|
}
|
2010-09-16 20:02:54 +00:00
|
|
|
|
2012-11-05 09:36:54 +13:00
|
|
|
return $filteredtext;
|
2007-04-18 21:52:03 +00:00
|
|
|
}
|
|
|
|
|
2004-09-25 05:29:21 +00:00
|
|
|
/**
|
|
|
|
* Given plain text, makes it into HTML as nicely as possible.
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
|
|
|
* May contain HTML tags already.
|
2004-09-25 05:29:21 +00:00
|
|
|
*
|
2010-10-23 18:41:47 +00:00
|
|
|
* Do not abuse this function. It is intended as lower level formatting feature used
|
2013-08-05 09:06:56 +12:00
|
|
|
* by {@link format_text()} to convert FORMAT_MOODLE to HTML. You are supposed
|
2010-10-23 18:41:47 +00:00
|
|
|
* to call format_text() in most of cases.
|
|
|
|
*
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param string $text The string to convert.
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param boolean $smileyignored Was used to determine if smiley characters should convert to smiley images, ignored now
|
2009-11-27 02:15:09 +00:00
|
|
|
* @param boolean $para If true then the returned string will be wrapped in div tags
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param boolean $newlines If true then lines newline breaks will be converted to HTML newline breaks.
|
|
|
|
* @return string
|
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
function text_to_html($text, $smileyignored = null, $para = true, $newlines = true) {
|
|
|
|
// Remove any whitespace that may be between HTML tags.
|
2009-06-22 01:22:37 +00:00
|
|
|
$text = preg_replace("~>([[:space:]]+)<~i", "><", $text);
|
2002-08-22 08:31:29 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Remove any returns that precede or follow HTML tags.
|
2009-06-22 01:22:37 +00:00
|
|
|
$text = preg_replace("~([\n\r])<~i", " <", $text);
|
|
|
|
$text = preg_replace("~>([\n\r])~i", "> ", $text);
|
2002-08-22 08:31:29 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Make returns into HTML newlines.
|
2004-03-09 06:44:27 +00:00
|
|
|
if ($newlines) {
|
|
|
|
$text = nl2br($text);
|
|
|
|
}
|
2001-11-22 06:23:56 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Wrap the whole thing in a div if required.
|
2002-08-12 13:45:41 +00:00
|
|
|
if ($para) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// In 1.9 this was changed from a p => div.
|
2009-11-27 02:15:09 +00:00
|
|
|
return '<div class="text_to_html">'.$text.'</div>';
|
2002-08-12 13:45:41 +00:00
|
|
|
} else {
|
|
|
|
return $text;
|
|
|
|
}
|
2001-11-22 06:23:56 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
|
|
|
* Given Markdown formatted text, make it into XHTML using external function
|
|
|
|
*
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param string $text The markdown formatted text to be converted.
|
|
|
|
* @return string Converted text
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2004-07-30 04:02:58 +00:00
|
|
|
function markdown_to_html($text) {
|
|
|
|
global $CFG;
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
if ($text === '' or $text === null) {
|
2010-06-06 17:17:06 +00:00
|
|
|
return $text;
|
|
|
|
}
|
|
|
|
|
2014-03-10 12:19:08 +08:00
|
|
|
require_once($CFG->libdir .'/markdown/MarkdownInterface.php');
|
2013-09-19 22:26:01 +02:00
|
|
|
require_once($CFG->libdir .'/markdown/Markdown.php');
|
|
|
|
require_once($CFG->libdir .'/markdown/MarkdownExtra.php');
|
2004-07-30 04:02:58 +00:00
|
|
|
|
2013-09-19 22:26:01 +02:00
|
|
|
return \Michelf\MarkdownExtra::defaultTransform($text);
|
2004-07-30 04:02:58 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
2004-09-25 05:29:21 +00:00
|
|
|
* Given HTML text, make it into plain text using external function
|
2004-09-23 04:36:43 +00:00
|
|
|
*
|
|
|
|
* @param string $html The text to be converted.
|
2010-08-04 17:40:01 +00:00
|
|
|
* @param integer $width Width to wrap the text at. (optional, default 75 which
|
|
|
|
* is a good value for email. 0 means do not limit line length.)
|
2010-09-02 13:06:17 +00:00
|
|
|
* @param boolean $dolinks By default, any links in the HTML are collected, and
|
|
|
|
* printed as a list at the end of the HTML. If you don't want that, set this
|
|
|
|
* argument to false.
|
2010-08-04 17:40:01 +00:00
|
|
|
* @return string plain text equivalent of the HTML.
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2010-09-02 13:06:17 +00:00
|
|
|
function html_to_text($html, $width = 75, $dolinks = true) {
|
2003-11-07 04:14:38 +00:00
|
|
|
global $CFG;
|
2003-11-07 03:27:21 +00:00
|
|
|
|
2015-10-01 14:04:15 +08:00
|
|
|
require_once($CFG->libdir .'/html2text/lib.php');
|
|
|
|
|
|
|
|
$options = array(
|
|
|
|
'width' => $width,
|
|
|
|
'do_links' => 'table',
|
|
|
|
);
|
2003-11-07 03:27:21 +00:00
|
|
|
|
2015-10-01 14:04:15 +08:00
|
|
|
if (empty($dolinks)) {
|
|
|
|
$options['do_links'] = 'none';
|
|
|
|
}
|
|
|
|
$h2t = new core_html2text($html, $options);
|
|
|
|
$result = $h2t->getText();
|
2008-07-14 02:32:59 +00:00
|
|
|
|
2008-06-16 14:07:47 +00:00
|
|
|
return $result;
|
2003-11-07 03:27:21 +00:00
|
|
|
}
|
|
|
|
|
2016-02-23 10:44:20 +08:00
|
|
|
/**
|
2016-05-18 16:28:18 +08:00
|
|
|
* Converts texts or strings to plain text.
|
|
|
|
*
|
|
|
|
* - When used to convert user input introduced in an editor the text format needs to be passed in $contentformat like we usually
|
|
|
|
* do in format_text.
|
|
|
|
* - When this function is used for strings that are usually passed through format_string before displaying them
|
|
|
|
* we need to set $contentformat to false. This will execute html_to_text as these strings can contain multilang tags if
|
|
|
|
* multilang filter is applied to headings.
|
2016-02-23 10:44:20 +08:00
|
|
|
*
|
|
|
|
* @param string $content The text as entered by the user
|
2016-05-18 16:28:18 +08:00
|
|
|
* @param int|false $contentformat False for strings or the text format: FORMAT_MOODLE/FORMAT_HTML/FORMAT_PLAIN/FORMAT_MARKDOWN
|
2016-02-23 10:44:20 +08:00
|
|
|
* @return string Plain text.
|
|
|
|
*/
|
|
|
|
function content_to_text($content, $contentformat) {
|
|
|
|
|
|
|
|
switch ($contentformat) {
|
|
|
|
case FORMAT_PLAIN:
|
2016-05-18 16:28:18 +08:00
|
|
|
// Nothing here.
|
|
|
|
break;
|
2016-02-23 10:44:20 +08:00
|
|
|
case FORMAT_MARKDOWN:
|
2016-05-18 16:28:18 +08:00
|
|
|
$content = markdown_to_html($content);
|
|
|
|
$content = html_to_text($content, 75, false);
|
|
|
|
break;
|
2016-02-23 10:44:20 +08:00
|
|
|
default:
|
2016-05-18 16:28:18 +08:00
|
|
|
// FORMAT_HTML, FORMAT_MOODLE and $contentformat = false, the later one are strings usually formatted through
|
|
|
|
// format_string, we need to convert them from html because they can contain HTML (multilang filter).
|
|
|
|
$content = html_to_text($content, 75, false);
|
2016-02-23 10:44:20 +08:00
|
|
|
}
|
2016-05-18 16:28:18 +08:00
|
|
|
|
|
|
|
return trim($content, "\r\n ");
|
2016-02-23 10:44:20 +08:00
|
|
|
}
|
|
|
|
|
2018-06-27 16:32:50 -04:00
|
|
|
/**
|
|
|
|
* Factory method for extracting draft file links from arbitrary text using regular expressions. Only text
|
|
|
|
* is required; other file fields may be passed to filter.
|
|
|
|
*
|
|
|
|
* @param string $text Some html content.
|
|
|
|
* @param bool $forcehttps force https urls.
|
|
|
|
* @param int $contextid This parameter and the next three identify the file area to save to.
|
|
|
|
* @param string $component The component name.
|
|
|
|
* @param string $filearea The filearea.
|
|
|
|
* @param int $itemid The item id for the filearea.
|
|
|
|
* @param string $filename The specific filename of the file.
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
function extract_draft_file_urls_from_text($text, $forcehttps = false, $contextid = null, $component = null,
|
2018-08-08 16:15:09 +08:00
|
|
|
$filearea = null, $itemid = null, $filename = null) {
|
2018-06-27 16:32:50 -04:00
|
|
|
global $CFG;
|
|
|
|
|
|
|
|
$wwwroot = $CFG->wwwroot;
|
|
|
|
if ($forcehttps) {
|
|
|
|
$wwwroot = str_replace('http://', 'https://', $wwwroot);
|
|
|
|
}
|
|
|
|
$urlstring = '/' . preg_quote($wwwroot, '/');
|
|
|
|
|
|
|
|
$urlbase = preg_quote('draftfile.php');
|
|
|
|
$urlstring .= "\/(?<urlbase>{$urlbase})";
|
|
|
|
|
|
|
|
if (is_null($contextid)) {
|
|
|
|
$contextid = '[0-9]+';
|
|
|
|
}
|
|
|
|
$urlstring .= "\/(?<contextid>{$contextid})";
|
|
|
|
|
|
|
|
if (is_null($component)) {
|
|
|
|
$component = '[a-z_]+';
|
|
|
|
}
|
|
|
|
$urlstring .= "\/(?<component>{$component})";
|
|
|
|
|
|
|
|
if (is_null($filearea)) {
|
|
|
|
$filearea = '[a-z_]+';
|
|
|
|
}
|
|
|
|
$urlstring .= "\/(?<filearea>{$filearea})";
|
|
|
|
|
|
|
|
if (is_null($itemid)) {
|
|
|
|
$itemid = '[0-9]+';
|
|
|
|
}
|
|
|
|
$urlstring .= "\/(?<itemid>{$itemid})";
|
|
|
|
|
|
|
|
// Filename matching magic based on file_rewrite_urls_to_pluginfile().
|
|
|
|
if (is_null($filename)) {
|
|
|
|
$filename = '[^\'\",&<>|`\s:\\\\]+';
|
|
|
|
}
|
|
|
|
$urlstring .= "\/(?<filename>{$filename})/";
|
|
|
|
|
|
|
|
// Regular expression which matches URLs and returns their components.
|
|
|
|
preg_match_all($urlstring, $text, $urls, PREG_SET_ORDER);
|
|
|
|
return $urls;
|
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
|
|
|
* This function will highlight search words in a given string
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2004-09-23 04:36:43 +00:00
|
|
|
* It cares about HTML and will not ruin links. It's best to use
|
|
|
|
* this function after performing any conversions to HTML.
|
|
|
|
*
|
2008-12-11 10:33:57 +00:00
|
|
|
* @param string $needle The search string. Syntax like "word1 +word2 -word3" is dealt with correctly.
|
|
|
|
* @param string $haystack The string (HTML) within which to highlight the search terms.
|
|
|
|
* @param boolean $matchcase whether to do case-sensitive. Default case-insensitive.
|
|
|
|
* @param string $prefix the string to put before each search term found.
|
|
|
|
* @param string $suffix the string to put after each search term found.
|
|
|
|
* @return string The highlighted HTML.
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2008-12-11 10:33:57 +00:00
|
|
|
function highlight($needle, $haystack, $matchcase = false,
|
|
|
|
$prefix = '<span class="highlight">', $suffix = '</span>') {
|
2008-01-01 15:51:54 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Quick bail-out in trivial cases.
|
2008-01-01 15:51:54 +00:00
|
|
|
if (empty($needle) or empty($haystack)) {
|
2003-12-13 06:27:25 +00:00
|
|
|
return $haystack;
|
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Break up the search term into words, discard any -words and build a regexp.
|
2008-12-11 10:33:57 +00:00
|
|
|
$words = preg_split('/ +/', trim($needle));
|
|
|
|
foreach ($words as $index => $word) {
|
|
|
|
if (strpos($word, '-') === 0) {
|
|
|
|
unset($words[$index]);
|
|
|
|
} else if (strpos($word, '+') === 0) {
|
|
|
|
$words[$index] = '\b' . preg_quote(ltrim($word, '+'), '/') . '\b'; // Match only as a complete word.
|
|
|
|
} else {
|
|
|
|
$words[$index] = preg_quote($word, '/');
|
2003-08-09 03:57:46 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-05 09:06:56 +12:00
|
|
|
$regexp = '/(' . implode('|', $words) . ')/u'; // Char u is to do UTF-8 matching.
|
2008-12-11 10:33:57 +00:00
|
|
|
if (!$matchcase) {
|
|
|
|
$regexp .= 'i';
|
2003-08-09 03:57:46 +00:00
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Another chance to bail-out if $search was only -words.
|
2008-12-11 10:33:57 +00:00
|
|
|
if (empty($words)) {
|
|
|
|
return $haystack;
|
2003-08-09 03:57:46 +00:00
|
|
|
}
|
|
|
|
|
2014-08-08 11:31:27 +01:00
|
|
|
// Split the string into HTML tags and real content.
|
|
|
|
$chunks = preg_split('/((?:<[^>]*>)+)/', $haystack, -1, PREG_SPLIT_DELIM_CAPTURE);
|
|
|
|
|
|
|
|
// We have an array of alternating blocks of text, then HTML tags, then text, ...
|
|
|
|
// Loop through replacing search terms in the text, and leaving the HTML unchanged.
|
|
|
|
$ishtmlchunk = false;
|
|
|
|
$result = '';
|
|
|
|
foreach ($chunks as $chunk) {
|
|
|
|
if ($ishtmlchunk) {
|
|
|
|
$result .= $chunk;
|
|
|
|
} else {
|
|
|
|
$result .= preg_replace($regexp, $prefix . '$1' . $suffix, $chunk);
|
|
|
|
}
|
|
|
|
$ishtmlchunk = !$ishtmlchunk;
|
2008-12-11 10:33:57 +00:00
|
|
|
}
|
2004-12-31 15:23:50 +00:00
|
|
|
|
2014-08-08 11:31:27 +01:00
|
|
|
return $result;
|
2003-08-09 03:57:46 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
|
|
|
* This function will highlight instances of $needle in $haystack
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
|
|
|
* It's faster that the above function {@link highlight()} and doesn't care about
|
2004-09-23 04:36:43 +00:00
|
|
|
* HTML or anything.
|
|
|
|
*
|
|
|
|
* @param string $needle The string to search for
|
|
|
|
* @param string $haystack The string to search for $needle in
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return string The highlighted HTML
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2003-08-09 03:57:46 +00:00
|
|
|
function highlightfast($needle, $haystack) {
|
2002-06-11 07:01:51 +00:00
|
|
|
|
2008-01-01 15:51:54 +00:00
|
|
|
if (empty($needle) or empty($haystack)) {
|
|
|
|
return $haystack;
|
|
|
|
}
|
|
|
|
|
2013-08-06 20:58:28 +02:00
|
|
|
$parts = explode(core_text::strtolower($needle), core_text::strtolower($haystack));
|
2002-06-11 07:01:51 +00:00
|
|
|
|
2008-01-01 15:51:54 +00:00
|
|
|
if (count($parts) === 1) {
|
|
|
|
return $haystack;
|
|
|
|
}
|
|
|
|
|
2002-06-11 07:01:51 +00:00
|
|
|
$pos = 0;
|
|
|
|
|
|
|
|
foreach ($parts as $key => $part) {
|
|
|
|
$parts[$key] = substr($haystack, $pos, strlen($part));
|
|
|
|
$pos += strlen($part);
|
|
|
|
|
2004-09-22 14:39:15 +00:00
|
|
|
$parts[$key] .= '<span class="highlight">'.substr($haystack, $pos, strlen($needle)).'</span>';
|
2002-06-11 07:01:51 +00:00
|
|
|
$pos += strlen($needle);
|
2004-05-21 13:07:11 +00:00
|
|
|
}
|
2002-06-11 07:01:51 +00:00
|
|
|
|
2008-01-01 15:51:54 +00:00
|
|
|
return str_replace('<span class="highlight"></span>', '', join('', $parts));
|
2002-06-11 07:01:51 +00:00
|
|
|
}
|
|
|
|
|
2022-05-27 14:24:29 +08:00
|
|
|
/**
|
|
|
|
* Converts a language code to hyphen-separated format in accordance to the
|
|
|
|
* {@link https://datatracker.ietf.org/doc/html/rfc5646#section-2.1 BCP47 syntax}.
|
|
|
|
*
|
|
|
|
* For additional information, check out
|
|
|
|
* {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang MDN web docs - lang}.
|
|
|
|
*
|
|
|
|
* @param string $langcode The language code to convert.
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function get_html_lang_attribute_value(string $langcode): string {
|
2023-11-21 13:58:37 +00:00
|
|
|
$langcode = clean_param($langcode, PARAM_LANG);
|
|
|
|
if ($langcode === '') {
|
|
|
|
return 'en';
|
2022-05-27 14:24:29 +08:00
|
|
|
}
|
2023-11-21 13:58:37 +00:00
|
|
|
|
|
|
|
// Grab language ISO code from lang config. If it differs from English, then it's been specified and we can return it.
|
|
|
|
$langiso = (string) (new lang_string('iso6391', 'core_langconfig', null, $langcode));
|
|
|
|
if ($langiso !== 'en') {
|
|
|
|
return $langiso;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Where we cannot determine the value from lang config, use the first two characters from the lang code.
|
|
|
|
return substr($langcode, 0, 2);
|
2022-05-27 14:24:29 +08:00
|
|
|
}
|
|
|
|
|
2007-02-21 10:42:50 +00:00
|
|
|
/**
|
|
|
|
* Return a string containing 'lang', xml:lang and optionally 'dir' HTML attributes.
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2007-02-21 10:42:50 +00:00
|
|
|
* Internationalisation, for print_header and backup/restorelib.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
|
|
|
* @param bool $dir Default false
|
|
|
|
* @return string Attributes
|
2007-02-21 10:42:50 +00:00
|
|
|
*/
|
|
|
|
function get_html_lang($dir = false) {
|
2021-10-22 14:15:56 +08:00
|
|
|
global $CFG;
|
|
|
|
|
|
|
|
$currentlang = current_language();
|
2023-03-24 12:42:53 +01:00
|
|
|
if (isset($CFG->lang) && $currentlang !== $CFG->lang && !get_string_manager()->translation_exists($currentlang)) {
|
2021-10-22 14:15:56 +08:00
|
|
|
// Use the default site language when the current language is not available.
|
|
|
|
$currentlang = $CFG->lang;
|
|
|
|
// Fix the current language.
|
|
|
|
fix_current_language($currentlang);
|
|
|
|
}
|
|
|
|
|
2007-02-21 10:42:50 +00:00
|
|
|
$direction = '';
|
|
|
|
if ($dir) {
|
2010-04-10 18:26:20 +00:00
|
|
|
if (right_to_left()) {
|
2007-02-21 10:42:50 +00:00
|
|
|
$direction = ' dir="rtl"';
|
|
|
|
} else {
|
|
|
|
$direction = ' dir="ltr"';
|
|
|
|
}
|
|
|
|
}
|
2021-10-22 14:15:56 +08:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Accessibility: added the 'lang' attribute to $direction, used in theme <html> tag.
|
2021-10-22 14:15:56 +08:00
|
|
|
$language = get_html_lang_attribute_value($currentlang);
|
2007-03-05 15:38:10 +00:00
|
|
|
@header('Content-Language: '.$language);
|
2007-06-19 14:44:02 +00:00
|
|
|
return ($direction.' lang="'.$language.'" xml:lang="'.$language.'"');
|
2007-02-21 10:42:50 +00:00
|
|
|
}
|
|
|
|
|
2009-06-26 09:06:16 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// STANDARD WEB PAGE PARTS.
|
2009-06-26 09:06:16 +00:00
|
|
|
|
2007-10-22 06:43:00 +00:00
|
|
|
/**
|
2009-06-26 09:06:16 +00:00
|
|
|
* Send the HTTP headers that Moodle requires.
|
2012-11-14 19:42:24 +01:00
|
|
|
*
|
|
|
|
* There is a backwards compatibility hack for legacy code
|
|
|
|
* that needs to add custom IE compatibility directive.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
* <code>
|
|
|
|
* if (!isset($CFG->additionalhtmlhead)) {
|
|
|
|
* $CFG->additionalhtmlhead = '';
|
|
|
|
* }
|
|
|
|
* $CFG->additionalhtmlhead .= '<meta http-equiv="X-UA-Compatible" content="IE=8" />';
|
|
|
|
* header('X-UA-Compatible: IE=8');
|
|
|
|
* echo $OUTPUT->header();
|
|
|
|
* </code>
|
|
|
|
*
|
|
|
|
* Please note the $CFG->additionalhtmlhead alone might not work,
|
|
|
|
* you should send the IE compatibility header() too.
|
|
|
|
*
|
|
|
|
* @param string $contenttype
|
|
|
|
* @param bool $cacheable Can this page be cached on back?
|
|
|
|
* @return void, sends HTTP headers
|
2007-10-22 06:43:00 +00:00
|
|
|
*/
|
2009-06-26 09:06:16 +00:00
|
|
|
function send_headers($contenttype, $cacheable = true) {
|
2011-07-14 22:01:23 +02:00
|
|
|
global $CFG;
|
|
|
|
|
2009-06-26 09:06:16 +00:00
|
|
|
@header('Content-Type: ' . $contenttype);
|
|
|
|
@header('Content-Script-Type: text/javascript');
|
|
|
|
@header('Content-Style-Type: text/css');
|
2012-11-10 11:47:09 +01:00
|
|
|
|
|
|
|
if (empty($CFG->additionalhtmlhead) or stripos($CFG->additionalhtmlhead, 'X-UA-Compatible') === false) {
|
|
|
|
@header('X-UA-Compatible: IE=edge');
|
|
|
|
}
|
2001-11-22 06:23:56 +00:00
|
|
|
|
2009-06-26 09:06:16 +00:00
|
|
|
if ($cacheable) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Allow caching on "back" (but not on normal clicks).
|
2013-12-28 12:00:18 +01:00
|
|
|
@header('Cache-Control: private, pre-check=0, post-check=0, max-age=0, no-transform');
|
2009-06-26 09:06:16 +00:00
|
|
|
@header('Pragma: no-cache');
|
|
|
|
@header('Expires: ');
|
|
|
|
} else {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Do everything we can to always prevent clients and proxies caching.
|
2009-06-26 09:06:16 +00:00
|
|
|
@header('Cache-Control: no-store, no-cache, must-revalidate');
|
2013-12-28 12:00:18 +01:00
|
|
|
@header('Cache-Control: post-check=0, pre-check=0, no-transform', false);
|
2009-06-26 09:06:16 +00:00
|
|
|
@header('Pragma: no-cache');
|
|
|
|
@header('Expires: Mon, 20 Aug 1969 09:23:00 GMT');
|
|
|
|
@header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
|
|
|
}
|
|
|
|
@header('Accept-Ranges: none');
|
2011-07-14 22:01:23 +02:00
|
|
|
|
2019-02-07 17:53:28 +01:00
|
|
|
// The Moodle app must be allowed to embed content always.
|
|
|
|
if (empty($CFG->allowframembedding) && !core_useragent::is_moodle_app()) {
|
2011-07-14 22:01:23 +02:00
|
|
|
@header('X-Frame-Options: sameorigin');
|
|
|
|
}
|
2020-06-03 15:18:19 +10:00
|
|
|
|
|
|
|
// If referrer policy is set, add a referrer header.
|
|
|
|
if (!empty($CFG->referrerpolicy) && ($CFG->referrerpolicy !== 'default')) {
|
|
|
|
@header('Referrer-Policy: ' . $CFG->referrerpolicy);
|
|
|
|
}
|
2009-06-26 09:06:16 +00:00
|
|
|
}
|
2002-12-20 14:44:14 +00:00
|
|
|
|
2007-05-09 14:15:33 +00:00
|
|
|
/**
|
2007-05-14 13:28:21 +00:00
|
|
|
* Return the right arrow with text ('next'), and optionally embedded in a link.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2007-05-22 08:59:56 +00:00
|
|
|
* @param string $text HTML/plain text label (set to blank only for breadcrumb separator cases).
|
2007-05-14 13:28:21 +00:00
|
|
|
* @param string $url An optional link to use in a surrounding HTML anchor.
|
|
|
|
* @param bool $accesshide True if text should be hidden (for screen readers only).
|
|
|
|
* @param string $addclass Additional class names for the link, or the arrow character.
|
|
|
|
* @return string HTML string.
|
2007-05-09 14:15:33 +00:00
|
|
|
*/
|
2017-07-19 09:26:15 +08:00
|
|
|
function link_arrow_right($text, $url='', $accesshide=false, $addclass='', $addparams = []) {
|
2013-08-05 09:06:56 +12:00
|
|
|
global $OUTPUT; // TODO: move to output renderer.
|
2007-05-14 13:28:21 +00:00
|
|
|
$arrowclass = 'arrow ';
|
2013-08-05 09:06:56 +12:00
|
|
|
if (!$url) {
|
2007-05-14 13:28:21 +00:00
|
|
|
$arrowclass .= $addclass;
|
|
|
|
}
|
2023-09-11 13:57:59 +08:00
|
|
|
$arrow = '<span class="'.$arrowclass.'" aria-hidden="true">'.$OUTPUT->rarrow().'</span>';
|
2007-05-14 13:28:21 +00:00
|
|
|
$htmltext = '';
|
|
|
|
if ($text) {
|
2008-05-13 12:36:16 +00:00
|
|
|
$htmltext = '<span class="arrow_text">'.$text.'</span> ';
|
2007-05-14 13:28:21 +00:00
|
|
|
if ($accesshide) {
|
2007-09-25 11:33:30 +00:00
|
|
|
$htmltext = get_accesshide($htmltext);
|
2007-05-14 13:28:21 +00:00
|
|
|
}
|
2007-05-09 14:15:33 +00:00
|
|
|
}
|
2007-05-14 13:28:21 +00:00
|
|
|
if ($url) {
|
2008-05-13 12:36:16 +00:00
|
|
|
$class = 'arrow_link';
|
2007-05-14 13:28:21 +00:00
|
|
|
if ($addclass) {
|
2008-05-13 12:36:16 +00:00
|
|
|
$class .= ' '.$addclass;
|
2007-05-14 13:28:21 +00:00
|
|
|
}
|
2017-07-19 09:26:15 +08:00
|
|
|
|
|
|
|
$linkparams = [
|
|
|
|
'class' => $class,
|
|
|
|
'href' => $url,
|
|
|
|
'title' => preg_replace('/<.*?>/', '', $text),
|
|
|
|
];
|
|
|
|
|
|
|
|
$linkparams += $addparams;
|
|
|
|
|
|
|
|
return html_writer::link($url, $htmltext . $arrow, $linkparams);
|
2007-05-14 13:28:21 +00:00
|
|
|
}
|
|
|
|
return $htmltext.$arrow;
|
2007-05-09 14:15:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-05-14 13:28:21 +00:00
|
|
|
* Return the left arrow with text ('previous'), and optionally embedded in a link.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2007-05-22 08:59:56 +00:00
|
|
|
* @param string $text HTML/plain text label (set to blank only for breadcrumb separator cases).
|
2007-05-14 13:28:21 +00:00
|
|
|
* @param string $url An optional link to use in a surrounding HTML anchor.
|
|
|
|
* @param bool $accesshide True if text should be hidden (for screen readers only).
|
|
|
|
* @param string $addclass Additional class names for the link, or the arrow character.
|
|
|
|
* @return string HTML string.
|
2007-05-09 14:15:33 +00:00
|
|
|
*/
|
2017-07-19 09:26:15 +08:00
|
|
|
function link_arrow_left($text, $url='', $accesshide=false, $addclass='', $addparams = []) {
|
2013-08-05 09:06:56 +12:00
|
|
|
global $OUTPUT; // TODO: move to utput renderer.
|
2007-05-14 13:28:21 +00:00
|
|
|
$arrowclass = 'arrow ';
|
|
|
|
if (! $url) {
|
|
|
|
$arrowclass .= $addclass;
|
|
|
|
}
|
2023-09-11 13:57:59 +08:00
|
|
|
$arrow = '<span class="'.$arrowclass.'" aria-hidden="true">'.$OUTPUT->larrow().'</span>';
|
2007-05-14 13:28:21 +00:00
|
|
|
$htmltext = '';
|
|
|
|
if ($text) {
|
2008-05-13 12:36:16 +00:00
|
|
|
$htmltext = ' <span class="arrow_text">'.$text.'</span>';
|
2007-05-14 13:28:21 +00:00
|
|
|
if ($accesshide) {
|
2007-09-25 11:33:30 +00:00
|
|
|
$htmltext = get_accesshide($htmltext);
|
2007-05-14 13:28:21 +00:00
|
|
|
}
|
2007-05-09 14:15:33 +00:00
|
|
|
}
|
2007-05-14 13:28:21 +00:00
|
|
|
if ($url) {
|
2008-05-13 12:36:16 +00:00
|
|
|
$class = 'arrow_link';
|
2007-05-14 13:28:21 +00:00
|
|
|
if ($addclass) {
|
2008-05-13 12:36:16 +00:00
|
|
|
$class .= ' '.$addclass;
|
2007-05-14 13:28:21 +00:00
|
|
|
}
|
2017-07-19 09:26:15 +08:00
|
|
|
|
|
|
|
$linkparams = [
|
|
|
|
'class' => $class,
|
|
|
|
'href' => $url,
|
|
|
|
'title' => preg_replace('/<.*?>/', '', $text),
|
|
|
|
];
|
|
|
|
|
|
|
|
$linkparams += $addparams;
|
|
|
|
|
|
|
|
return html_writer::link($url, $arrow . $htmltext, $linkparams);
|
2007-05-14 13:28:21 +00:00
|
|
|
}
|
|
|
|
return $arrow.$htmltext;
|
|
|
|
}
|
|
|
|
|
2007-09-25 11:33:30 +00:00
|
|
|
/**
|
|
|
|
* Return a HTML element with the class "accesshide", for accessibility.
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2009-05-22 03:26:07 +00:00
|
|
|
* Please use cautiously - where possible, text should be visible!
|
|
|
|
*
|
2007-09-25 11:33:30 +00:00
|
|
|
* @param string $text Plain text.
|
|
|
|
* @param string $elem Lowercase element name, default "span".
|
|
|
|
* @param string $class Additional classes for the element.
|
|
|
|
* @param string $attrs Additional attributes string in the form, "name='value' name2='value2'"
|
|
|
|
* @return string HTML string.
|
|
|
|
*/
|
|
|
|
function get_accesshide($text, $elem='span', $class='', $attrs='') {
|
|
|
|
return "<$elem class=\"accesshide $class\" $attrs>$text</$elem>";
|
|
|
|
}
|
|
|
|
|
2007-05-14 13:28:21 +00:00
|
|
|
/**
|
|
|
|
* Return the breadcrumb trail navigation separator.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2007-05-14 13:28:21 +00:00
|
|
|
* @return string HTML string.
|
|
|
|
*/
|
|
|
|
function get_separator() {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Accessibility: the 'hidden' slash is preferred for screen readers.
|
2007-05-14 13:28:21 +00:00
|
|
|
return ' '.link_arrow_right($text='/', $url='', $accesshide=true, 'sep').' ';
|
2007-05-09 14:15:33 +00:00
|
|
|
}
|
|
|
|
|
2008-11-03 05:27:10 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Print (or return) a collapsible region, that has a caption that can be clicked to expand or collapse the region.
|
2009-08-04 02:05:32 +00:00
|
|
|
*
|
2010-05-22 20:31:11 +00:00
|
|
|
* If JavaScript is off, then the region will always be expanded.
|
2008-11-03 05:27:10 +00:00
|
|
|
*
|
|
|
|
* @param string $contents the contents of the box.
|
|
|
|
* @param string $classes class names added to the div that is output.
|
|
|
|
* @param string $id id added to the div that is output. Must not be blank.
|
|
|
|
* @param string $caption text displayed at the top. Clicking on this will cause the region to expand or contract.
|
2010-05-22 20:31:11 +00:00
|
|
|
* @param string $userpref the name of the user preference that stores the user's preferred default state.
|
2008-11-03 05:27:10 +00:00
|
|
|
* (May be blank if you do not wish the state to be persisted.
|
2010-05-22 20:31:11 +00:00
|
|
|
* @param boolean $default Initial collapsed state to use if the user_preference it not set.
|
2008-11-03 05:27:10 +00:00
|
|
|
* @param boolean $return if true, return the HTML as a string, rather than printing it.
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return string|void If $return is false, returns nothing, otherwise returns a string of HTML.
|
2008-11-03 05:27:10 +00:00
|
|
|
*/
|
2008-11-03 05:04:23 +00:00
|
|
|
function print_collapsible_region($contents, $classes, $id, $caption, $userpref = '', $default = false, $return = false) {
|
2011-02-13 11:52:09 +01:00
|
|
|
$output = print_collapsible_region_start($classes, $id, $caption, $userpref, $default, true);
|
2008-11-03 05:04:23 +00:00
|
|
|
$output .= $contents;
|
|
|
|
$output .= print_collapsible_region_end(true);
|
|
|
|
|
|
|
|
if ($return) {
|
|
|
|
return $output;
|
|
|
|
} else {
|
|
|
|
echo $output;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-03 05:27:10 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Print (or return) the start of a collapsible region
|
|
|
|
*
|
|
|
|
* The collapsibleregion has a caption that can be clicked to expand or collapse the region. If JavaScript is off, then the region
|
2010-05-22 20:31:11 +00:00
|
|
|
* will always be expanded.
|
2008-11-03 05:27:10 +00:00
|
|
|
*
|
|
|
|
* @param string $classes class names added to the div that is output.
|
|
|
|
* @param string $id id added to the div that is output. Must not be blank.
|
|
|
|
* @param string $caption text displayed at the top. Clicking on this will cause the region to expand or contract.
|
2011-02-13 11:52:09 +01:00
|
|
|
* @param string $userpref the name of the user preference that stores the user's preferred default state.
|
2008-11-03 05:27:10 +00:00
|
|
|
* (May be blank if you do not wish the state to be persisted.
|
2010-05-22 20:31:11 +00:00
|
|
|
* @param boolean $default Initial collapsed state to use if the user_preference it not set.
|
2008-11-03 05:27:10 +00:00
|
|
|
* @param boolean $return if true, return the HTML as a string, rather than printing it.
|
2020-11-09 15:47:14 +07:00
|
|
|
* @param string $extracontent the extra content will show next to caption, eg.Help icon.
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return string|void if $return is false, returns nothing, otherwise returns a string of HTML.
|
2008-11-03 05:27:10 +00:00
|
|
|
*/
|
2020-11-09 15:47:14 +07:00
|
|
|
function print_collapsible_region_start($classes, $id, $caption, $userpref = '', $default = false, $return = false,
|
|
|
|
$extracontent = null) {
|
2013-08-05 09:06:56 +12:00
|
|
|
global $PAGE;
|
2008-11-03 05:04:23 +00:00
|
|
|
|
|
|
|
// Work out the initial state.
|
2011-02-13 11:52:09 +01:00
|
|
|
if (!empty($userpref) and is_string($userpref)) {
|
2008-11-03 05:04:23 +00:00
|
|
|
$collapsed = get_user_preferences($userpref, $default);
|
|
|
|
} else {
|
|
|
|
$collapsed = $default;
|
|
|
|
$userpref = false;
|
|
|
|
}
|
|
|
|
|
2008-11-04 05:12:12 +00:00
|
|
|
if ($collapsed) {
|
|
|
|
$classes .= ' collapsed';
|
|
|
|
}
|
|
|
|
|
2008-11-03 05:04:23 +00:00
|
|
|
$output = '';
|
|
|
|
$output .= '<div id="' . $id . '" class="collapsibleregion ' . $classes . '">';
|
2008-11-04 05:12:12 +00:00
|
|
|
$output .= '<div id="' . $id . '_sizer">';
|
2008-11-03 05:04:23 +00:00
|
|
|
$output .= '<div id="' . $id . '_caption" class="collapsibleregioncaption">';
|
2020-11-09 15:47:14 +07:00
|
|
|
$output .= $caption . ' </div>';
|
|
|
|
if ($extracontent) {
|
|
|
|
$output .= html_writer::div($extracontent, 'collapsibleregionextracontent');
|
|
|
|
}
|
|
|
|
$output .= '<div id="' . $id . '_inner" class="collapsibleregioninner">';
|
2010-01-24 10:34:02 +00:00
|
|
|
$PAGE->requires->js_init_call('M.util.init_collapsible_region', array($id, $userpref, get_string('clicktohideshow')));
|
2008-11-03 05:04:23 +00:00
|
|
|
|
|
|
|
if ($return) {
|
|
|
|
return $output;
|
|
|
|
} else {
|
|
|
|
echo $output;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-03 05:27:10 +00:00
|
|
|
/**
|
|
|
|
* Close a region started with print_collapsible_region_start.
|
|
|
|
*
|
|
|
|
* @param boolean $return if true, return the HTML as a string, rather than printing it.
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return string|void if $return is false, returns nothing, otherwise returns a string of HTML.
|
2008-11-03 05:27:10 +00:00
|
|
|
*/
|
2008-11-03 05:04:23 +00:00
|
|
|
function print_collapsible_region_end($return = false) {
|
2008-11-04 05:12:12 +00:00
|
|
|
$output = '</div></div></div>';
|
2008-11-03 05:04:23 +00:00
|
|
|
|
|
|
|
if ($return) {
|
|
|
|
return $output;
|
|
|
|
} else {
|
|
|
|
echo $output;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
|
|
|
* Print a specified group's avatar.
|
|
|
|
*
|
2010-09-17 20:05:40 +00:00
|
|
|
* @param array|stdClass $group A single {@link group} object OR array of groups.
|
2007-05-09 14:15:33 +00:00
|
|
|
* @param int $courseid The course ID.
|
|
|
|
* @param boolean $large Default small picture, or large.
|
|
|
|
* @param boolean $return If false print picture, otherwise return the output as string
|
|
|
|
* @param boolean $link Enclose image in a link to view specified course?
|
2018-06-03 21:15:35 +08:00
|
|
|
* @param boolean $includetoken Whether to use a user token when displaying this group image.
|
2019-03-22 11:48:12 +01:00
|
|
|
* 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.
|
2018-06-03 21:15:35 +08:00
|
|
|
* 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.
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return string|void Depending on the setting of $return
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2018-06-03 21:15:35 +08:00
|
|
|
function print_group_picture($group, $courseid, $large = false, $return = false, $link = true, $includetoken = false) {
|
2003-12-30 17:18:06 +00:00
|
|
|
global $CFG;
|
|
|
|
|
2006-05-23 19:18:25 +00:00
|
|
|
if (is_array($group)) {
|
|
|
|
$output = '';
|
2013-08-05 09:06:56 +12:00
|
|
|
foreach ($group as $g) {
|
2018-06-03 21:15:35 +08:00
|
|
|
$output .= print_group_picture($g, $courseid, $large, true, $link, $includetoken);
|
2006-05-23 19:18:25 +00:00
|
|
|
}
|
2006-08-10 06:41:38 +00:00
|
|
|
if ($return) {
|
2006-05-23 19:18:25 +00:00
|
|
|
return $output;
|
|
|
|
} else {
|
|
|
|
echo $output;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-03 21:15:35 +08:00
|
|
|
$pictureurl = get_group_picture_url($group, $courseid, $large, $includetoken);
|
2017-10-30 11:00:36 +08:00
|
|
|
|
|
|
|
// If there is no picture, do nothing.
|
|
|
|
if (!isset($pictureurl)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$context = context_course::instance($courseid);
|
|
|
|
|
|
|
|
$groupname = s($group->name);
|
|
|
|
$pictureimage = html_writer::img($pictureurl, $groupname, ['title' => $groupname]);
|
|
|
|
|
|
|
|
$output = '';
|
|
|
|
if ($link or has_capability('moodle/site:accessallgroups', $context)) {
|
|
|
|
$linkurl = new moodle_url('/user/index.php', ['id' => $courseid, 'group' => $group->id]);
|
|
|
|
$output .= html_writer::link($linkurl, $pictureimage);
|
|
|
|
} else {
|
|
|
|
$output .= $pictureimage;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($return) {
|
|
|
|
return $output;
|
|
|
|
} else {
|
|
|
|
echo $output;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the url to the group picture.
|
|
|
|
*
|
|
|
|
* @param stdClass $group A group object.
|
|
|
|
* @param int $courseid The course ID for the group.
|
|
|
|
* @param bool $large A large or small group picture? Default is small.
|
2018-06-03 21:15:35 +08:00
|
|
|
* @param boolean $includetoken Whether to use a user token when displaying this group image.
|
2019-03-22 11:48:12 +01:00
|
|
|
* 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.
|
2018-06-03 21:15:35 +08:00
|
|
|
* 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.
|
2024-02-05 15:20:28 +00:00
|
|
|
* @return ?moodle_url Returns the url for the group picture.
|
2017-10-30 11:00:36 +08:00
|
|
|
*/
|
2018-06-03 21:15:35 +08:00
|
|
|
function get_group_picture_url($group, $courseid, $large = false, $includetoken = false) {
|
2017-10-30 11:00:36 +08:00
|
|
|
global $CFG;
|
|
|
|
|
2012-07-25 16:25:55 +08:00
|
|
|
$context = context_course::instance($courseid);
|
2004-02-15 07:37:48 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// If there is no picture, do nothing.
|
2010-04-23 11:14:10 +00:00
|
|
|
if (!$group->picture) {
|
2017-10-30 11:00:36 +08:00
|
|
|
return;
|
2010-04-23 11:14:10 +00:00
|
|
|
}
|
|
|
|
|
2004-02-15 07:29:55 +00:00
|
|
|
if ($large) {
|
2004-09-22 14:39:15 +00:00
|
|
|
$file = 'f1';
|
2004-02-15 07:29:55 +00:00
|
|
|
} else {
|
2004-09-22 14:39:15 +00:00
|
|
|
$file = 'f2';
|
2004-02-15 07:29:55 +00:00
|
|
|
}
|
2010-04-23 11:14:10 +00:00
|
|
|
|
2018-06-03 21:15:35 +08:00
|
|
|
$grouppictureurl = moodle_url::make_pluginfile_url(
|
|
|
|
$context->id, 'group', 'icon', $group->id, '/', $file, false, $includetoken);
|
2014-11-06 15:23:58 +08:00
|
|
|
$grouppictureurl->param('rev', $group->picture);
|
2017-10-30 11:00:36 +08:00
|
|
|
return $grouppictureurl;
|
2003-12-30 17:18:06 +00:00
|
|
|
}
|
|
|
|
|
2002-12-20 14:44:14 +00:00
|
|
|
|
2009-05-22 03:26:07 +00:00
|
|
|
/**
|
|
|
|
* Display a recent activity note
|
2009-08-04 02:05:32 +00:00
|
|
|
*
|
2009-05-22 03:26:07 +00:00
|
|
|
* @staticvar string $strftimerecent
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param int $time A timestamp int.
|
|
|
|
* @param stdClass $user A user object from the database.
|
2009-05-22 03:26:07 +00:00
|
|
|
* @param string $text Text for display for the note
|
|
|
|
* @param string $link The link to wrap around the text
|
|
|
|
* @param bool $return If set to true the HTML is returned rather than echo'd
|
|
|
|
* @param string $viewfullnames
|
2024-02-05 15:20:28 +00:00
|
|
|
* @return ?string If $retrun was true returns HTML for a recent activity notice.
|
2009-05-22 03:26:07 +00:00
|
|
|
*/
|
2008-01-24 20:33:50 +00:00
|
|
|
function print_recent_activity_note($time, $user, $text, $link, $return=false, $viewfullnames=null) {
|
|
|
|
static $strftimerecent = null;
|
2006-08-10 06:41:38 +00:00
|
|
|
$output = '';
|
|
|
|
|
2008-01-24 20:33:50 +00:00
|
|
|
if (is_null($viewfullnames)) {
|
2012-07-25 16:25:55 +08:00
|
|
|
$context = context_system::instance();
|
2008-01-24 20:33:50 +00:00
|
|
|
$viewfullnames = has_capability('moodle/site:viewfullnames', $context);
|
|
|
|
}
|
2006-09-24 14:35:48 +00:00
|
|
|
|
2008-01-24 20:33:50 +00:00
|
|
|
if (is_null($strftimerecent)) {
|
2005-03-10 13:30:57 +00:00
|
|
|
$strftimerecent = get_string('strftimerecent');
|
|
|
|
}
|
|
|
|
|
2006-08-10 06:41:38 +00:00
|
|
|
$output .= '<div class="head">';
|
2008-01-24 20:33:50 +00:00
|
|
|
$output .= '<div class="date">'.userdate($time, $strftimerecent).'</div>';
|
|
|
|
$output .= '<div class="name">'.fullname($user, $viewfullnames).'</div>';
|
2006-08-10 06:41:38 +00:00
|
|
|
$output .= '</div>';
|
2013-08-05 09:06:56 +12:00
|
|
|
$output .= '<div class="info"><a href="'.$link.'">'.format_string($text, true).'</a></div>';
|
2006-08-10 06:41:38 +00:00
|
|
|
|
|
|
|
if ($return) {
|
|
|
|
return $output;
|
|
|
|
} else {
|
|
|
|
echo $output;
|
|
|
|
}
|
2005-03-10 13:30:57 +00:00
|
|
|
}
|
|
|
|
|
2005-03-29 13:37:08 +00:00
|
|
|
/**
|
2009-05-22 03:26:07 +00:00
|
|
|
* Returns a popup menu with course activity modules
|
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* Given a course this function returns a small popup menu with all the course activity modules in it, as a navigation menu
|
|
|
|
* outputs a simple list structure in XHTML.
|
|
|
|
* The data is taken from the serialised array stored in the course record.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2023-02-28 13:13:42 +00:00
|
|
|
* @param stdClass $course A course object.
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param array $sections
|
|
|
|
* @param course_modinfo $modinfo
|
2009-05-22 03:26:07 +00:00
|
|
|
* @param string $strsection
|
|
|
|
* @param string $strjumpto
|
|
|
|
* @param int $width
|
|
|
|
* @param string $cmid
|
|
|
|
* @return string The HTML block
|
2005-03-29 13:37:08 +00:00
|
|
|
*/
|
2006-10-02 14:57:00 +00:00
|
|
|
function navmenulist($course, $sections, $modinfo, $strsection, $strjumpto, $width=50, $cmid=0) {
|
2005-03-29 13:37:08 +00:00
|
|
|
|
2010-09-16 16:43:29 +00:00
|
|
|
global $CFG, $OUTPUT;
|
2005-03-29 13:37:08 +00:00
|
|
|
|
|
|
|
$section = -1;
|
|
|
|
$menu = array();
|
2008-01-24 20:33:50 +00:00
|
|
|
$doneheading = false;
|
2005-03-29 13:37:08 +00:00
|
|
|
|
2012-11-02 14:32:17 +08:00
|
|
|
$courseformatoptions = course_get_format($course)->get_format_options();
|
2012-07-25 16:25:55 +08:00
|
|
|
$coursecontext = context_course::instance($course->id);
|
2006-10-02 14:57:00 +00:00
|
|
|
|
2005-03-30 12:31:00 +00:00
|
|
|
$menu[] = '<ul class="navmenulist"><li class="jumpto section"><span>'.$strjumpto.'</span><ul>';
|
2008-01-24 20:33:50 +00:00
|
|
|
foreach ($modinfo->cms as $mod) {
|
2011-01-26 10:29:16 +00:00
|
|
|
if (!$mod->has_view()) {
|
|
|
|
// Don't show modules which you can't link to!
|
2005-03-29 13:37:08 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// For course formats using 'numsections' do not show extra sections.
|
2012-11-02 14:32:17 +08:00
|
|
|
if (isset($courseformatoptions['numsections']) && $mod->sectionnum > $courseformatoptions['numsections']) {
|
2005-03-29 13:37:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
if (!$mod->uservisible) { // Do not icnlude empty sections at all.
|
2008-01-24 20:33:50 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-02-01 14:10:49 +00:00
|
|
|
if ($mod->sectionnum >= 0 and $section != $mod->sectionnum) {
|
|
|
|
$thissection = $sections[$mod->sectionnum];
|
2005-03-29 13:37:08 +00:00
|
|
|
|
2012-11-02 14:32:17 +08:00
|
|
|
if ($thissection->visible or
|
|
|
|
(isset($courseformatoptions['hiddensections']) and !$courseformatoptions['hiddensections']) or
|
|
|
|
has_capability('moodle/course:viewhiddensections', $coursecontext)) {
|
2013-08-05 09:06:56 +12:00
|
|
|
$thissection->summary = strip_tags(format_string($thissection->summary, true));
|
2008-01-24 20:33:50 +00:00
|
|
|
if (!$doneheading) {
|
2005-03-29 13:46:20 +00:00
|
|
|
$menu[] = '</ul></li>';
|
2005-03-29 13:37:08 +00:00
|
|
|
}
|
|
|
|
if ($course->format == 'weeks' or empty($thissection->summary)) {
|
2008-02-01 14:10:49 +00:00
|
|
|
$item = $strsection ." ". $mod->sectionnum;
|
2005-03-29 13:37:08 +00:00
|
|
|
} else {
|
2013-08-06 20:58:28 +02:00
|
|
|
if (core_text::strlen($thissection->summary) < ($width-3)) {
|
2005-03-30 11:54:58 +00:00
|
|
|
$item = $thissection->summary;
|
2005-03-29 13:37:08 +00:00
|
|
|
} else {
|
2013-08-06 20:58:28 +02:00
|
|
|
$item = core_text::substr($thissection->summary, 0, $width).'...';
|
2005-03-29 13:37:08 +00:00
|
|
|
}
|
|
|
|
}
|
2005-03-30 12:31:00 +00:00
|
|
|
$menu[] = '<li class="section"><span>'.$item.'</span>';
|
2005-03-29 13:37:08 +00:00
|
|
|
$menu[] = '<ul>';
|
|
|
|
$doneheading = true;
|
2008-01-24 20:33:50 +00:00
|
|
|
|
2008-02-01 14:10:49 +00:00
|
|
|
$section = $mod->sectionnum;
|
2008-01-24 20:33:50 +00:00
|
|
|
} else {
|
2013-08-05 09:06:56 +12:00
|
|
|
// No activities from this hidden section shown.
|
2008-01-24 20:33:50 +00:00
|
|
|
continue;
|
2005-03-29 13:37:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-24 20:33:50 +00:00
|
|
|
$url = $mod->modname .'/view.php?id='. $mod->id;
|
2010-02-14 20:18:10 +00:00
|
|
|
$mod->name = strip_tags(format_string($mod->name ,true));
|
2013-08-06 20:58:28 +02:00
|
|
|
if (core_text::strlen($mod->name) > ($width+5)) {
|
|
|
|
$mod->name = core_text::substr($mod->name, 0, $width).'...';
|
2005-03-29 13:37:08 +00:00
|
|
|
}
|
2008-01-24 20:33:50 +00:00
|
|
|
if (!$mod->visible) {
|
|
|
|
$mod->name = '('.$mod->name.')';
|
|
|
|
}
|
|
|
|
$class = 'activity '.$mod->modname;
|
2009-02-03 07:47:24 +00:00
|
|
|
$class .= ($cmid == $mod->id) ? ' selected' : '';
|
2008-01-24 20:33:50 +00:00
|
|
|
$menu[] = '<li class="'.$class.'">'.
|
2022-03-18 14:00:53 +08:00
|
|
|
$OUTPUT->image_icon('monologo', '', $mod->modname).
|
2008-01-24 20:33:50 +00:00
|
|
|
'<a href="'.$CFG->wwwroot.'/mod/'.$url.'">'.$mod->name.'</a></li>';
|
2005-03-29 13:37:08 +00:00
|
|
|
}
|
2008-01-24 20:33:50 +00:00
|
|
|
|
2005-03-29 13:46:20 +00:00
|
|
|
if ($doneheading) {
|
2005-03-29 13:48:25 +00:00
|
|
|
$menu[] = '</ul></li>';
|
2005-03-29 13:46:20 +00:00
|
|
|
}
|
2005-03-29 21:08:17 +00:00
|
|
|
$menu[] = '</ul></li></ul>';
|
2005-03-29 13:37:08 +00:00
|
|
|
|
|
|
|
return implode("\n", $menu);
|
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Prints a grade menu (as part of an existing form) with help showing all possible numerical grades and scales.
|
2004-09-23 04:36:43 +00:00
|
|
|
*
|
|
|
|
* @todo Finish documenting this function
|
2009-07-27 10:33:00 +00:00
|
|
|
* @todo Deprecate: this is only used in a few contrib modules
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
|
|
|
* @param int $courseid The course ID
|
2009-08-04 02:05:32 +00:00
|
|
|
* @param string $name
|
|
|
|
* @param string $current
|
2009-05-22 03:26:07 +00:00
|
|
|
* @param boolean $includenograde Include those with no grades
|
|
|
|
* @param boolean $return If set to true returns rather than echo's
|
2024-02-05 15:20:28 +00:00
|
|
|
* @return string|bool|null Depending on value of $return
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2006-08-10 06:41:38 +00:00
|
|
|
function print_grade_menu($courseid, $name, $current, $includenograde=true, $return=false) {
|
2013-08-05 09:06:56 +12:00
|
|
|
global $OUTPUT;
|
2003-08-18 05:28:30 +00:00
|
|
|
|
2006-08-10 06:41:38 +00:00
|
|
|
$output = '';
|
2004-09-22 14:39:15 +00:00
|
|
|
$strscale = get_string('scale');
|
|
|
|
$strscales = get_string('scales');
|
2003-08-18 05:28:30 +00:00
|
|
|
|
2003-08-18 11:58:07 +00:00
|
|
|
$scales = get_scales_menu($courseid);
|
2003-08-18 05:28:30 +00:00
|
|
|
foreach ($scales as $i => $scalename) {
|
2004-09-22 14:39:15 +00:00
|
|
|
$grades[-$i] = $strscale .': '. $scalename;
|
2003-08-18 05:28:30 +00:00
|
|
|
}
|
2003-08-25 12:47:36 +00:00
|
|
|
if ($includenograde) {
|
2004-09-22 14:39:15 +00:00
|
|
|
$grades[0] = get_string('nograde');
|
2003-08-25 12:47:36 +00:00
|
|
|
}
|
2003-08-18 05:28:30 +00:00
|
|
|
for ($i=100; $i>=1; $i--) {
|
|
|
|
$grades[$i] = $i;
|
|
|
|
}
|
2010-01-16 18:29:51 +00:00
|
|
|
$output .= html_writer::select($grades, $name, $current, false);
|
2003-08-18 05:28:30 +00:00
|
|
|
|
2017-01-19 16:20:27 +08:00
|
|
|
$linkobject = '<span class="helplink">' . $OUTPUT->pix_icon('help', $strscales) . '</span>';
|
2013-08-05 09:06:56 +12:00
|
|
|
$link = new moodle_url('/course/scales.php', array('id' => $courseid, 'list' => 1));
|
2010-11-24 02:08:30 +00:00
|
|
|
$action = new popup_action('click', $link, 'ratingscales', array('height' => 400, 'width' => 500));
|
2013-08-05 09:06:56 +12:00
|
|
|
$output .= $OUTPUT->action_link($link, $linkobject, $action, array('title' => $strscales));
|
2006-08-10 06:41:38 +00:00
|
|
|
|
|
|
|
if ($return) {
|
|
|
|
return $output;
|
|
|
|
} else {
|
|
|
|
echo $output;
|
|
|
|
}
|
2003-08-18 05:28:30 +00:00
|
|
|
}
|
|
|
|
|
2008-02-27 02:52:28 +00:00
|
|
|
/**
|
|
|
|
* Print an error to STDOUT and exit with a non-zero code. For commandline scripts.
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2008-02-27 02:52:28 +00:00
|
|
|
* Default errorcode is 1.
|
|
|
|
*
|
|
|
|
* Very useful for perl-like error-handling:
|
|
|
|
* do_somethting() or mdie("Something went wrong");
|
|
|
|
*
|
|
|
|
* @param string $msg Error message
|
2008-05-21 14:59:33 +00:00
|
|
|
* @param integer $errorcode Error code to emit
|
2008-02-27 02:52:28 +00:00
|
|
|
*/
|
|
|
|
function mdie($msg='', $errorcode=1) {
|
|
|
|
trigger_error($msg);
|
|
|
|
exit($errorcode);
|
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
|
|
|
* Print a message and exit.
|
|
|
|
*
|
2009-05-22 03:26:07 +00:00
|
|
|
* @param string $message The message to print in the notice
|
2017-04-04 16:14:56 +10:00
|
|
|
* @param moodle_url|string $link The link to use for the continue button
|
2013-08-05 09:06:56 +12:00
|
|
|
* @param object $course A course object. Unused.
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return void This function simply exits
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
function notice ($message, $link='', $course=null) {
|
|
|
|
global $PAGE, $OUTPUT;
|
2002-12-20 14:44:14 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
$message = clean_text($message); // In case nasties are in here.
|
2007-11-23 16:49:51 +00:00
|
|
|
|
2009-01-03 14:28:02 +00:00
|
|
|
if (CLI_SCRIPT) {
|
2009-05-25 17:33:28 +00:00
|
|
|
echo("!!$message!!\n");
|
2013-08-05 09:06:56 +12:00
|
|
|
exit(1); // No success.
|
2007-12-14 21:22:38 +00:00
|
|
|
}
|
|
|
|
|
2009-05-06 08:29:22 +00:00
|
|
|
if (!$PAGE->headerprinted) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Header not yet printed.
|
2009-09-03 06:59:25 +00:00
|
|
|
$PAGE->set_title(get_string('notice'));
|
|
|
|
echo $OUTPUT->header();
|
2007-12-14 21:22:38 +00:00
|
|
|
} else {
|
2009-12-23 18:05:58 +00:00
|
|
|
echo $OUTPUT->container_end_all(false);
|
2007-12-14 21:22:38 +00:00
|
|
|
}
|
2002-12-20 14:44:14 +00:00
|
|
|
|
2009-08-10 04:58:02 +00:00
|
|
|
echo $OUTPUT->box($message, 'generalbox', 'notice');
|
2009-08-18 05:20:12 +00:00
|
|
|
echo $OUTPUT->continue_button($link);
|
2007-01-04 10:23:06 +00:00
|
|
|
|
2009-08-06 14:21:34 +00:00
|
|
|
echo $OUTPUT->footer();
|
2013-08-05 09:06:56 +12:00
|
|
|
exit(1); // General error code.
|
2002-12-20 14:44:14 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Redirects the user to another page, after printing a notice.
|
2004-09-23 04:36:43 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* This function calls the OUTPUT redirect method, echo's the output and then dies to ensure nothing else happens.
|
2009-06-29 07:19:05 +00:00
|
|
|
*
|
|
|
|
* <strong>Good practice:</strong> You should call this method before starting page
|
|
|
|
* output by using any of the OUTPUT methods.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2010-09-17 09:34:05 +00:00
|
|
|
* @param moodle_url|string $url A moodle_url to redirect to. Strings are not to be trusted!
|
2009-06-29 07:19:05 +00:00
|
|
|
* @param string $message The message to display to the user
|
|
|
|
* @param int $delay The delay before redirecting
|
2016-02-16 08:49:42 +08:00
|
|
|
* @param string $messagetype The type of notification to show the message in. See constants on \core\output\notification.
|
2013-08-05 09:06:56 +12:00
|
|
|
* @throws moodle_exception
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2016-02-16 08:52:22 +08:00
|
|
|
function redirect($url, $message='', $delay=null, $messagetype = \core\output\notification::NOTIFY_INFO) {
|
2013-08-05 09:06:56 +12:00
|
|
|
global $OUTPUT, $PAGE, $CFG;
|
2006-01-05 07:08:10 +00:00
|
|
|
|
2010-03-28 09:05:47 +00:00
|
|
|
if (CLI_SCRIPT or AJAX_SCRIPT) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// This is wrong - developers should not use redirect in these scripts but it should not be very likely.
|
2010-03-28 09:05:47 +00:00
|
|
|
throw new moodle_exception('redirecterrordetected', 'error');
|
|
|
|
}
|
|
|
|
|
2016-02-16 08:52:22 +08:00
|
|
|
if ($delay === null) {
|
|
|
|
$delay = -1;
|
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Prevent debug errors - make sure context is properly initialised.
|
2010-09-29 21:09:19 +00:00
|
|
|
if ($PAGE) {
|
|
|
|
$PAGE->set_context(null);
|
2013-08-05 09:06:56 +12:00
|
|
|
$PAGE->set_pagelayout('redirect'); // No header and footer needed.
|
2013-12-30 18:26:24 +08:00
|
|
|
$PAGE->set_title(get_string('pageshouldredirect', 'moodle'));
|
2010-09-29 21:09:19 +00:00
|
|
|
}
|
2010-09-28 22:34:33 +00:00
|
|
|
|
2009-07-15 04:05:05 +00:00
|
|
|
if ($url instanceof moodle_url) {
|
2010-01-17 09:50:55 +00:00
|
|
|
$url = $url->out(false);
|
2009-07-15 04:05:05 +00:00
|
|
|
}
|
|
|
|
|
2010-09-28 22:34:33 +00:00
|
|
|
$debugdisableredirect = false;
|
|
|
|
do {
|
|
|
|
if (defined('DEBUGGING_PRINTED')) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Some debugging already printed, no need to look more.
|
2010-09-28 22:34:33 +00:00
|
|
|
$debugdisableredirect = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-12-18 16:32:52 +08:00
|
|
|
if (core_useragent::is_msword()) {
|
|
|
|
// Clicking a URL from MS Word sends a request to the server without cookies. If that
|
|
|
|
// causes a redirect Word will open a browser pointing the new URL. If not, the URL that
|
|
|
|
// was clicked is opened. Because the request from Word is without cookies, it almost
|
|
|
|
// always results in a redirect to the login page, even if the user is logged in in their
|
|
|
|
// browser. This is not what we want, so prevent the redirect for requests from Word.
|
|
|
|
$debugdisableredirect = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-09-28 22:34:33 +00:00
|
|
|
if (empty($CFG->debugdisplay) or empty($CFG->debug)) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// No errors should be displayed.
|
2010-09-28 22:34:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!function_exists('error_get_last') or !$lasterror = error_get_last()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!($lasterror['type'] & $CFG->debug)) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Last error not interesting.
|
2010-09-28 22:34:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Watch out here, @hidden() errors are returned from error_get_last() too.
|
2010-09-28 22:34:33 +00:00
|
|
|
if (headers_sent()) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// We already started printing something - that means errors likely printed.
|
2010-09-28 22:34:33 +00:00
|
|
|
$debugdisableredirect = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ob_get_level() and ob_get_contents()) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// There is something waiting to be printed, hopefully it is the errors,
|
|
|
|
// but it might be some error hidden by @ too - such as the timezone mess from setup.php.
|
2010-09-28 22:34:33 +00:00
|
|
|
$debugdisableredirect = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (false);
|
2009-07-03 09:03:29 +00:00
|
|
|
|
2011-10-28 19:32:07 +02:00
|
|
|
// Technically, HTTP/1.1 requires Location: header to contain the absolute path.
|
|
|
|
// (In practice browsers accept relative paths - but still, might as well do it properly.)
|
|
|
|
// This code turns relative into absolute.
|
2015-08-21 12:26:08 +08:00
|
|
|
if (!preg_match('|^[a-z]+:|i', $url)) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Get host name http://www.wherever.com.
|
2011-10-28 19:32:07 +02:00
|
|
|
$hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot);
|
|
|
|
if (preg_match('|^/|', $url)) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// URLs beginning with / are relative to web server root so we just add them in.
|
2011-10-28 19:32:07 +02:00
|
|
|
$url = $hostpart.$url;
|
|
|
|
} else {
|
|
|
|
// URLs not beginning with / are relative to path of current script, so add that on.
|
2013-08-05 09:06:56 +12:00
|
|
|
$url = $hostpart.preg_replace('|\?.*$|', '', me()).'/../'.$url;
|
2011-10-28 19:32:07 +02:00
|
|
|
}
|
2013-08-05 09:06:56 +12:00
|
|
|
// Replace all ..s.
|
2011-10-28 19:32:07 +02:00
|
|
|
while (true) {
|
|
|
|
$newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url);
|
|
|
|
if ($newurl == $url) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
$url = $newurl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sanitise url - we can not rely on moodle_url or our URL cleaning
|
2013-08-05 09:06:56 +12:00
|
|
|
// because they do not support all valid external URLs.
|
2011-10-28 19:32:07 +02:00
|
|
|
$url = preg_replace('/[\x00-\x1F\x7F]/', '', $url);
|
|
|
|
$url = str_replace('"', '%22', $url);
|
|
|
|
$encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&", $url);
|
|
|
|
$encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />', FORMAT_HTML));
|
|
|
|
$url = str_replace('&', '&', $encodedurl);
|
|
|
|
|
2009-07-03 09:03:29 +00:00
|
|
|
if (!empty($message)) {
|
2016-02-16 08:49:42 +08:00
|
|
|
if (!$debugdisableredirect && !headers_sent()) {
|
|
|
|
// A message has been provided, and the headers have not yet been sent.
|
|
|
|
// Display the message as a notification on the subsequent page.
|
|
|
|
\core\notification::add($message, $messagetype);
|
|
|
|
$message = null;
|
|
|
|
$delay = 0;
|
|
|
|
} else {
|
|
|
|
if ($delay === -1 || !is_numeric($delay)) {
|
|
|
|
$delay = 3;
|
|
|
|
}
|
|
|
|
$message = clean_text($message);
|
2007-09-12 02:57:08 +00:00
|
|
|
}
|
2009-06-29 07:19:05 +00:00
|
|
|
} else {
|
2009-07-03 09:03:29 +00:00
|
|
|
$message = get_string('pageshouldredirect');
|
2009-06-29 07:19:05 +00:00
|
|
|
$delay = 0;
|
2006-05-16 20:31:22 +00:00
|
|
|
}
|
2005-11-17 06:45:40 +00:00
|
|
|
|
2013-09-08 08:38:52 +02:00
|
|
|
// Make sure the session is closed properly, this prevents problems in IIS
|
|
|
|
// and also some potential PHP shutdown issues.
|
|
|
|
\core\session\manager::write_close();
|
2011-03-13 10:46:41 +01:00
|
|
|
|
2013-09-08 08:38:52 +02:00
|
|
|
if ($delay == 0 && !$debugdisableredirect && !headers_sent()) {
|
2020-09-24 16:30:39 +10:00
|
|
|
|
2019-11-28 22:44:51 +11:00
|
|
|
// This helps when debugging redirect issues like loops and it is not clear
|
2020-09-24 16:30:39 +10:00
|
|
|
// which layer in the stack sent the redirect header. If debugging is on
|
|
|
|
// then the file and line is also shown.
|
|
|
|
$redirectby = 'Moodle';
|
|
|
|
if (debugging('', DEBUG_DEVELOPER)) {
|
|
|
|
$origin = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0];
|
|
|
|
$redirectby .= ' /' . str_replace($CFG->dirroot . '/', '', $origin['file']) . ':' . $origin['line'];
|
|
|
|
}
|
|
|
|
@header("X-Redirect-By: $redirectby");
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// 302 might not work for POST requests, 303 is ignored by obsolete clients.
|
2009-07-03 09:03:29 +00:00
|
|
|
@header($_SERVER['SERVER_PROTOCOL'] . ' 303 See Other');
|
|
|
|
@header('Location: '.$url);
|
2009-07-10 08:44:01 +00:00
|
|
|
echo bootstrap_renderer::plain_redirect_message($encodedurl);
|
|
|
|
exit;
|
2009-07-03 09:03:29 +00:00
|
|
|
}
|
2009-07-01 05:54:26 +00:00
|
|
|
|
2009-07-03 09:03:29 +00:00
|
|
|
// Include a redirect message, even with a HTTP redirect, because that is recommended practice.
|
2011-10-21 16:35:19 +02:00
|
|
|
if ($PAGE) {
|
2013-08-05 09:06:56 +12:00
|
|
|
$CFG->docroot = false; // To prevent the link to moodle docs from being displayed on redirect page.
|
2016-02-16 08:49:42 +08:00
|
|
|
echo $OUTPUT->redirect_message($encodedurl, $message, $delay, $debugdisableredirect, $messagetype);
|
2011-10-21 16:35:19 +02:00
|
|
|
exit;
|
|
|
|
} else {
|
|
|
|
echo bootstrap_renderer::early_redirect_message($encodedurl, $message, $delay);
|
|
|
|
exit;
|
|
|
|
}
|
2002-12-20 14:44:14 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Given an email address, this function will return an obfuscated version of it.
|
2004-09-23 04:36:43 +00:00
|
|
|
*
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param string $email The email address to obfuscate
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return string The obfuscated email address
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2013-08-05 09:06:56 +12:00
|
|
|
function obfuscate_email($email) {
|
2003-07-11 08:38:39 +00:00
|
|
|
$i = 0;
|
|
|
|
$length = strlen($email);
|
2004-09-22 14:39:15 +00:00
|
|
|
$obfuscated = '';
|
2003-07-11 08:38:39 +00:00
|
|
|
while ($i < $length) {
|
2019-10-19 20:52:24 +02:00
|
|
|
if (rand(0, 2) && $email[$i]!='@') { // MDL-20619 some browsers have problems unobfuscating @.
|
|
|
|
$obfuscated.='%'.dechex(ord($email[$i]));
|
2003-07-11 08:38:39 +00:00
|
|
|
} else {
|
2019-10-19 20:52:24 +02:00
|
|
|
$obfuscated.=$email[$i];
|
2003-07-11 08:38:39 +00:00
|
|
|
}
|
|
|
|
$i++;
|
|
|
|
}
|
|
|
|
return $obfuscated;
|
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
|
|
|
* This function takes some text and replaces about half of the characters
|
|
|
|
* with HTML entity equivalents. Return string is obviously longer.
|
|
|
|
*
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param string $plaintext The text to be obfuscated
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return string The obfuscated text
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2003-07-11 08:38:39 +00:00
|
|
|
function obfuscate_text($plaintext) {
|
|
|
|
$i=0;
|
2013-08-06 20:58:28 +02:00
|
|
|
$length = core_text::strlen($plaintext);
|
2004-09-22 14:39:15 +00:00
|
|
|
$obfuscated='';
|
2013-08-05 09:06:56 +12:00
|
|
|
$prevobfuscated = false;
|
2003-07-11 08:38:39 +00:00
|
|
|
while ($i < $length) {
|
2013-08-06 20:58:28 +02:00
|
|
|
$char = core_text::substr($plaintext, $i, 1);
|
|
|
|
$ord = core_text::utf8ord($char);
|
2013-06-07 22:38:48 +02:00
|
|
|
$numerical = ($ord >= ord('0')) && ($ord <= ord('9'));
|
2013-08-05 09:06:56 +12:00
|
|
|
if ($prevobfuscated and $numerical ) {
|
2013-06-07 22:38:48 +02:00
|
|
|
$obfuscated.='&#'.$ord.';';
|
2013-08-05 09:06:56 +12:00
|
|
|
} else if (rand(0, 2)) {
|
2013-06-07 22:38:48 +02:00
|
|
|
$obfuscated.='&#'.$ord.';';
|
2013-08-05 09:06:56 +12:00
|
|
|
$prevobfuscated = true;
|
2003-07-11 08:38:39 +00:00
|
|
|
} else {
|
2013-06-07 22:38:48 +02:00
|
|
|
$obfuscated.=$char;
|
2013-08-05 09:06:56 +12:00
|
|
|
$prevobfuscated = false;
|
2003-07-11 08:38:39 +00:00
|
|
|
}
|
2013-08-05 09:06:56 +12:00
|
|
|
$i++;
|
2003-07-11 08:38:39 +00:00
|
|
|
}
|
|
|
|
return $obfuscated;
|
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
2004-09-25 05:29:21 +00:00
|
|
|
* This function uses the {@link obfuscate_email()} and {@link obfuscate_text()}
|
|
|
|
* to generate a fully obfuscated email link, ready to use.
|
2004-09-23 04:36:43 +00:00
|
|
|
*
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param string $email The email address to display
|
2010-05-22 20:31:11 +00:00
|
|
|
* @param string $label The text to displayed as hyperlink to $email
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param boolean $dimmed If true then use css class 'dimmed' for hyperlink
|
2012-08-15 16:01:09 +08:00
|
|
|
* @param string $subject The subject of the email in the mailto link
|
|
|
|
* @param string $body The content of the email in the mailto link
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return string The obfuscated mailto link
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2012-08-15 16:01:09 +08:00
|
|
|
function obfuscate_mailto($email, $label='', $dimmed=false, $subject = '', $body = '') {
|
2003-07-11 08:38:39 +00:00
|
|
|
|
|
|
|
if (empty($label)) {
|
|
|
|
$label = $email;
|
|
|
|
}
|
2012-08-15 16:01:09 +08:00
|
|
|
|
|
|
|
$label = obfuscate_text($label);
|
|
|
|
$email = obfuscate_email($email);
|
|
|
|
$mailto = obfuscate_text('mailto');
|
|
|
|
$url = new moodle_url("mailto:$email");
|
|
|
|
$attrs = array();
|
|
|
|
|
|
|
|
if (!empty($subject)) {
|
|
|
|
$url->param('subject', format_string($subject));
|
|
|
|
}
|
|
|
|
if (!empty($body)) {
|
|
|
|
$url->param('body', format_string($body));
|
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
// Use the obfuscated mailto.
|
2012-08-15 16:01:09 +08:00
|
|
|
$url = preg_replace('/^mailto/', $mailto, $url->out());
|
|
|
|
|
2004-02-20 10:27:24 +00:00
|
|
|
if ($dimmed) {
|
2012-08-15 16:01:09 +08:00
|
|
|
$attrs['title'] = get_string('emaildisable');
|
|
|
|
$attrs['class'] = 'dimmed';
|
2004-02-20 10:27:24 +00:00
|
|
|
}
|
2012-08-15 16:01:09 +08:00
|
|
|
|
|
|
|
return html_writer::link($url, $label, $attrs);
|
2003-07-11 08:38:39 +00:00
|
|
|
}
|
|
|
|
|
2004-09-23 04:36:43 +00:00
|
|
|
/**
|
|
|
|
* This function is used to rebuild the <nolink> tag because some formats (PLAIN and WIKI)
|
|
|
|
* will transform it to html entities
|
|
|
|
*
|
2004-09-25 05:29:21 +00:00
|
|
|
* @param string $text Text to search for nolink tag in
|
|
|
|
* @return string
|
2004-09-23 04:36:43 +00:00
|
|
|
*/
|
2004-05-11 23:17:25 +00:00
|
|
|
function rebuildnolinktag($text) {
|
2004-05-21 13:07:11 +00:00
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
$text = preg_replace('/<(\/*nolink)>/i', '<$1>', $text);
|
2004-05-11 23:17:25 +00:00
|
|
|
|
|
|
|
return $text;
|
|
|
|
}
|
|
|
|
|
2005-02-10 05:11:34 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Prints a maintenance message from $CFG->maintenance_message or default if empty.
|
2005-02-10 05:11:34 +00:00
|
|
|
*/
|
2009-05-31 14:42:29 +00:00
|
|
|
function print_maintenance_message() {
|
2009-08-06 08:19:21 +00:00
|
|
|
global $CFG, $SITE, $PAGE, $OUTPUT;
|
2005-04-03 12:15:45 +00:00
|
|
|
|
2016-09-14 18:15:21 +10:00
|
|
|
header($_SERVER['SERVER_PROTOCOL'] . ' 503 Moodle under maintenance');
|
|
|
|
header('Status: 503 Moodle under maintenance');
|
|
|
|
header('Retry-After: 300');
|
|
|
|
|
2009-05-06 08:43:51 +00:00
|
|
|
$PAGE->set_pagetype('maintenance-message');
|
2009-12-16 18:00:58 +00:00
|
|
|
$PAGE->set_pagelayout('maintenance');
|
2009-09-03 06:59:25 +00:00
|
|
|
$PAGE->set_heading($SITE->fullname);
|
|
|
|
echo $OUTPUT->header();
|
2009-08-06 08:19:21 +00:00
|
|
|
echo $OUTPUT->heading(get_string('sitemaintenance', 'admin'));
|
2009-05-31 14:42:29 +00:00
|
|
|
if (isset($CFG->maintenance_message) and !html_is_blank($CFG->maintenance_message)) {
|
2009-08-10 04:58:02 +00:00
|
|
|
echo $OUTPUT->box_start('maintenance_message generalbox boxwidthwide boxaligncenter');
|
2009-05-31 14:42:29 +00:00
|
|
|
echo $CFG->maintenance_message;
|
2009-08-10 04:58:02 +00:00
|
|
|
echo $OUTPUT->box_end();
|
2009-05-31 14:42:29 +00:00
|
|
|
}
|
2009-08-06 14:21:34 +00:00
|
|
|
echo $OUTPUT->footer();
|
2009-05-31 14:42:29 +00:00
|
|
|
die;
|
2005-02-10 05:11:34 +00:00
|
|
|
}
|
|
|
|
|
2005-03-15 08:49:14 +00:00
|
|
|
/**
|
2007-01-26 06:28:43 +00:00
|
|
|
* Returns a string containing a nested list, suitable for formatting into tabs with CSS.
|
2005-03-15 08:49:14 +00:00
|
|
|
*
|
2013-04-11 19:06:52 +10:00
|
|
|
* It is not recommended to use this function in Moodle 2.5 but it is left for backward
|
|
|
|
* compartibility.
|
|
|
|
*
|
|
|
|
* Example how to print a single line tabs:
|
|
|
|
* $rows = array(
|
|
|
|
* new tabobject(...),
|
|
|
|
* new tabobject(...)
|
|
|
|
* );
|
|
|
|
* echo $OUTPUT->tabtree($rows, $selectedid);
|
|
|
|
*
|
|
|
|
* Multiple row tabs may not look good on some devices but if you want to use them
|
|
|
|
* you can specify ->subtree for the active tabobject.
|
|
|
|
*
|
2005-03-15 08:49:14 +00:00
|
|
|
* @param array $tabrows An array of rows where each row is an array of tab objects
|
2007-01-26 06:28:43 +00:00
|
|
|
* @param string $selected The id of the selected tab (whatever row it's on)
|
|
|
|
* @param array $inactive An array of ids of inactive tabs that are not selectable.
|
|
|
|
* @param array $activated An array of ids of other tabs that are currently activated
|
2009-05-22 03:26:07 +00:00
|
|
|
* @param bool $return If true output is returned rather then echo'd
|
2013-08-05 09:06:56 +12:00
|
|
|
* @return string HTML output if $return was set to true.
|
|
|
|
*/
|
2013-04-11 19:06:52 +10:00
|
|
|
function print_tabs($tabrows, $selected = null, $inactive = null, $activated = null, $return = false) {
|
|
|
|
global $OUTPUT;
|
2007-01-11 06:54:23 +00:00
|
|
|
|
|
|
|
$tabrows = array_reverse($tabrows);
|
|
|
|
$subtree = array();
|
|
|
|
foreach ($tabrows as $row) {
|
|
|
|
$tree = array();
|
|
|
|
|
|
|
|
foreach ($row as $tab) {
|
2013-04-11 19:06:52 +10:00
|
|
|
$tab->inactive = is_array($inactive) && in_array((string)$tab->id, $inactive);
|
|
|
|
$tab->activated = is_array($activated) && in_array((string)$tab->id, $activated);
|
2007-02-01 07:02:28 +00:00
|
|
|
$tab->selected = (string)$tab->id == $selected;
|
2007-01-11 06:54:23 +00:00
|
|
|
|
2013-04-11 19:06:52 +10:00
|
|
|
if ($tab->activated || $tab->selected) {
|
|
|
|
$tab->subtree = $subtree;
|
2007-01-11 06:54:23 +00:00
|
|
|
}
|
|
|
|
$tree[] = $tab;
|
|
|
|
}
|
|
|
|
$subtree = $tree;
|
2005-03-15 09:47:41 +00:00
|
|
|
}
|
2013-04-11 19:06:52 +10:00
|
|
|
$output = $OUTPUT->tabtree($subtree);
|
|
|
|
if ($return) {
|
|
|
|
return $output;
|
|
|
|
} else {
|
|
|
|
print $output;
|
|
|
|
return !empty($output);
|
|
|
|
}
|
2005-03-15 08:49:14 +00:00
|
|
|
}
|
|
|
|
|
2013-08-10 22:46:49 +02:00
|
|
|
/**
|
|
|
|
* Alter debugging level for the current request,
|
|
|
|
* the change is not saved in database.
|
|
|
|
*
|
|
|
|
* @param int $level one of the DEBUG_* constants
|
|
|
|
* @param bool $debugdisplay
|
|
|
|
*/
|
|
|
|
function set_debugging($level, $debugdisplay = null) {
|
|
|
|
global $CFG;
|
|
|
|
|
|
|
|
$CFG->debug = (int)$level;
|
2013-08-21 13:38:33 +02:00
|
|
|
$CFG->debugdeveloper = (($CFG->debug & DEBUG_DEVELOPER) === DEBUG_DEVELOPER);
|
2013-08-10 22:46:49 +02:00
|
|
|
|
|
|
|
if ($debugdisplay !== null) {
|
|
|
|
$CFG->debugdisplay = (bool)$debugdisplay;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-14 04:25:17 +00:00
|
|
|
/**
|
2009-05-22 03:26:07 +00:00
|
|
|
* Standard Debugging Function
|
|
|
|
*
|
2006-09-23 09:38:39 +00:00
|
|
|
* Returns true if the current site debugging settings are equal or above specified level.
|
2006-12-21 04:03:21 +00:00
|
|
|
* If passed a parameter it will emit a debugging notice similar to trigger_error(). The
|
|
|
|
* routing of notices is controlled by $CFG->debugdisplay
|
2006-09-14 04:25:17 +00:00
|
|
|
* eg use like this:
|
|
|
|
*
|
2006-09-23 09:38:39 +00:00
|
|
|
* 1) debugging('a normal debug notice');
|
|
|
|
* 2) debugging('something really picky', DEBUG_ALL);
|
2010-05-22 20:31:11 +00:00
|
|
|
* 3) debugging('annoying debug message only for developers', DEBUG_DEVELOPER);
|
2006-12-21 04:03:21 +00:00
|
|
|
* 4) if (debugging()) { perform extra debugging operations (do not use print or echo) }
|
|
|
|
*
|
|
|
|
* In code blocks controlled by debugging() (such as example 4)
|
|
|
|
* any output should be routed via debugging() itself, or the lower-level
|
|
|
|
* trigger_error() or error_log(). Using echo or print will break XHTML
|
|
|
|
* JS and HTTP headers.
|
|
|
|
*
|
2009-10-31 22:02:05 +00:00
|
|
|
* It is also possible to define NO_DEBUG_DISPLAY which redirects the message to error_log.
|
2006-09-14 04:25:17 +00:00
|
|
|
*
|
2006-09-14 04:31:05 +00:00
|
|
|
* @param string $message a message to print
|
2006-09-14 04:25:17 +00:00
|
|
|
* @param int $level the level at which this debugging statement should show
|
2008-06-22 16:51:55 +00:00
|
|
|
* @param array $backtrace use different backtrace
|
2006-09-14 04:25:17 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2009-06-26 09:06:16 +00:00
|
|
|
function debugging($message = '', $level = DEBUG_NORMAL, $backtrace = null) {
|
2012-07-21 10:11:50 +02:00
|
|
|
global $CFG, $USER;
|
2006-09-14 04:25:17 +00:00
|
|
|
|
2010-11-11 05:27:34 +00:00
|
|
|
$forcedebug = false;
|
2012-02-26 18:39:40 +08:00
|
|
|
if (!empty($CFG->debugusers) && $USER) {
|
2010-11-11 05:27:34 +00:00
|
|
|
$debugusers = explode(',', $CFG->debugusers);
|
|
|
|
$forcedebug = in_array($USER->id, $debugusers);
|
|
|
|
}
|
|
|
|
|
2012-03-31 23:51:02 +02:00
|
|
|
if (!$forcedebug and (empty($CFG->debug) || ($CFG->debug != -1 and $CFG->debug < $level))) {
|
2006-09-14 04:25:17 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-06-26 09:06:16 +00:00
|
|
|
if (!isset($CFG->debugdisplay)) {
|
|
|
|
$CFG->debugdisplay = ini_get_bool('display_errors');
|
2009-01-31 20:07:32 +00:00
|
|
|
}
|
|
|
|
|
2009-06-26 09:06:16 +00:00
|
|
|
if ($message) {
|
|
|
|
if (!$backtrace) {
|
|
|
|
$backtrace = debug_backtrace();
|
2008-06-13 17:51:34 +00:00
|
|
|
}
|
2014-04-14 13:16:41 +08:00
|
|
|
$from = format_backtrace($backtrace, CLI_SCRIPT || NO_DEBUG_DISPLAY);
|
2012-03-31 23:51:02 +02:00
|
|
|
if (PHPUNIT_TEST) {
|
2012-09-17 10:43:47 +02:00
|
|
|
if (phpunit_util::debugging_triggered($message, $level, $from)) {
|
|
|
|
// We are inside test, the debug message was logged.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2012-03-21 10:31:37 +01:00
|
|
|
|
2012-09-17 10:43:47 +02:00
|
|
|
if (NO_DEBUG_DISPLAY) {
|
2013-08-05 09:06:56 +12:00
|
|
|
// Script does not want any errors or debugging in output,
|
|
|
|
// we send the info to error log instead.
|
2014-04-14 13:16:41 +08:00
|
|
|
error_log('Debugging: ' . $message . ' in '. PHP_EOL . $from);
|
2010-11-11 05:27:34 +00:00
|
|
|
} else if ($forcedebug or $CFG->debugdisplay) {
|
2009-06-26 09:06:16 +00:00
|
|
|
if (!defined('DEBUGGING_PRINTED')) {
|
2013-08-05 09:06:56 +12:00
|
|
|
define('DEBUGGING_PRINTED', 1); // Indicates we have printed something.
|
2008-06-13 17:51:34 +00:00
|
|
|
}
|
2023-11-21 22:49:31 +08:00
|
|
|
|
2010-12-13 20:53:19 +00:00
|
|
|
if (CLI_SCRIPT) {
|
|
|
|
echo "++ $message ++\n$from";
|
|
|
|
} else {
|
2023-11-21 22:49:31 +08:00
|
|
|
if (property_exists($CFG, 'debug_developer_debugging_as_error')) {
|
|
|
|
$showaserror = $CFG->debug_developer_debugging_as_error;
|
|
|
|
} else {
|
|
|
|
$showaserror = (bool) get_whoops();
|
|
|
|
}
|
2009-10-31 22:02:05 +00:00
|
|
|
|
2023-11-21 22:49:31 +08:00
|
|
|
if ($showaserror) {
|
|
|
|
trigger_error($message, E_USER_NOTICE);
|
|
|
|
} else {
|
|
|
|
echo '<div class="notifytiny debuggingmessage" data-rel="debugging">', $message, $from, '</div>';
|
|
|
|
}
|
|
|
|
}
|
2009-06-26 09:06:16 +00:00
|
|
|
} else {
|
|
|
|
trigger_error($message . $from, E_USER_NOTICE);
|
2008-06-13 17:51:34 +00:00
|
|
|
}
|
|
|
|
}
|
2009-06-26 09:06:16 +00:00
|
|
|
return true;
|
2008-06-13 17:51:34 +00:00
|
|
|
}
|
|
|
|
|
2007-03-23 08:01:01 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Outputs a HTML comment to the browser.
|
|
|
|
*
|
|
|
|
* This is used for those hard-to-debug pages that use bits from many different files in very confusing ways (e.g. blocks).
|
|
|
|
*
|
|
|
|
* <code>print_location_comment(__FILE__, __LINE__);</code>
|
|
|
|
*
|
|
|
|
* @param string $file
|
|
|
|
* @param integer $line
|
|
|
|
* @param boolean $return Whether to return or print the comment
|
|
|
|
* @return string|void Void unless true given as third parameter
|
|
|
|
*/
|
|
|
|
function print_location_comment($file, $line, $return = false) {
|
2007-03-23 08:01:01 +00:00
|
|
|
if ($return) {
|
|
|
|
return "<!-- $file at line $line -->\n";
|
|
|
|
} else {
|
|
|
|
echo "<!-- $file at line $line -->\n";
|
|
|
|
}
|
|
|
|
}
|
2007-05-09 15:03:01 +00:00
|
|
|
|
2007-07-04 10:01:20 +00:00
|
|
|
|
2007-08-17 07:25:47 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Returns true if the user is using a right-to-left language.
|
|
|
|
*
|
2009-07-01 05:54:26 +00:00
|
|
|
* @return boolean true if the current language is right-to-left (Hebrew, Arabic etc)
|
2007-08-09 08:40:02 +00:00
|
|
|
*/
|
|
|
|
function right_to_left() {
|
2010-04-10 18:26:20 +00:00
|
|
|
return (get_string('thisdirection', 'langconfig') === 'rtl');
|
2007-08-09 08:40:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Returns swapped left<=> right if in RTL environment.
|
|
|
|
*
|
|
|
|
* Part of RTL Moodles support.
|
2007-08-09 08:40:02 +00:00
|
|
|
*
|
|
|
|
* @param string $align align to check
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function fix_align_rtl($align) {
|
2008-01-13 08:30:39 +00:00
|
|
|
if (!right_to_left()) {
|
2007-08-17 07:25:47 +00:00
|
|
|
return $align;
|
2007-08-09 08:40:02 +00:00
|
|
|
}
|
2013-08-05 09:06:56 +12:00
|
|
|
if ($align == 'left') {
|
|
|
|
return 'right';
|
|
|
|
}
|
|
|
|
if ($align == 'right') {
|
|
|
|
return 'left';
|
|
|
|
}
|
2008-01-13 08:30:39 +00:00
|
|
|
return $align;
|
2007-08-09 08:40:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-10 14:53:54 +00:00
|
|
|
/**
|
|
|
|
* Returns true if the page is displayed in a popup window.
|
2013-08-05 09:06:56 +12:00
|
|
|
*
|
2007-11-10 14:53:54 +00:00
|
|
|
* Gets the information from the URL parameter inpopup.
|
|
|
|
*
|
2010-05-22 20:31:11 +00:00
|
|
|
* @todo Use a central function to create the popup calls all over Moodle and
|
2009-05-22 03:26:07 +00:00
|
|
|
* In the moment only works with resources and probably questions.
|
2007-11-10 14:53:54 +00:00
|
|
|
*
|
2009-05-22 03:26:07 +00:00
|
|
|
* @return boolean
|
2007-11-10 14:53:54 +00:00
|
|
|
*/
|
2007-11-12 11:17:24 +00:00
|
|
|
function is_in_popup() {
|
2007-11-10 14:53:54 +00:00
|
|
|
$inpopup = optional_param('inpopup', '', PARAM_BOOL);
|
2008-01-13 08:30:39 +00:00
|
|
|
|
2007-11-10 14:53:54 +00:00
|
|
|
return ($inpopup);
|
|
|
|
}
|
2009-01-10 20:44:45 +00:00
|
|
|
|
2009-02-12 08:33:42 +00:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Progress trace class.
|
|
|
|
*
|
2009-02-12 08:33:42 +00:00
|
|
|
* Use this class from long operations where you want to output occasional information about
|
|
|
|
* what is going on, but don't know if, or in what format, the output should be.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @copyright 2009 Tim Hunt
|
2009-05-22 03:26:07 +00:00
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2013-08-05 09:06:56 +12:00
|
|
|
* @package core
|
2009-02-12 08:33:42 +00:00
|
|
|
*/
|
2009-12-16 21:35:58 +00:00
|
|
|
abstract class progress_trace {
|
2009-02-12 08:33:42 +00:00
|
|
|
/**
|
2012-12-22 21:18:48 +01:00
|
|
|
* Output an progress message in whatever format.
|
|
|
|
*
|
2009-02-12 08:33:42 +00:00
|
|
|
* @param string $message the message to output.
|
|
|
|
* @param integer $depth indent depth for this message.
|
|
|
|
*/
|
|
|
|
abstract public function output($message, $depth = 0);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when the processing is finished.
|
|
|
|
*/
|
|
|
|
public function finished() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-12-16 21:35:58 +00:00
|
|
|
* This subclass of progress_trace does not ouput anything.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @copyright 2009 Tim Hunt
|
2009-05-22 03:26:07 +00:00
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2013-08-05 09:06:56 +12:00
|
|
|
* @package core
|
2009-02-12 08:33:42 +00:00
|
|
|
*/
|
2009-12-16 21:35:58 +00:00
|
|
|
class null_progress_trace extends progress_trace {
|
2009-05-22 03:26:07 +00:00
|
|
|
/**
|
|
|
|
* Does Nothing
|
|
|
|
*
|
|
|
|
* @param string $message
|
|
|
|
* @param int $depth
|
|
|
|
* @return void Does Nothing
|
|
|
|
*/
|
2009-02-12 08:33:42 +00:00
|
|
|
public function output($message, $depth = 0) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-12-16 21:35:58 +00:00
|
|
|
* This subclass of progress_trace outputs to plain text.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @copyright 2009 Tim Hunt
|
2009-05-22 03:26:07 +00:00
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2013-08-05 09:06:56 +12:00
|
|
|
* @package core
|
2009-02-12 08:33:42 +00:00
|
|
|
*/
|
2009-12-16 21:35:58 +00:00
|
|
|
class text_progress_trace extends progress_trace {
|
2009-05-22 03:26:07 +00:00
|
|
|
/**
|
2012-12-22 21:18:48 +01:00
|
|
|
* Output the trace message.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
|
|
|
* @param string $message
|
|
|
|
* @param int $depth
|
|
|
|
* @return void Output is echo'd
|
|
|
|
*/
|
2009-02-12 08:33:42 +00:00
|
|
|
public function output($message, $depth = 0) {
|
2017-11-06 11:55:29 +00:00
|
|
|
mtrace(str_repeat(' ', $depth) . $message);
|
2009-02-12 08:33:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-12-16 21:35:58 +00:00
|
|
|
* This subclass of progress_trace outputs as HTML.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @copyright 2009 Tim Hunt
|
2009-05-22 03:26:07 +00:00
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2013-08-05 09:06:56 +12:00
|
|
|
* @package core
|
2009-02-12 08:33:42 +00:00
|
|
|
*/
|
2009-12-16 21:35:58 +00:00
|
|
|
class html_progress_trace extends progress_trace {
|
2009-05-22 03:26:07 +00:00
|
|
|
/**
|
2012-12-22 21:18:48 +01:00
|
|
|
* Output the trace message.
|
2009-05-22 03:26:07 +00:00
|
|
|
*
|
|
|
|
* @param string $message
|
|
|
|
* @param int $depth
|
|
|
|
* @return void Output is echo'd
|
|
|
|
*/
|
2009-02-12 08:33:42 +00:00
|
|
|
public function output($message, $depth = 0) {
|
2022-10-28 10:27:37 +02:00
|
|
|
echo '<p>', str_repeat('  ', $depth), htmlspecialchars($message, ENT_COMPAT), "</p>\n";
|
2009-02-12 08:33:42 +00:00
|
|
|
flush();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-22 03:26:07 +00:00
|
|
|
/**
|
|
|
|
* HTML List Progress Tree
|
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @copyright 2009 Tim Hunt
|
2009-05-22 03:26:07 +00:00
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2013-08-05 09:06:56 +12:00
|
|
|
* @package core
|
2009-05-22 03:26:07 +00:00
|
|
|
*/
|
2009-12-16 21:35:58 +00:00
|
|
|
class html_list_progress_trace extends progress_trace {
|
2009-05-22 03:26:07 +00:00
|
|
|
/** @var int */
|
2009-02-12 08:33:42 +00:00
|
|
|
protected $currentdepth = -1;
|
|
|
|
|
2009-05-22 03:26:07 +00:00
|
|
|
/**
|
|
|
|
* Echo out the list
|
|
|
|
*
|
|
|
|
* @param string $message The message to display
|
|
|
|
* @param int $depth
|
|
|
|
* @return void Output is echoed
|
|
|
|
*/
|
2009-02-12 08:33:42 +00:00
|
|
|
public function output($message, $depth = 0) {
|
|
|
|
$samedepth = true;
|
|
|
|
while ($this->currentdepth > $depth) {
|
|
|
|
echo "</li>\n</ul>\n";
|
|
|
|
$this->currentdepth -= 1;
|
|
|
|
if ($this->currentdepth == $depth) {
|
|
|
|
echo '<li>';
|
|
|
|
}
|
|
|
|
$samedepth = false;
|
|
|
|
}
|
|
|
|
while ($this->currentdepth < $depth) {
|
|
|
|
echo "<ul>\n<li>";
|
|
|
|
$this->currentdepth += 1;
|
|
|
|
$samedepth = false;
|
|
|
|
}
|
|
|
|
if ($samedepth) {
|
|
|
|
echo "</li>\n<li>";
|
|
|
|
}
|
2022-10-28 10:27:37 +02:00
|
|
|
echo htmlspecialchars($message, ENT_COMPAT);
|
2009-02-12 08:33:42 +00:00
|
|
|
flush();
|
|
|
|
}
|
|
|
|
|
2009-05-22 03:26:07 +00:00
|
|
|
/**
|
|
|
|
* Called when the processing is finished.
|
|
|
|
*/
|
2009-02-12 08:33:42 +00:00
|
|
|
public function finished() {
|
|
|
|
while ($this->currentdepth >= 0) {
|
|
|
|
echo "</li>\n</ul>\n";
|
|
|
|
$this->currentdepth -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-29 18:02:08 +01:00
|
|
|
/**
|
|
|
|
* This subclass of progress_trace outputs to error log.
|
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @copyright Petr Skoda {@link http://skodak.org}
|
2012-12-29 18:02:08 +01:00
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2013-08-05 09:06:56 +12:00
|
|
|
* @package core
|
2012-12-29 18:02:08 +01:00
|
|
|
*/
|
|
|
|
class error_log_progress_trace extends progress_trace {
|
|
|
|
/** @var string log prefix */
|
|
|
|
protected $prefix;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
* @param string $prefix optional log prefix
|
|
|
|
*/
|
|
|
|
public function __construct($prefix = '') {
|
|
|
|
$this->prefix = $prefix;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Output the trace message.
|
|
|
|
*
|
|
|
|
* @param string $message
|
|
|
|
* @param int $depth
|
|
|
|
* @return void Output is sent to error log.
|
|
|
|
*/
|
|
|
|
public function output($message, $depth = 0) {
|
|
|
|
error_log($this->prefix . str_repeat(' ', $depth) . $message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-22 21:18:48 +01:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Special type of trace that can be used for catching of output of other traces.
|
2012-12-22 21:18:48 +01:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @copyright Petr Skoda {@link http://skodak.org}
|
2012-12-22 21:18:48 +01:00
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2013-08-05 09:06:56 +12:00
|
|
|
* @package core
|
2012-12-22 21:18:48 +01:00
|
|
|
*/
|
|
|
|
class progress_trace_buffer extends progress_trace {
|
2023-02-28 13:13:42 +00:00
|
|
|
/** @var progress_trace */
|
2012-12-22 21:18:48 +01:00
|
|
|
protected $trace;
|
|
|
|
/** @var bool do we pass output out */
|
|
|
|
protected $passthrough;
|
|
|
|
/** @var string output buffer */
|
|
|
|
protected $buffer;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*
|
|
|
|
* @param progress_trace $trace
|
|
|
|
* @param bool $passthrough true means output and buffer, false means just buffer and no output
|
|
|
|
*/
|
|
|
|
public function __construct(progress_trace $trace, $passthrough = true) {
|
|
|
|
$this->trace = $trace;
|
|
|
|
$this->passthrough = $passthrough;
|
|
|
|
$this->buffer = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Output the trace message.
|
|
|
|
*
|
|
|
|
* @param string $message the message to output.
|
|
|
|
* @param int $depth indent depth for this message.
|
|
|
|
* @return void output stored in buffer
|
|
|
|
*/
|
|
|
|
public function output($message, $depth = 0) {
|
|
|
|
ob_start();
|
|
|
|
$this->trace->output($message, $depth);
|
|
|
|
$this->buffer .= ob_get_contents();
|
|
|
|
if ($this->passthrough) {
|
|
|
|
ob_end_flush();
|
|
|
|
} else {
|
|
|
|
ob_end_clean();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when the processing is finished.
|
|
|
|
*/
|
|
|
|
public function finished() {
|
|
|
|
ob_start();
|
|
|
|
$this->trace->finished();
|
|
|
|
$this->buffer .= ob_get_contents();
|
|
|
|
if ($this->passthrough) {
|
|
|
|
ob_end_flush();
|
|
|
|
} else {
|
|
|
|
ob_end_clean();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset internal text buffer.
|
|
|
|
*/
|
|
|
|
public function reset_buffer() {
|
|
|
|
$this->buffer = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return internal text buffer.
|
|
|
|
* @return string buffered plain text
|
|
|
|
*/
|
|
|
|
public function get_buffer() {
|
|
|
|
return $this->buffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-29 18:55:44 +01:00
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Special type of trace that can be used for redirecting to multiple other traces.
|
2012-12-29 18:55:44 +01:00
|
|
|
*
|
2013-08-05 09:06:56 +12:00
|
|
|
* @copyright Petr Skoda {@link http://skodak.org}
|
2012-12-29 18:55:44 +01:00
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2013-08-05 09:06:56 +12:00
|
|
|
* @package core
|
2012-12-29 18:55:44 +01:00
|
|
|
*/
|
|
|
|
class combined_progress_trace extends progress_trace {
|
2013-08-05 09:06:56 +12:00
|
|
|
|
|
|
|
/**
|
|
|
|
* An array of traces.
|
|
|
|
* @var array
|
|
|
|
*/
|
2012-12-29 18:55:44 +01:00
|
|
|
protected $traces;
|
|
|
|
|
|
|
|
/**
|
2013-08-05 09:06:56 +12:00
|
|
|
* Constructs a new instance.
|
|
|
|
*
|
2012-12-29 18:55:44 +01:00
|
|
|
* @param array $traces multiple traces
|
|
|
|
*/
|
|
|
|
public function __construct(array $traces) {
|
|
|
|
$this->traces = $traces;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Output an progress message in whatever format.
|
|
|
|
*
|
|
|
|
* @param string $message the message to output.
|
|
|
|
* @param integer $depth indent depth for this message.
|
|
|
|
*/
|
|
|
|
public function output($message, $depth = 0) {
|
2013-08-05 09:06:56 +12:00
|
|
|
foreach ($this->traces as $trace) {
|
2012-12-29 18:55:44 +01:00
|
|
|
$trace->output($message, $depth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when the processing is finished.
|
|
|
|
*/
|
|
|
|
public function finished() {
|
2013-08-05 09:06:56 +12:00
|
|
|
foreach ($this->traces as $trace) {
|
2012-12-29 18:55:44 +01:00
|
|
|
$trace->finished();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-06 06:49:16 +00:00
|
|
|
/**
|
2010-01-14 20:53:06 +00:00
|
|
|
* Returns a localized sentence in the current language summarizing the current password policy
|
|
|
|
*
|
|
|
|
* @todo this should be handled by a function/method in the language pack library once we have a support for it
|
2010-01-06 06:49:16 +00:00
|
|
|
* @uses $CFG
|
|
|
|
* @return string
|
|
|
|
*/
|
2010-01-14 20:53:06 +00:00
|
|
|
function print_password_policy() {
|
2010-01-06 06:49:16 +00:00
|
|
|
global $CFG;
|
2010-01-14 20:53:06 +00:00
|
|
|
|
|
|
|
$message = '';
|
|
|
|
if (!empty($CFG->passwordpolicy)) {
|
|
|
|
$messages = array();
|
2019-07-30 14:49:42 +10:00
|
|
|
if (!empty($CFG->minpasswordlength)) {
|
|
|
|
$messages[] = get_string('informminpasswordlength', 'auth', $CFG->minpasswordlength);
|
|
|
|
}
|
2010-01-14 20:53:06 +00:00
|
|
|
if (!empty($CFG->minpassworddigits)) {
|
|
|
|
$messages[] = get_string('informminpassworddigits', 'auth', $CFG->minpassworddigits);
|
|
|
|
}
|
|
|
|
if (!empty($CFG->minpasswordlower)) {
|
|
|
|
$messages[] = get_string('informminpasswordlower', 'auth', $CFG->minpasswordlower);
|
|
|
|
}
|
|
|
|
if (!empty($CFG->minpasswordupper)) {
|
|
|
|
$messages[] = get_string('informminpasswordupper', 'auth', $CFG->minpasswordupper);
|
|
|
|
}
|
|
|
|
if (!empty($CFG->minpasswordnonalphanum)) {
|
|
|
|
$messages[] = get_string('informminpasswordnonalphanum', 'auth', $CFG->minpasswordnonalphanum);
|
|
|
|
}
|
|
|
|
|
2019-07-30 12:42:27 +10:00
|
|
|
// Fire any additional password policy functions from plugins.
|
|
|
|
// Callbacks must return an array of message strings.
|
|
|
|
$pluginsfunction = get_plugins_with_function('print_password_policy');
|
|
|
|
foreach ($pluginsfunction as $plugintype => $plugins) {
|
|
|
|
foreach ($plugins as $pluginfunction) {
|
|
|
|
$messages = array_merge($messages, $pluginfunction());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-05 09:06:56 +12:00
|
|
|
$messages = join(', ', $messages); // This is ugly but we do not have anything better yet...
|
2019-07-30 14:49:42 +10:00
|
|
|
// Check if messages is empty before outputting any text.
|
|
|
|
if ($messages != '') {
|
|
|
|
$message = get_string('informpasswordpolicy', 'auth', $messages);
|
|
|
|
}
|
2010-01-14 20:53:06 +00:00
|
|
|
}
|
|
|
|
return $message;
|
2010-01-08 17:20:56 +00:00
|
|
|
}
|
2013-03-16 01:29:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the value of a help string fully prepared for display in the current language.
|
|
|
|
*
|
|
|
|
* @param string $identifier The identifier of the string to search for.
|
|
|
|
* @param string $component The module the string is associated with.
|
|
|
|
* @param boolean $ajax Whether this help is called from an AJAX script.
|
|
|
|
* This is used to influence text formatting and determines
|
|
|
|
* which format to output the doclink in.
|
2014-09-19 00:37:35 -07:00
|
|
|
* @param string|object|array $a An object, string or number that can be used
|
|
|
|
* within translation strings
|
2023-02-28 13:13:42 +00:00
|
|
|
* @return stdClass An object containing:
|
2013-03-16 01:29:05 +00:00
|
|
|
* - heading: Any heading that there may be for this help string.
|
|
|
|
* - text: The wiki-formatted help string.
|
|
|
|
* - doclink: An object containing a link, the linktext, and any additional
|
|
|
|
* CSS classes to apply to that link. Only present if $ajax = false.
|
|
|
|
* - completedoclink: A text representation of the doclink. Only present if $ajax = true.
|
|
|
|
*/
|
2014-09-19 00:37:35 -07:00
|
|
|
function get_formatted_help_string($identifier, $component, $ajax = false, $a = null) {
|
2013-03-16 01:29:05 +00:00
|
|
|
global $CFG, $OUTPUT;
|
|
|
|
$sm = get_string_manager();
|
|
|
|
|
2013-08-04 00:01:58 +02:00
|
|
|
// Do not rebuild caches here!
|
|
|
|
// Devs need to learn to purge all caches after any change or disable $CFG->langstringcache.
|
2013-03-16 01:29:05 +00:00
|
|
|
|
|
|
|
$data = new stdClass();
|
|
|
|
|
|
|
|
if ($sm->string_exists($identifier, $component)) {
|
|
|
|
$data->heading = format_string(get_string($identifier, $component));
|
|
|
|
} else {
|
|
|
|
// Gracefully fall back to an empty string.
|
|
|
|
$data->heading = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($sm->string_exists($identifier . '_help', $component)) {
|
|
|
|
$options = new stdClass();
|
|
|
|
$options->trusted = false;
|
|
|
|
$options->noclean = false;
|
|
|
|
$options->filter = false;
|
|
|
|
$options->para = true;
|
|
|
|
$options->newlines = false;
|
|
|
|
$options->overflowdiv = !$ajax;
|
|
|
|
|
|
|
|
// Should be simple wiki only MDL-21695.
|
2014-09-19 00:37:35 -07:00
|
|
|
$data->text = format_text(get_string($identifier.'_help', $component, $a), FORMAT_MARKDOWN, $options);
|
2013-03-16 01:29:05 +00:00
|
|
|
|
|
|
|
$helplink = $identifier . '_link';
|
2013-08-05 09:06:56 +12:00
|
|
|
if ($sm->string_exists($helplink, $component)) { // Link to further info in Moodle docs.
|
2013-03-16 01:29:05 +00:00
|
|
|
$link = get_string($helplink, $component);
|
|
|
|
$linktext = get_string('morehelp');
|
|
|
|
|
|
|
|
$data->doclink = new stdClass();
|
|
|
|
$url = new moodle_url(get_docs_url($link));
|
|
|
|
if ($ajax) {
|
|
|
|
$data->doclink->link = $url->out();
|
|
|
|
$data->doclink->linktext = $linktext;
|
|
|
|
$data->doclink->class = ($CFG->doctonewwindow) ? 'helplinkpopup' : '';
|
|
|
|
} else {
|
2013-08-05 09:06:56 +12:00
|
|
|
$data->completedoclink = html_writer::tag('div', $OUTPUT->doc_link($link, $linktext),
|
|
|
|
array('class' => 'helpdoclink'));
|
2013-03-16 01:29:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$data->text = html_writer::tag('p',
|
2013-08-05 09:06:56 +12:00
|
|
|
html_writer::tag('strong', 'TODO') . ": missing help string [{$identifier}_help, {$component}]");
|
2013-03-16 01:29:05 +00:00
|
|
|
}
|
|
|
|
return $data;
|
|
|
|
}
|