PageRenderTime 48ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/weblib.php

https://github.com/mylescarrick/moodle
PHP | 3290 lines | 1683 code | 387 blank | 1220 comment | 390 complexity | 82150a642eb2cd0e656ee2ce6389f7fe MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Library of functions for web output
  18. *
  19. * Library of all general-purpose Moodle PHP functions and constants
  20. * that produce HTML output
  21. *
  22. * Other main libraries:
  23. * - datalib.php - functions that access the database.
  24. * - moodlelib.php - general-purpose Moodle functions.
  25. *
  26. * @package core
  27. * @subpackage lib
  28. * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
  29. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30. */
  31. defined('MOODLE_INTERNAL') || die();
  32. /// Constants
  33. /// Define text formatting types ... eventually we can add Wiki, BBcode etc
  34. /**
  35. * Does all sorts of transformations and filtering
  36. */
  37. define('FORMAT_MOODLE', '0'); // Does all sorts of transformations and filtering
  38. /**
  39. * Plain HTML (with some tags stripped)
  40. */
  41. define('FORMAT_HTML', '1'); // Plain HTML (with some tags stripped)
  42. /**
  43. * Plain text (even tags are printed in full)
  44. */
  45. define('FORMAT_PLAIN', '2'); // Plain text (even tags are printed in full)
  46. /**
  47. * Wiki-formatted text
  48. * Deprecated: left here just to note that '3' is not used (at the moment)
  49. * and to catch any latent wiki-like text (which generates an error)
  50. */
  51. define('FORMAT_WIKI', '3'); // Wiki-formatted text
  52. /**
  53. * Markdown-formatted text http://daringfireball.net/projects/markdown/
  54. */
  55. define('FORMAT_MARKDOWN', '4'); // Markdown-formatted text http://daringfireball.net/projects/markdown/
  56. /**
  57. * A moodle_url comparison using this flag will return true if the base URLs match, params are ignored
  58. */
  59. define('URL_MATCH_BASE', 0);
  60. /**
  61. * A moodle_url comparison using this flag will return true if the base URLs match and the params of url1 are part of url2
  62. */
  63. define('URL_MATCH_PARAMS', 1);
  64. /**
  65. * A moodle_url comparison using this flag will return true if the two URLs are identical, except for the order of the params
  66. */
  67. define('URL_MATCH_EXACT', 2);
  68. /**
  69. * Allowed tags - string of html tags that can be tested against for safe html tags
  70. * @global string $ALLOWED_TAGS
  71. * @name $ALLOWED_TAGS
  72. */
  73. global $ALLOWED_TAGS;
  74. $ALLOWED_TAGS =
  75. '<p><br><b><i><u><font><table><tbody><thead><tfoot><span><div><tr><td><th><ol><ul><dl><li><dt><dd><h1><h2><h3><h4><h5><h6><hr><img><a><strong><emphasis><em><sup><sub><address><cite><blockquote><pre><strike><param><acronym><nolink><lang><tex><algebra><math><mi><mn><mo><mtext><mspace><ms><mrow><mfrac><msqrt><mroot><mstyle><merror><mpadded><mphantom><mfenced><msub><msup><msubsup><munder><mover><munderover><mmultiscripts><mtable><mtr><mtd><maligngroup><malignmark><maction><cn><ci><apply><reln><fn><interval><inverse><sep><condition><declare><lambda><compose><ident><quotient><exp><factorial><divide><max><min><minus><plus><power><rem><times><root><gcd><and><or><xor><not><implies><forall><exists><abs><conjugate><eq><neq><gt><lt><geq><leq><ln><log><int><diff><partialdiff><lowlimit><uplimit><bvar><degree><set><list><union><intersect><in><notin><subset><prsubset><notsubset><notprsubset><setdiff><sum><product><limit><tendsto><mean><sdev><variance><median><mode><moment><vector><matrix><matrixrow><determinant><transpose><selector><annotation><semantics><annotation-xml><tt><code>';
  76. /**
  77. * Allowed protocols - array of protocols that are safe to use in links and so on
  78. * @global string $ALLOWED_PROTOCOLS
  79. */
  80. $ALLOWED_PROTOCOLS = array('http', 'https', 'ftp', 'news', 'mailto', 'rtsp', 'teamspeak', 'gopher', 'mms',
  81. 'color', 'callto', 'cursor', 'text-align', 'font-size', 'font-weight', 'font-style', 'font-family',
  82. 'border', 'border-bottom', 'border-left', 'border-top', 'border-right', 'margin', 'margin-bottom', 'margin-left', 'margin-top', 'margin-right',
  83. 'padding', 'padding-bottom', 'padding-left', 'padding-top', 'padding-right', 'vertical-align',
  84. 'background', 'background-color', 'text-decoration'); // CSS as well to get through kses
  85. /// Functions
  86. /**
  87. * Add quotes to HTML characters
  88. *
  89. * Returns $var with HTML characters (like "<", ">", etc.) properly quoted.
  90. * This function is very similar to {@link p()}
  91. *
  92. * @todo Remove obsolete param $obsolete if not used anywhere
  93. *
  94. * @param string $var the string potentially containing HTML characters
  95. * @param boolean $obsolete no longer used.
  96. * @return string
  97. */
  98. function s($var, $obsolete = false) {
  99. if ($var === '0' or $var === false or $var === 0) {
  100. return '0';
  101. }
  102. return preg_replace("/&amp;#(\d+|x[0-7a-fA-F]+);/i", "&#$1;", htmlspecialchars($var, ENT_QUOTES, 'UTF-8', true));
  103. }
  104. /**
  105. * Add quotes to HTML characters
  106. *
  107. * Prints $var with HTML characters (like "<", ">", etc.) properly quoted.
  108. * This function simply calls {@link s()}
  109. * @see s()
  110. *
  111. * @todo Remove obsolete param $obsolete if not used anywhere
  112. *
  113. * @param string $var the string potentially containing HTML characters
  114. * @param boolean $obsolete no longer used.
  115. * @return string
  116. */
  117. function p($var, $obsolete = false) {
  118. echo s($var, $obsolete);
  119. }
  120. /**
  121. * Does proper javascript quoting.
  122. *
  123. * Do not use addslashes anymore, because it does not work when magic_quotes_sybase is enabled.
  124. *
  125. * @param mixed $var String, Array, or Object to add slashes to
  126. * @return mixed quoted result
  127. */
  128. function addslashes_js($var) {
  129. if (is_string($var)) {
  130. $var = str_replace('\\', '\\\\', $var);
  131. $var = str_replace(array('\'', '"', "\n", "\r", "\0"), array('\\\'', '\\"', '\\n', '\\r', '\\0'), $var);
  132. $var = str_replace('</', '<\/', $var); // XHTML compliance
  133. } else if (is_array($var)) {
  134. $var = array_map('addslashes_js', $var);
  135. } else if (is_object($var)) {
  136. $a = get_object_vars($var);
  137. foreach ($a as $key=>$value) {
  138. $a[$key] = addslashes_js($value);
  139. }
  140. $var = (object)$a;
  141. }
  142. return $var;
  143. }
  144. /**
  145. * Remove query string from url
  146. *
  147. * Takes in a URL and returns it without the querystring portion
  148. *
  149. * @param string $url the url which may have a query string attached
  150. * @return string The remaining URL
  151. */
  152. function strip_querystring($url) {
  153. if ($commapos = strpos($url, '?')) {
  154. return substr($url, 0, $commapos);
  155. } else {
  156. return $url;
  157. }
  158. }
  159. /**
  160. * Returns the URL of the HTTP_REFERER, less the querystring portion if required
  161. *
  162. * @uses $_SERVER
  163. * @param boolean $stripquery if true, also removes the query part of the url.
  164. * @return string The resulting referer or empty string
  165. */
  166. function get_referer($stripquery=true) {
  167. if (isset($_SERVER['HTTP_REFERER'])) {
  168. if ($stripquery) {
  169. return strip_querystring($_SERVER['HTTP_REFERER']);
  170. } else {
  171. return $_SERVER['HTTP_REFERER'];
  172. }
  173. } else {
  174. return '';
  175. }
  176. }
  177. /**
  178. * Returns the name of the current script, WITH the querystring portion.
  179. *
  180. * This function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
  181. * return different things depending on a lot of things like your OS, Web
  182. * server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.)
  183. * <b>NOTE:</b> This function returns false if the global variables needed are not set.
  184. *
  185. * @global string
  186. * @return mixed String, or false if the global variables needed are not set
  187. */
  188. function me() {
  189. global $ME;
  190. return $ME;
  191. }
  192. /**
  193. * Returns the name of the current script, WITH the full URL.
  194. *
  195. * This function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
  196. * return different things depending on a lot of things like your OS, Web
  197. * server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.
  198. * <b>NOTE:</b> This function returns false if the global variables needed are not set.
  199. *
  200. * Like {@link me()} but returns a full URL
  201. * @see me()
  202. *
  203. * @global string
  204. * @return mixed String, or false if the global variables needed are not set
  205. */
  206. function qualified_me() {
  207. global $FULLME;
  208. return $FULLME;
  209. }
  210. /**
  211. * Class for creating and manipulating urls.
  212. *
  213. * It can be used in moodle pages where config.php has been included without any further includes.
  214. *
  215. * It is useful for manipulating urls with long lists of params.
  216. * One situation where it will be useful is a page which links to itself to perform various actions
  217. * and / or to process form data. A moodle_url object :
  218. * can be created for a page to refer to itself with all the proper get params being passed from page call to
  219. * page call and methods can be used to output a url including all the params, optionally adding and overriding
  220. * params and can also be used to
  221. * - output the url without any get params
  222. * - and output the params as hidden fields to be output within a form
  223. *
  224. * @link http://docs.moodle.org/en/Development:lib/weblib.php_moodle_url See short write up here
  225. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  226. * @package moodlecore
  227. */
  228. class moodle_url {
  229. /**
  230. * Scheme, ex.: http, https
  231. * @var string
  232. */
  233. protected $scheme = '';
  234. /**
  235. * hostname
  236. * @var string
  237. */
  238. protected $host = '';
  239. /**
  240. * Port number, empty means default 80 or 443 in case of http
  241. * @var unknown_type
  242. */
  243. protected $port = '';
  244. /**
  245. * Username for http auth
  246. * @var string
  247. */
  248. protected $user = '';
  249. /**
  250. * Password for http auth
  251. * @var string
  252. */
  253. protected $pass = '';
  254. /**
  255. * Script path
  256. * @var string
  257. */
  258. protected $path = '';
  259. /**
  260. * Optional slash argument value
  261. * @var string
  262. */
  263. protected $slashargument = '';
  264. /**
  265. * Anchor, may be also empty, null means none
  266. * @var string
  267. */
  268. protected $anchor = null;
  269. /**
  270. * Url parameters as associative array
  271. * @var array
  272. */
  273. protected $params = array(); // Associative array of query string params
  274. /**
  275. * Create new instance of moodle_url.
  276. *
  277. * @param moodle_url|string $url - moodle_url means make a copy of another
  278. * moodle_url and change parameters, string means full url or shortened
  279. * form (ex.: '/course/view.php'). It is strongly encouraged to not include
  280. * query string because it may result in double encoded values. Use the
  281. * $params instead. For admin URLs, just use /admin/script.php, this
  282. * class takes care of the $CFG->admin issue.
  283. * @param array $params these params override current params or add new
  284. */
  285. public function __construct($url, array $params = null) {
  286. global $CFG;
  287. if ($url instanceof moodle_url) {
  288. $this->scheme = $url->scheme;
  289. $this->host = $url->host;
  290. $this->port = $url->port;
  291. $this->user = $url->user;
  292. $this->pass = $url->pass;
  293. $this->path = $url->path;
  294. $this->slashargument = $url->slashargument;
  295. $this->params = $url->params;
  296. $this->anchor = $url->anchor;
  297. } else {
  298. // detect if anchor used
  299. $apos = strpos($url, '#');
  300. if ($apos !== false) {
  301. $anchor = substr($url, $apos);
  302. $anchor = ltrim($anchor, '#');
  303. $this->set_anchor($anchor);
  304. $url = substr($url, 0, $apos);
  305. }
  306. // normalise shortened form of our url ex.: '/course/view.php'
  307. if (strpos($url, '/') === 0) {
  308. // we must not use httpswwwroot here, because it might be url of other page,
  309. // devs have to use httpswwwroot explicitly when creating new moodle_url
  310. $url = $CFG->wwwroot.$url;
  311. }
  312. // now fix the admin links if needed, no need to mess with httpswwwroot
  313. if ($CFG->admin !== 'admin') {
  314. if (strpos($url, "$CFG->wwwroot/admin/") === 0) {
  315. $url = str_replace("$CFG->wwwroot/admin/", "$CFG->wwwroot/$CFG->admin/", $url);
  316. }
  317. }
  318. // parse the $url
  319. $parts = parse_url($url);
  320. if ($parts === false) {
  321. throw new moodle_exception('invalidurl');
  322. }
  323. if (isset($parts['query'])) {
  324. // note: the values may not be correctly decoded,
  325. // url parameters should be always passed as array
  326. parse_str(str_replace('&amp;', '&', $parts['query']), $this->params);
  327. }
  328. unset($parts['query']);
  329. foreach ($parts as $key => $value) {
  330. $this->$key = $value;
  331. }
  332. // detect slashargument value from path - we do not support directory names ending with .php
  333. $pos = strpos($this->path, '.php/');
  334. if ($pos !== false) {
  335. $this->slashargument = substr($this->path, $pos + 4);
  336. $this->path = substr($this->path, 0, $pos + 4);
  337. }
  338. }
  339. $this->params($params);
  340. }
  341. /**
  342. * Add an array of params to the params for this url.
  343. *
  344. * The added params override existing ones if they have the same name.
  345. *
  346. * @param array $params Defaults to null. If null then returns all params.
  347. * @return array Array of Params for url.
  348. */
  349. public function params(array $params = null) {
  350. $params = (array)$params;
  351. foreach ($params as $key=>$value) {
  352. if (is_int($key)) {
  353. throw new coding_exception('Url parameters can not have numeric keys!');
  354. }
  355. if (!is_string($value)) {
  356. if (is_array($value)) {
  357. throw new coding_exception('Url parameters values can not be arrays!');
  358. }
  359. if (is_object($value) and !method_exists($value, '__toString')) {
  360. throw new coding_exception('Url parameters values can not be objects, unless __toString() is defined!');
  361. }
  362. }
  363. $this->params[$key] = (string)$value;
  364. }
  365. return $this->params;
  366. }
  367. /**
  368. * Remove all params if no arguments passed.
  369. * Remove selected params if arguments are passed.
  370. *
  371. * Can be called as either remove_params('param1', 'param2')
  372. * or remove_params(array('param1', 'param2')).
  373. *
  374. * @param mixed $params either an array of param names, or a string param name,
  375. * @param string $params,... any number of additional param names.
  376. * @return array url parameters
  377. */
  378. public function remove_params($params = null) {
  379. if (!is_array($params)) {
  380. $params = func_get_args();
  381. }
  382. foreach ($params as $param) {
  383. unset($this->params[$param]);
  384. }
  385. return $this->params;
  386. }
  387. /**
  388. * Remove all url parameters
  389. * @param $params
  390. * @return void
  391. */
  392. public function remove_all_params($params = null) {
  393. $this->params = array();
  394. $this->slashargument = '';
  395. }
  396. /**
  397. * Add a param to the params for this url.
  398. *
  399. * The added param overrides existing one if they have the same name.
  400. *
  401. * @param string $paramname name
  402. * @param string $newvalue Param value. If new value specified current value is overriden or parameter is added
  403. * @return mixed string parameter value, null if parameter does not exist
  404. */
  405. public function param($paramname, $newvalue = '') {
  406. if (func_num_args() > 1) {
  407. // set new value
  408. $this->params(array($paramname=>$newvalue));
  409. }
  410. if (isset($this->params[$paramname])) {
  411. return $this->params[$paramname];
  412. } else {
  413. return null;
  414. }
  415. }
  416. /**
  417. * Merges parameters and validates them
  418. * @param array $overrideparams
  419. * @return array merged parameters
  420. */
  421. protected function merge_overrideparams(array $overrideparams = null) {
  422. $overrideparams = (array)$overrideparams;
  423. $params = $this->params;
  424. foreach ($overrideparams as $key=>$value) {
  425. if (is_int($key)) {
  426. throw new coding_exception('Overridden parameters can not have numeric keys!');
  427. }
  428. if (is_array($value)) {
  429. throw new coding_exception('Overridden parameters values can not be arrays!');
  430. }
  431. if (is_object($value) and !method_exists($value, '__toString')) {
  432. throw new coding_exception('Overridden parameters values can not be objects, unless __toString() is defined!');
  433. }
  434. $params[$key] = (string)$value;
  435. }
  436. return $params;
  437. }
  438. /**
  439. * Get the params as as a query string.
  440. * This method should not be used outside of this method.
  441. *
  442. * @param boolean $escaped Use &amp; as params separator instead of plain &
  443. * @param array $overrideparams params to add to the output params, these
  444. * override existing ones with the same name.
  445. * @return string query string that can be added to a url.
  446. */
  447. public function get_query_string($escaped = true, array $overrideparams = null) {
  448. $arr = array();
  449. if ($overrideparams !== null) {
  450. $params = $this->merge_overrideparams($overrideparams);
  451. } else {
  452. $params = $this->params;
  453. }
  454. foreach ($params as $key => $val) {
  455. $arr[] = rawurlencode($key)."=".rawurlencode($val);
  456. }
  457. if ($escaped) {
  458. return implode('&amp;', $arr);
  459. } else {
  460. return implode('&', $arr);
  461. }
  462. }
  463. /**
  464. * Shortcut for printing of encoded URL.
  465. * @return string
  466. */
  467. public function __toString() {
  468. return $this->out(true);
  469. }
  470. /**
  471. * Output url
  472. *
  473. * If you use the returned URL in HTML code, you want the escaped ampersands. If you use
  474. * the returned URL in HTTP headers, you want $escaped=false.
  475. *
  476. * @param boolean $escaped Use &amp; as params separator instead of plain &
  477. * @param array $overrideparams params to add to the output url, these override existing ones with the same name.
  478. * @return string Resulting URL
  479. */
  480. public function out($escaped = true, array $overrideparams = null) {
  481. if (!is_bool($escaped)) {
  482. debugging('Escape parameter must be of type boolean, '.gettype($escaped).' given instead.');
  483. }
  484. $uri = $this->out_omit_querystring().$this->slashargument;
  485. $querystring = $this->get_query_string($escaped, $overrideparams);
  486. if ($querystring !== '') {
  487. $uri .= '?' . $querystring;
  488. }
  489. if (!is_null($this->anchor)) {
  490. $uri .= '#'.$this->anchor;
  491. }
  492. return $uri;
  493. }
  494. /**
  495. * Returns url without parameters, everything before '?'.
  496. * @return string
  497. */
  498. public function out_omit_querystring() {
  499. $uri = $this->scheme ? $this->scheme.':'.((strtolower($this->scheme) == 'mailto') ? '':'//'): '';
  500. $uri .= $this->user ? $this->user.($this->pass? ':'.$this->pass:'').'@':'';
  501. $uri .= $this->host ? $this->host : '';
  502. $uri .= $this->port ? ':'.$this->port : '';
  503. $uri .= $this->path ? $this->path : '';
  504. return $uri;
  505. }
  506. /**
  507. * Compares this moodle_url with another
  508. * See documentation of constants for an explanation of the comparison flags.
  509. * @param moodle_url $url The moodle_url object to compare
  510. * @param int $matchtype The type of comparison (URL_MATCH_BASE, URL_MATCH_PARAMS, URL_MATCH_EXACT)
  511. * @return boolean
  512. */
  513. public function compare(moodle_url $url, $matchtype = URL_MATCH_EXACT) {
  514. $baseself = $this->out_omit_querystring();
  515. $baseother = $url->out_omit_querystring();
  516. // Append index.php if there is no specific file
  517. if (substr($baseself,-1)=='/') {
  518. $baseself .= 'index.php';
  519. }
  520. if (substr($baseother,-1)=='/') {
  521. $baseother .= 'index.php';
  522. }
  523. // Compare the two base URLs
  524. if ($baseself != $baseother) {
  525. return false;
  526. }
  527. if ($matchtype == URL_MATCH_BASE) {
  528. return true;
  529. }
  530. $urlparams = $url->params();
  531. foreach ($this->params() as $param => $value) {
  532. if ($param == 'sesskey') {
  533. continue;
  534. }
  535. if (!array_key_exists($param, $urlparams) || $urlparams[$param] != $value) {
  536. return false;
  537. }
  538. }
  539. if ($matchtype == URL_MATCH_PARAMS) {
  540. return true;
  541. }
  542. foreach ($urlparams as $param => $value) {
  543. if ($param == 'sesskey') {
  544. continue;
  545. }
  546. if (!array_key_exists($param, $this->params()) || $this->param($param) != $value) {
  547. return false;
  548. }
  549. }
  550. return true;
  551. }
  552. /**
  553. * Sets the anchor for the URI (the bit after the hash)
  554. * @param string $anchor null means remove previous
  555. */
  556. public function set_anchor($anchor) {
  557. if (is_null($anchor)) {
  558. // remove
  559. $this->anchor = null;
  560. } else if ($anchor === '') {
  561. // special case, used as empty link
  562. $this->anchor = '';
  563. } else if (preg_match('|[a-zA-Z\_\:][a-zA-Z0-9\_\-\.\:]*|', $anchor)) {
  564. // Match the anchor against the NMTOKEN spec
  565. $this->anchor = $anchor;
  566. } else {
  567. // bad luck, no valid anchor found
  568. $this->anchor = null;
  569. }
  570. }
  571. /**
  572. * Sets the url slashargument value
  573. * @param string $path usually file path
  574. * @param string $parameter name of page parameter if slasharguments not supported
  575. * @param bool $supported usually null, then it depends on $CFG->slasharguments, use true or false for other servers
  576. * @return void
  577. */
  578. public function set_slashargument($path, $parameter = 'file', $supported = NULL) {
  579. global $CFG;
  580. if (is_null($supported)) {
  581. $supported = $CFG->slasharguments;
  582. }
  583. if ($supported) {
  584. $parts = explode('/', $path);
  585. $parts = array_map('rawurlencode', $parts);
  586. $path = implode('/', $parts);
  587. $this->slashargument = $path;
  588. unset($this->params[$parameter]);
  589. } else {
  590. $this->slashargument = '';
  591. $this->params[$parameter] = $path;
  592. }
  593. }
  594. // == static factory methods ==
  595. /**
  596. * General moodle file url.
  597. * @param string $urlbase the script serving the file
  598. * @param string $path
  599. * @param bool $forcedownload
  600. * @return moodle_url
  601. */
  602. public static function make_file_url($urlbase, $path, $forcedownload = false) {
  603. global $CFG;
  604. $params = array();
  605. if ($forcedownload) {
  606. $params['forcedownload'] = 1;
  607. }
  608. $url = new moodle_url($urlbase, $params);
  609. $url->set_slashargument($path);
  610. return $url;
  611. }
  612. /**
  613. * Factory method for creation of url pointing to plugin file.
  614. * Please note this method can be used only from the plugins to
  615. * create urls of own files, it must not be used outside of plugins!
  616. * @param int $contextid
  617. * @param string $component
  618. * @param string $area
  619. * @param int $itemid
  620. * @param string $pathname
  621. * @param string $filename
  622. * @param bool $forcedownload
  623. * @return moodle_url
  624. */
  625. public static function make_pluginfile_url($contextid, $component, $area, $itemid, $pathname, $filename, $forcedownload = false) {
  626. global $CFG;
  627. $urlbase = "$CFG->httpswwwroot/pluginfile.php";
  628. if ($itemid === NULL) {
  629. return self::make_file_url($urlbase, "/$contextid/$component/$area".$pathname.$filename, $forcedownload);
  630. } else {
  631. return self::make_file_url($urlbase, "/$contextid/$component/$area/$itemid".$pathname.$filename, $forcedownload);
  632. }
  633. }
  634. /**
  635. * Factory method for creation of url pointing to draft
  636. * file of current user.
  637. * @param int $draftid draft item id
  638. * @param string $pathname
  639. * @param string $filename
  640. * @param bool $forcedownload
  641. * @return moodle_url
  642. */
  643. public static function make_draftfile_url($draftid, $pathname, $filename, $forcedownload = false) {
  644. global $CFG, $USER;
  645. $urlbase = "$CFG->httpswwwroot/draftfile.php";
  646. $context = get_context_instance(CONTEXT_USER, $USER->id);
  647. return self::make_file_url($urlbase, "/$context->id/user/draft/$draftid".$pathname.$filename, $forcedownload);
  648. }
  649. /**
  650. * Factory method for creating of links to legacy
  651. * course files.
  652. * @param int $courseid
  653. * @param string $filepath
  654. * @param bool $forcedownload
  655. * @return moodle_url
  656. */
  657. public static function make_legacyfile_url($courseid, $filepath, $forcedownload = false) {
  658. global $CFG;
  659. $urlbase = "$CFG->wwwroot/file.php";
  660. return self::make_file_url($urlbase, '/'.$courseid.'/'.$filepath, $forcedownload);
  661. }
  662. }
  663. /**
  664. * Determine if there is data waiting to be processed from a form
  665. *
  666. * Used on most forms in Moodle to check for data
  667. * Returns the data as an object, if it's found.
  668. * This object can be used in foreach loops without
  669. * casting because it's cast to (array) automatically
  670. *
  671. * Checks that submitted POST data exists and returns it as object.
  672. *
  673. * @uses $_POST
  674. * @return mixed false or object
  675. */
  676. function data_submitted() {
  677. if (empty($_POST)) {
  678. return false;
  679. } else {
  680. return (object)$_POST;
  681. }
  682. }
  683. /**
  684. * Given some normal text this function will break up any
  685. * long words to a given size by inserting the given character
  686. *
  687. * It's multibyte savvy and doesn't change anything inside html tags.
  688. *
  689. * @param string $string the string to be modified
  690. * @param int $maxsize maximum length of the string to be returned
  691. * @param string $cutchar the string used to represent word breaks
  692. * @return string
  693. */
  694. function break_up_long_words($string, $maxsize=20, $cutchar=' ') {
  695. /// Loading the textlib singleton instance. We are going to need it.
  696. $textlib = textlib_get_instance();
  697. /// First of all, save all the tags inside the text to skip them
  698. $tags = array();
  699. filter_save_tags($string,$tags);
  700. /// Process the string adding the cut when necessary
  701. $output = '';
  702. $length = $textlib->strlen($string);
  703. $wordlength = 0;
  704. for ($i=0; $i<$length; $i++) {
  705. $char = $textlib->substr($string, $i, 1);
  706. if ($char == ' ' or $char == "\t" or $char == "\n" or $char == "\r" or $char == "<" or $char == ">") {
  707. $wordlength = 0;
  708. } else {
  709. $wordlength++;
  710. if ($wordlength > $maxsize) {
  711. $output .= $cutchar;
  712. $wordlength = 0;
  713. }
  714. }
  715. $output .= $char;
  716. }
  717. /// Finally load the tags back again
  718. if (!empty($tags)) {
  719. $output = str_replace(array_keys($tags), $tags, $output);
  720. }
  721. return $output;
  722. }
  723. /**
  724. * Try and close the current window using JavaScript, either immediately, or after a delay.
  725. *
  726. * Echo's out the resulting XHTML & javascript
  727. *
  728. * @global object
  729. * @global object
  730. * @param integer $delay a delay in seconds before closing the window. Default 0.
  731. * @param boolean $reloadopener if true, we will see if this window was a pop-up, and try
  732. * to reload the parent window before this one closes.
  733. */
  734. function close_window($delay = 0, $reloadopener = false) {
  735. global $PAGE, $OUTPUT;
  736. if (!$PAGE->headerprinted) {
  737. $PAGE->set_title(get_string('closewindow'));
  738. echo $OUTPUT->header();
  739. } else {
  740. $OUTPUT->container_end_all(false);
  741. }
  742. if ($reloadopener) {
  743. // Trigger the reload immediately, even if the reload is after a delay.
  744. $PAGE->requires->js_function_call('window.opener.location.reload', array(true));
  745. }
  746. $OUTPUT->notification(get_string('windowclosing'), 'notifysuccess');
  747. $PAGE->requires->js_function_call('close_window', array(new stdClass()), false, $delay);
  748. echo $OUTPUT->footer();
  749. exit;
  750. }
  751. /**
  752. * Returns a string containing a link to the user documentation for the current
  753. * page. Also contains an icon by default. Shown to teachers and admin only.
  754. *
  755. * @global object
  756. * @global object
  757. * @param string $text The text to be displayed for the link
  758. * @param string $iconpath The path to the icon to be displayed
  759. * @return string The link to user documentation for this current page
  760. */
  761. function page_doc_link($text='') {
  762. global $CFG, $PAGE, $OUTPUT;
  763. if (empty($CFG->docroot) || during_initial_install()) {
  764. return '';
  765. }
  766. if (!has_capability('moodle/site:doclinks', $PAGE->context)) {
  767. return '';
  768. }
  769. $path = $PAGE->docspath;
  770. if (!$path) {
  771. return '';
  772. }
  773. return $OUTPUT->doc_link($path, $text);
  774. }
  775. /**
  776. * Validates an email to make sure it makes sense.
  777. *
  778. * @param string $address The email address to validate.
  779. * @return boolean
  780. */
  781. function validate_email($address) {
  782. return (preg_match('#^[-!\#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+'.
  783. '(\.[-!\#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+)*'.
  784. '@'.
  785. '[-!\#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.
  786. '[-!\#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$#',
  787. $address));
  788. }
  789. /**
  790. * Extracts file argument either from file parameter or PATH_INFO
  791. * Note: $scriptname parameter is not needed anymore
  792. *
  793. * @global string
  794. * @uses $_SERVER
  795. * @uses PARAM_PATH
  796. * @return string file path (only safe characters)
  797. */
  798. function get_file_argument() {
  799. global $SCRIPT;
  800. $relativepath = optional_param('file', FALSE, PARAM_PATH);
  801. if ($relativepath !== false and $relativepath !== '') {
  802. return $relativepath;
  803. }
  804. $relativepath = false;
  805. // then try extract file from the slasharguments
  806. if (stripos($_SERVER['SERVER_SOFTWARE'], 'iis') !== false) {
  807. // NOTE: ISS tends to convert all file paths to single byte DOS encoding,
  808. // we can not use other methods because they break unicode chars,
  809. // the only way is to use URL rewriting
  810. if (isset($_SERVER['PATH_INFO']) and $_SERVER['PATH_INFO'] !== '') {
  811. // check that PATH_INFO works == must not contain the script name
  812. if (strpos($_SERVER['PATH_INFO'], $SCRIPT) === false) {
  813. $relativepath = clean_param(urldecode($_SERVER['PATH_INFO']), PARAM_PATH);
  814. }
  815. }
  816. } else {
  817. // all other apache-like servers depend on PATH_INFO
  818. if (isset($_SERVER['PATH_INFO'])) {
  819. if (isset($_SERVER['SCRIPT_NAME']) and strpos($_SERVER['PATH_INFO'], $_SERVER['SCRIPT_NAME']) === 0) {
  820. $relativepath = substr($_SERVER['PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
  821. } else {
  822. $relativepath = $_SERVER['PATH_INFO'];
  823. }
  824. $relativepath = clean_param($relativepath, PARAM_PATH);
  825. }
  826. }
  827. return $relativepath;
  828. }
  829. /**
  830. * Just returns an array of text formats suitable for a popup menu
  831. *
  832. * @uses FORMAT_MOODLE
  833. * @uses FORMAT_HTML
  834. * @uses FORMAT_PLAIN
  835. * @uses FORMAT_MARKDOWN
  836. * @return array
  837. */
  838. function format_text_menu() {
  839. return array (FORMAT_MOODLE => get_string('formattext'),
  840. FORMAT_HTML => get_string('formathtml'),
  841. FORMAT_PLAIN => get_string('formatplain'),
  842. FORMAT_MARKDOWN => get_string('formatmarkdown'));
  843. }
  844. /**
  845. * Given text in a variety of format codings, this function returns
  846. * the text as safe HTML.
  847. *
  848. * This function should mainly be used for long strings like posts,
  849. * answers, glossary items etc. For short strings @see format_string().
  850. *
  851. * <pre>
  852. * Options:
  853. * trusted : If true the string won't be cleaned. Default false required noclean=true.
  854. * noclean : If true the string won't be cleaned. Default false required trusted=true.
  855. * nocache : If true the strign will not be cached and will be formatted every call. Default false.
  856. * filter : If true the string will be run through applicable filters as well. Default true.
  857. * para : If true then the returned string will be wrapped in div tags. Default true.
  858. * newlines : If true then lines newline breaks will be converted to HTML newline breaks. Default true.
  859. * context : The context that will be used for filtering.
  860. * overflowdiv : If set to true the formatted text will be encased in a div
  861. * with the class no-overflow before being returned. Default false.
  862. * </pre>
  863. *
  864. * @todo Finish documenting this function
  865. *
  866. * @staticvar array $croncache
  867. * @param string $text The text to be formatted. This is raw text originally from user input.
  868. * @param int $format Identifier of the text format to be used
  869. * [FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_MARKDOWN]
  870. * @param object/array $options text formatting options
  871. * @param int $courseid_do_not_use deprecated course id, use context option instead
  872. * @return string
  873. */
  874. function format_text($text, $format = FORMAT_MOODLE, $options = NULL, $courseid_do_not_use = NULL) {
  875. global $CFG, $COURSE, $DB, $PAGE;
  876. static $croncache = array();
  877. if ($text === '') {
  878. return ''; // no need to do any filters and cleaning
  879. }
  880. $options = (array)$options; // detach object, we can not modify it
  881. if (!isset($options['trusted'])) {
  882. $options['trusted'] = false;
  883. }
  884. if (!isset($options['noclean'])) {
  885. if ($options['trusted'] and trusttext_active()) {
  886. // no cleaning if text trusted and noclean not specified
  887. $options['noclean'] = true;
  888. } else {
  889. $options['noclean'] = false;
  890. }
  891. }
  892. if (!isset($options['nocache'])) {
  893. $options['nocache'] = false;
  894. }
  895. if (!isset($options['filter'])) {
  896. $options['filter'] = true;
  897. }
  898. if (!isset($options['para'])) {
  899. $options['para'] = true;
  900. }
  901. if (!isset($options['newlines'])) {
  902. $options['newlines'] = true;
  903. }
  904. if (!isset($options['overflowdiv'])) {
  905. $options['overflowdiv'] = false;
  906. }
  907. // Calculate best context
  908. if (empty($CFG->version) or $CFG->version < 2010072800 or during_initial_install()) {
  909. // do not filter anything during installation or before upgrade completes
  910. $context = null;
  911. } else if (isset($options['context'])) { // first by explicit passed context option
  912. if (is_object($options['context'])) {
  913. $context = $options['context'];
  914. } else {
  915. $context = get_context_instance_by_id($context);
  916. }
  917. } else if ($courseid_do_not_use) {
  918. // legacy courseid
  919. $context = get_context_instance(CONTEXT_COURSE, $courseid_do_not_use);
  920. } else {
  921. // fallback to $PAGE->context this may be problematic in CLI and other non-standard pages :-(
  922. $context = $PAGE->context;
  923. }
  924. if (!$context) {
  925. // either install/upgrade or something has gone really wrong because context does not exist (yet?)
  926. $options['nocache'] = true;
  927. $options['filter'] = false;
  928. }
  929. if ($options['filter']) {
  930. $filtermanager = filter_manager::instance();
  931. } else {
  932. $filtermanager = new null_filter_manager();
  933. }
  934. if (!empty($CFG->cachetext) and empty($options['nocache'])) {
  935. $hashstr = $text.'-'.$filtermanager->text_filtering_hash($context).'-'.$context->id.'-'.current_language().'-'.
  936. (int)$format.(int)$options['trusted'].(int)$options['noclean'].
  937. (int)$options['para'].(int)$options['newlines'];
  938. $time = time() - $CFG->cachetext;
  939. $md5key = md5($hashstr);
  940. if (CLI_SCRIPT) {
  941. if (isset($croncache[$md5key])) {
  942. return $croncache[$md5key];
  943. }
  944. }
  945. if ($oldcacheitem = $DB->get_record('cache_text', array('md5key'=>$md5key), '*', IGNORE_MULTIPLE)) {
  946. if ($oldcacheitem->timemodified >= $time) {
  947. if (CLI_SCRIPT) {
  948. if (count($croncache) > 150) {
  949. reset($croncache);
  950. $key = key($croncache);
  951. unset($croncache[$key]);
  952. }
  953. $croncache[$md5key] = $oldcacheitem->formattedtext;
  954. }
  955. return $oldcacheitem->formattedtext;
  956. }
  957. }
  958. }
  959. switch ($format) {
  960. case FORMAT_HTML:
  961. if (!$options['noclean']) {
  962. $text = clean_text($text, FORMAT_HTML);
  963. }
  964. $text = $filtermanager->filter_text($text, $context, array('originalformat' => FORMAT_HTML));
  965. break;
  966. case FORMAT_PLAIN:
  967. $text = s($text); // cleans dangerous JS
  968. $text = rebuildnolinktag($text);
  969. $text = str_replace(' ', '&nbsp; ', $text);
  970. $text = nl2br($text);
  971. break;
  972. case FORMAT_WIKI:
  973. // this format is deprecated
  974. $text = '<p>NOTICE: Wiki-like formatting has been removed from Moodle. You should not be seeing
  975. this message as all texts should have been converted to Markdown format instead.
  976. Please post a bug report to http://moodle.org/bugs with information about where you
  977. saw this message.</p>'.s($text);
  978. break;
  979. case FORMAT_MARKDOWN:
  980. $text = markdown_to_html($text);
  981. if (!$options['noclean']) {
  982. $text = clean_text($text, FORMAT_HTML);
  983. }
  984. $text = $filtermanager->filter_text($text, $context, array('originalformat' => FORMAT_MARKDOWN));
  985. break;
  986. default: // FORMAT_MOODLE or anything else
  987. $text = text_to_html($text, null, $options['para'], $options['newlines']);
  988. if (!$options['noclean']) {
  989. $text = clean_text($text, FORMAT_HTML);
  990. }
  991. $text = $filtermanager->filter_text($text, $context, array('originalformat' => $format));
  992. break;
  993. }
  994. if ($options['filter']) {
  995. // at this point there should not be any draftfile links any more,
  996. // this happens when developers forget to post process the text.
  997. // The only potential problem is that somebody might try to format
  998. // the text before storing into database which would be itself big bug.
  999. $text = str_replace("\"$CFG->httpswwwroot/draftfile.php", "\"$CFG->httpswwwroot/brokenfile.php#", $text);
  1000. }
  1001. // Warn people that we have removed this old mechanism, just in case they
  1002. // were stupid enough to rely on it.
  1003. if (isset($CFG->currenttextiscacheable)) {
  1004. debugging('Once upon a time, Moodle had a truly evil use of global variables ' .
  1005. 'called $CFG->currenttextiscacheable. The good news is that this no ' .
  1006. 'longer exists. The bad news is that you seem to be using a filter that '.
  1007. 'relies on it. Please seek out and destroy that filter code.', DEBUG_DEVELOPER);
  1008. }
  1009. if (!empty($options['overflowdiv'])) {
  1010. $text = html_writer::tag('div', $text, array('class'=>'no-overflow'));
  1011. }
  1012. if (empty($options['nocache']) and !empty($CFG->cachetext)) {
  1013. if (CLI_SCRIPT) {
  1014. // special static cron cache - no need to store it in db if its not already there
  1015. if (count($croncache) > 150) {
  1016. reset($croncache);
  1017. $key = key($croncache);
  1018. unset($croncache[$key]);
  1019. }
  1020. $croncache[$md5key] = $text;
  1021. return $text;
  1022. }
  1023. $newcacheitem = new stdClass();
  1024. $newcacheitem->md5key = $md5key;
  1025. $newcacheitem->formattedtext = $text;
  1026. $newcacheitem->timemodified = time();
  1027. if ($oldcacheitem) { // See bug 4677 for discussion
  1028. $newcacheitem->id = $oldcacheitem->id;
  1029. try {
  1030. $DB->update_record('cache_text', $newcacheitem); // Update existing record in the cache table
  1031. } catch (dml_exception $e) {
  1032. // It's unlikely that the cron cache cleaner could have
  1033. // deleted this entry in the meantime, as it allows
  1034. // some extra time to cover these cases.
  1035. }
  1036. } else {
  1037. try {
  1038. $DB->insert_record('cache_text', $newcacheitem); // Insert a new record in the cache table
  1039. } catch (dml_exception $e) {
  1040. // Again, it's possible that another user has caused this
  1041. // record to be created already in the time that it took
  1042. // to traverse this function. That's OK too, as the
  1043. // call above handles duplicate entries, and eventually
  1044. // the cron cleaner will delete them.
  1045. }
  1046. }
  1047. }
  1048. return $text;
  1049. }
  1050. /**
  1051. * Resets all data related to filters, called during upgrade or when filter settings change.
  1052. *
  1053. * @global object
  1054. * @global object
  1055. * @return void
  1056. */
  1057. function reset_text_filters_cache() {
  1058. global $CFG, $DB;
  1059. $DB->delete_records('cache_text');
  1060. $purifdir = $CFG->dataroot.'/cache/htmlpurifier';
  1061. remove_dir($purifdir, true);
  1062. }
  1063. /**
  1064. * Given a simple string, this function returns the string
  1065. * processed by enabled string filters if $CFG->filterall is enabled
  1066. *
  1067. * This function should be used to print short strings (non html) that
  1068. * need filter processing e.g. activity titles, post subjects,
  1069. * glossary concepts.
  1070. *
  1071. * @global object
  1072. * @global object
  1073. * @global object
  1074. * @staticvar bool $strcache
  1075. * @param string $string The string to be filtered.
  1076. * @param boolean $striplinks To strip any link in the result text.
  1077. Moodle 1.8 default changed from false to true! MDL-8713
  1078. * @param array $options options array/object or courseid
  1079. * @return string
  1080. */
  1081. function format_string($string, $striplinks = true, $options = NULL) {
  1082. global $CFG, $COURSE, $PAGE;
  1083. //We'll use a in-memory cache here to speed up repeated strings
  1084. static $strcache = false;
  1085. if (empty($CFG->version) or $CFG->version < 2010072800 or during_initial_install()) {
  1086. // do not filter anything during installation or before upgrade completes
  1087. return $string = strip_tags($string);
  1088. }
  1089. if ($strcache === false or count($strcache) > 2000) { // this number might need some tuning to limit memory usage in cron
  1090. $strcache = array();
  1091. }
  1092. if (is_numeric($options)) {
  1093. // legacy courseid usage
  1094. $options = array('context'=>get_context_instance(CONTEXT_COURSE, $options));
  1095. } else {
  1096. $options = (array)$options; // detach object, we can not modify it
  1097. }
  1098. if (empty($options['context'])) {
  1099. // fallback to $PAGE->context this may be problematic in CLI and other non-standard pages :-(
  1100. $options['context'] = $PAGE->context;
  1101. } else if (is_numeric($options['context'])) {
  1102. $options['context'] = get_context_instance_by_id($options['context']);
  1103. }
  1104. if (!$options['context']) {
  1105. // we did not find any context? weird
  1106. return $string = strip_tags($string);
  1107. }
  1108. //Calculate md5
  1109. $md5 = md5($string.'<+>'.$striplinks.'<+>'.$options['context']->id.'<+>'.current_language());
  1110. //Fetch from cache if possible
  1111. if (isset($strcache[$md5])) {
  1112. return $strcache[$md5];
  1113. }
  1114. // First replace all ampersands not followed by html entity code
  1115. // Regular expression moved to its own method for easier unit testing
  1116. $string = replace_ampersands_not_followed_by_entity($string);
  1117. if (!empty($CFG->filterall)) {
  1118. $string = filter_manager::instance()->filter_string($string, $options['context']);
  1119. }
  1120. // If the site requires it, strip ALL tags from this string
  1121. if (!empty($CFG->formatstringstriptags)) {
  1122. $string = strip_tags($string);
  1123. } else {
  1124. // Otherwise strip just links if that is required (default)
  1125. if ($striplinks) { //strip links in string
  1126. $string = strip_links($string);
  1127. }
  1128. $string = clean_text($string);
  1129. }
  1130. //Store to cache
  1131. $strcache[$md5] = $string;
  1132. return $string;
  1133. }
  1134. /**
  1135. * Given a string, performs a negative lookahead looking for any ampersand character
  1136. * that is not followed by a proper HTML entity. If any is found, it is replaced
  1137. * by &amp;. The string is then returned.
  1138. *
  1139. * @param string $string
  1140. * @return string
  1141. */
  1142. function replace_ampersands_not_followed_by_entity($string) {
  1143. return preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&amp;", $string);
  1144. }
  1145. /**
  1146. * Given a string, replaces all <a>.*</a> by .* and returns the string.
  1147. *
  1148. * @param string $string
  1149. * @return string
  1150. */
  1151. function strip_links($string) {
  1152. return preg_replace('/(<a\s[^>]+?>)(.+?)(<\/a>)/is','$2',$string);
  1153. }
  1154. /**
  1155. * This expression turns links into something nice in a text format. (Russell Jungwirth)
  1156. *
  1157. * @param string $string
  1158. * @return string
  1159. */
  1160. function wikify_links($string) {
  1161. return preg_replace('~(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)~i','$3 [ $2 ]', $string);
  1162. }
  1163. /**
  1164. * Replaces non-standard HTML entities
  1165. *
  1166. * @param string $string
  1167. * @return string
  1168. */
  1169. function fix_non_standard_entities($string) {
  1170. $text = preg_replace('/&#0*([0-9]+);?/', '&#$1;', $string);
  1171. $text = preg_replace('/&#x0*([0-9a-fA-F]+);?/', '&#x$1;', $text);
  1172. $text = preg_replace('[\x00-\x08\x0b-\x0c\x0e-\x1f]', '', $text);
  1173. return $text;
  1174. }
  1175. /**
  1176. * Given text in a variety of format codings, this function returns
  1177. * the text as plain text suitable for plain email.
  1178. *
  1179. * @uses FORMAT_MOODLE
  1180. * @uses FORMAT_HTML
  1181. * @uses FORMAT_PLAIN
  1182. * @uses FORMAT_WIKI
  1183. * @uses FORMAT_MARKDOWN
  1184. * @param string $text The text to be formatted. This is raw text originally from user input.
  1185. * @param int $format Identifier of the text format to be used
  1186. * [FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN]
  1187. * @return string
  1188. */
  1189. function format_text_email($text, $format) {
  1190. switch ($format) {
  1191. case FORMAT_PLAIN:
  1192. return $text;
  1193. break;
  1194. case FORMAT_WIKI:
  1195. // there should not be any of these any more!
  1196. $text = wikify_links($text);
  1197. return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
  1198. break;
  1199. case FORMAT_HTML:
  1200. return html_to_text($text);
  1201. break;
  1202. case FORMAT_MOODLE:
  1203. case FORMAT_MARKDOWN:
  1204. default:
  1205. $text = wikify_links($text);
  1206. return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
  1207. break;
  1208. }
  1209. }
  1210. /**
  1211. * Formats activity intro text
  1212. *
  1213. * @global object
  1214. * @uses CONTEXT_MODULE
  1215. * @param string $module name of module
  1216. * @param object $activity instance of activity
  1217. * @param int $cmid course module id
  1218. * @param bool $filter filter resulting html text
  1219. * @return text
  1220. */
  1221. function format_module_intro($module, $activity, $cmid, $filter=true) {
  1222. global $CFG;
  1223. require_once("$CFG->libdir/filelib.php");
  1224. $context = get_context_instance(CONTEXT_MODULE, $cmid);
  1225. $options = array('noclean'=>true, 'para'=>false, 'filter'=>$filter, 'context'=>$context, 'overflowdiv'=>true);
  1226. $intro = file_rewrite_pluginfile_urls($activity->intro, 'pluginfile.php', $context->id, 'mod_'.$module, 'intro', null);
  1227. return trim(format_text($intro, $activity->introformat, $options, null));
  1228. }
  1229. /**
  1230. * Legacy function, used for cleaning of old forum and glossary text only.
  1231. *
  1232. * @global object
  1233. * @param string $text text that may contain legacy TRUSTTEXT marker
  1234. * @return text without legacy TRUSTTEXT marker
  1235. */
  1236. function trusttext_strip($text) {
  1237. while (true) { //removing nested TRUSTTEXT
  1238. $orig = $text;
  1239. $text = str_replace('#####TRUSTTEXT#####', '', $text);
  1240. if (strcmp($orig, $text) === 0) {
  1241. return $text;
  1242. }
  1243. }
  1244. }
  1245. /**
  1246. * Must be called before editing of all texts
  1247. * with trust flag. Removes all XSS nasties
  1248. * from texts stored in database if needed.
  1249. *
  1250. * @param object $object data object with xxx, xxxformat and xxxtrust fields
  1251. * @param string $field name of text field
  1252. * @param object $context active context
  1253. * @return object updated $object
  1254. */
  1255. function trusttext_pre_edit($object, $field, $context) {
  1256. $trustfield = $field.'trust';
  1257. $formatfield = $field.'format';
  1258. if (!$object->$trustfield or !trusttext_trusted($context)) {
  1259. $object->$field = clean_text($object->$field, $object->$formatfield);
  1260. }
  1261. return $object;
  1262. }
  1263. /**
  1264. * Is current user trusted to enter no dangerous XSS in this context?
  1265. *
  1266. * Please note the user must be in fact trusted everywhere on this server!!
  1267. *
  1268. * @param object $context
  1269. * @return bool true if user trusted
  1270. */
  1271. function trusttext_trusted($context) {
  1272. return (trusttext_active() and has_capability('moodle/site:trustcontent', $context));
  1273. }
  1274. /**
  1275. * Is trusttext feature active?
  1276. *
  1277. * @global object
  1278. * @param object $context
  1279. * @return bool
  1280. */
  1281. function trusttext_active() {
  1282. gl

Large files files are truncated, but you can click here to view the full file