PageRenderTime 71ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/weblib.php

https://github.com/glovenone/moodle
PHP | 3312 lines | 1690 code | 387 blank | 1235 comment | 395 complexity | f73eec5ab04b5fd484d6012f82d15678 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, BSD-3-Clause, AGPL-3.0, MPL-2.0-no-copyleft-exception, Apache-2.0

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. *
  497. * @param bool $includeanchor if {@link self::anchor} is defined, should it be returned?
  498. * @return string
  499. */
  500. public function out_omit_querystring($includeanchor = false) {
  501. $uri = $this->scheme ? $this->scheme.':'.((strtolower($this->scheme) == 'mailto') ? '':'//'): '';
  502. $uri .= $this->user ? $this->user.($this->pass? ':'.$this->pass:'').'@':'';
  503. $uri .= $this->host ? $this->host : '';
  504. $uri .= $this->port ? ':'.$this->port : '';
  505. $uri .= $this->path ? $this->path : '';
  506. if ($includeanchor and !is_null($this->anchor)) {
  507. $uri .= '#' . $this->anchor;
  508. }
  509. return $uri;
  510. }
  511. /**
  512. * Compares this moodle_url with another
  513. * See documentation of constants for an explanation of the comparison flags.
  514. * @param moodle_url $url The moodle_url object to compare
  515. * @param int $matchtype The type of comparison (URL_MATCH_BASE, URL_MATCH_PARAMS, URL_MATCH_EXACT)
  516. * @return boolean
  517. */
  518. public function compare(moodle_url $url, $matchtype = URL_MATCH_EXACT) {
  519. $baseself = $this->out_omit_querystring();
  520. $baseother = $url->out_omit_querystring();
  521. // Append index.php if there is no specific file
  522. if (substr($baseself,-1)=='/') {
  523. $baseself .= 'index.php';
  524. }
  525. if (substr($baseother,-1)=='/') {
  526. $baseother .= 'index.php';
  527. }
  528. // Compare the two base URLs
  529. if ($baseself != $baseother) {
  530. return false;
  531. }
  532. if ($matchtype == URL_MATCH_BASE) {
  533. return true;
  534. }
  535. $urlparams = $url->params();
  536. foreach ($this->params() as $param => $value) {
  537. if ($param == 'sesskey') {
  538. continue;
  539. }
  540. if (!array_key_exists($param, $urlparams) || $urlparams[$param] != $value) {
  541. return false;
  542. }
  543. }
  544. if ($matchtype == URL_MATCH_PARAMS) {
  545. return true;
  546. }
  547. foreach ($urlparams as $param => $value) {
  548. if ($param == 'sesskey') {
  549. continue;
  550. }
  551. if (!array_key_exists($param, $this->params()) || $this->param($param) != $value) {
  552. return false;
  553. }
  554. }
  555. return true;
  556. }
  557. /**
  558. * Sets the anchor for the URI (the bit after the hash)
  559. * @param string $anchor null means remove previous
  560. */
  561. public function set_anchor($anchor) {
  562. if (is_null($anchor)) {
  563. // remove
  564. $this->anchor = null;
  565. } else if ($anchor === '') {
  566. // special case, used as empty link
  567. $this->anchor = '';
  568. } else if (preg_match('|[a-zA-Z\_\:][a-zA-Z0-9\_\-\.\:]*|', $anchor)) {
  569. // Match the anchor against the NMTOKEN spec
  570. $this->anchor = $anchor;
  571. } else {
  572. // bad luck, no valid anchor found
  573. $this->anchor = null;
  574. }
  575. }
  576. /**
  577. * Sets the url slashargument value
  578. * @param string $path usually file path
  579. * @param string $parameter name of page parameter if slasharguments not supported
  580. * @param bool $supported usually null, then it depends on $CFG->slasharguments, use true or false for other servers
  581. * @return void
  582. */
  583. public function set_slashargument($path, $parameter = 'file', $supported = NULL) {
  584. global $CFG;
  585. if (is_null($supported)) {
  586. $supported = $CFG->slasharguments;
  587. }
  588. if ($supported) {
  589. $parts = explode('/', $path);
  590. $parts = array_map('rawurlencode', $parts);
  591. $path = implode('/', $parts);
  592. $this->slashargument = $path;
  593. unset($this->params[$parameter]);
  594. } else {
  595. $this->slashargument = '';
  596. $this->params[$parameter] = $path;
  597. }
  598. }
  599. // == static factory methods ==
  600. /**
  601. * General moodle file url.
  602. * @param string $urlbase the script serving the file
  603. * @param string $path
  604. * @param bool $forcedownload
  605. * @return moodle_url
  606. */
  607. public static function make_file_url($urlbase, $path, $forcedownload = false) {
  608. global $CFG;
  609. $params = array();
  610. if ($forcedownload) {
  611. $params['forcedownload'] = 1;
  612. }
  613. $url = new moodle_url($urlbase, $params);
  614. $url->set_slashargument($path);
  615. return $url;
  616. }
  617. /**
  618. * Factory method for creation of url pointing to plugin file.
  619. * Please note this method can be used only from the plugins to
  620. * create urls of own files, it must not be used outside of plugins!
  621. * @param int $contextid
  622. * @param string $component
  623. * @param string $area
  624. * @param int $itemid
  625. * @param string $pathname
  626. * @param string $filename
  627. * @param bool $forcedownload
  628. * @return moodle_url
  629. */
  630. public static function make_pluginfile_url($contextid, $component, $area, $itemid, $pathname, $filename, $forcedownload = false) {
  631. global $CFG;
  632. $urlbase = "$CFG->httpswwwroot/pluginfile.php";
  633. if ($itemid === NULL) {
  634. return self::make_file_url($urlbase, "/$contextid/$component/$area".$pathname.$filename, $forcedownload);
  635. } else {
  636. return self::make_file_url($urlbase, "/$contextid/$component/$area/$itemid".$pathname.$filename, $forcedownload);
  637. }
  638. }
  639. /**
  640. * Factory method for creation of url pointing to draft
  641. * file of current user.
  642. * @param int $draftid draft item id
  643. * @param string $pathname
  644. * @param string $filename
  645. * @param bool $forcedownload
  646. * @return moodle_url
  647. */
  648. public static function make_draftfile_url($draftid, $pathname, $filename, $forcedownload = false) {
  649. global $CFG, $USER;
  650. $urlbase = "$CFG->httpswwwroot/draftfile.php";
  651. $context = get_context_instance(CONTEXT_USER, $USER->id);
  652. return self::make_file_url($urlbase, "/$context->id/user/draft/$draftid".$pathname.$filename, $forcedownload);
  653. }
  654. /**
  655. * Factory method for creating of links to legacy
  656. * course files.
  657. * @param int $courseid
  658. * @param string $filepath
  659. * @param bool $forcedownload
  660. * @return moodle_url
  661. */
  662. public static function make_legacyfile_url($courseid, $filepath, $forcedownload = false) {
  663. global $CFG;
  664. $urlbase = "$CFG->wwwroot/file.php";
  665. return self::make_file_url($urlbase, '/'.$courseid.'/'.$filepath, $forcedownload);
  666. }
  667. }
  668. /**
  669. * Determine if there is data waiting to be processed from a form
  670. *
  671. * Used on most forms in Moodle to check for data
  672. * Returns the data as an object, if it's found.
  673. * This object can be used in foreach loops without
  674. * casting because it's cast to (array) automatically
  675. *
  676. * Checks that submitted POST data exists and returns it as object.
  677. *
  678. * @uses $_POST
  679. * @return mixed false or object
  680. */
  681. function data_submitted() {
  682. if (empty($_POST)) {
  683. return false;
  684. } else {
  685. return (object)$_POST;
  686. }
  687. }
  688. /**
  689. * Given some normal text this function will break up any
  690. * long words to a given size by inserting the given character
  691. *
  692. * It's multibyte savvy and doesn't change anything inside html tags.
  693. *
  694. * @param string $string the string to be modified
  695. * @param int $maxsize maximum length of the string to be returned
  696. * @param string $cutchar the string used to represent word breaks
  697. * @return string
  698. */
  699. function break_up_long_words($string, $maxsize=20, $cutchar=' ') {
  700. /// Loading the textlib singleton instance. We are going to need it.
  701. $textlib = textlib_get_instance();
  702. /// First of all, save all the tags inside the text to skip them
  703. $tags = array();
  704. filter_save_tags($string,$tags);
  705. /// Process the string adding the cut when necessary
  706. $output = '';
  707. $length = $textlib->strlen($string);
  708. $wordlength = 0;
  709. for ($i=0; $i<$length; $i++) {
  710. $char = $textlib->substr($string, $i, 1);
  711. if ($char == ' ' or $char == "\t" or $char == "\n" or $char == "\r" or $char == "<" or $char == ">") {
  712. $wordlength = 0;
  713. } else {
  714. $wordlength++;
  715. if ($wordlength > $maxsize) {
  716. $output .= $cutchar;
  717. $wordlength = 0;
  718. }
  719. }
  720. $output .= $char;
  721. }
  722. /// Finally load the tags back again
  723. if (!empty($tags)) {
  724. $output = str_replace(array_keys($tags), $tags, $output);
  725. }
  726. return $output;
  727. }
  728. /**
  729. * Try and close the current window using JavaScript, either immediately, or after a delay.
  730. *
  731. * Echo's out the resulting XHTML & javascript
  732. *
  733. * @global object
  734. * @global object
  735. * @param integer $delay a delay in seconds before closing the window. Default 0.
  736. * @param boolean $reloadopener if true, we will see if this window was a pop-up, and try
  737. * to reload the parent window before this one closes.
  738. */
  739. function close_window($delay = 0, $reloadopener = false) {
  740. global $PAGE, $OUTPUT;
  741. if (!$PAGE->headerprinted) {
  742. $PAGE->set_title(get_string('closewindow'));
  743. echo $OUTPUT->header();
  744. } else {
  745. $OUTPUT->container_end_all(false);
  746. }
  747. if ($reloadopener) {
  748. // Trigger the reload immediately, even if the reload is after a delay.
  749. $PAGE->requires->js_function_call('window.opener.location.reload', array(true));
  750. }
  751. $OUTPUT->notification(get_string('windowclosing'), 'notifysuccess');
  752. $PAGE->requires->js_function_call('close_window', array(new stdClass()), false, $delay);
  753. echo $OUTPUT->footer();
  754. exit;
  755. }
  756. /**
  757. * Returns a string containing a link to the user documentation for the current
  758. * page. Also contains an icon by default. Shown to teachers and admin only.
  759. *
  760. * @global object
  761. * @global object
  762. * @param string $text The text to be displayed for the link
  763. * @param string $iconpath The path to the icon to be displayed
  764. * @return string The link to user documentation for this current page
  765. */
  766. function page_doc_link($text='') {
  767. global $CFG, $PAGE, $OUTPUT;
  768. if (empty($CFG->docroot) || during_initial_install()) {
  769. return '';
  770. }
  771. if (!has_capability('moodle/site:doclinks', $PAGE->context)) {
  772. return '';
  773. }
  774. $path = $PAGE->docspath;
  775. if (!$path) {
  776. return '';
  777. }
  778. return $OUTPUT->doc_link($path, $text);
  779. }
  780. /**
  781. * Validates an email to make sure it makes sense.
  782. *
  783. * @param string $address The email address to validate.
  784. * @return boolean
  785. */
  786. function validate_email($address) {
  787. return (preg_match('#^[-!\#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+'.
  788. '(\.[-!\#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+)*'.
  789. '@'.
  790. '[-!\#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.
  791. '[-!\#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$#',
  792. $address));
  793. }
  794. /**
  795. * Extracts file argument either from file parameter or PATH_INFO
  796. * Note: $scriptname parameter is not needed anymore
  797. *
  798. * @global string
  799. * @uses $_SERVER
  800. * @uses PARAM_PATH
  801. * @return string file path (only safe characters)
  802. */
  803. function get_file_argument() {
  804. global $SCRIPT;
  805. $relativepath = optional_param('file', FALSE, PARAM_PATH);
  806. if ($relativepath !== false and $relativepath !== '') {
  807. return $relativepath;
  808. }
  809. $relativepath = false;
  810. // then try extract file from the slasharguments
  811. if (stripos($_SERVER['SERVER_SOFTWARE'], 'iis') !== false) {
  812. // NOTE: ISS tends to convert all file paths to single byte DOS encoding,
  813. // we can not use other methods because they break unicode chars,
  814. // the only way is to use URL rewriting
  815. if (isset($_SERVER['PATH_INFO']) and $_SERVER['PATH_INFO'] !== '') {
  816. // check that PATH_INFO works == must not contain the script name
  817. if (strpos($_SERVER['PATH_INFO'], $SCRIPT) === false) {
  818. $relativepath = clean_param(urldecode($_SERVER['PATH_INFO']), PARAM_PATH);
  819. }
  820. }
  821. } else {
  822. // all other apache-like servers depend on PATH_INFO
  823. if (isset($_SERVER['PATH_INFO'])) {
  824. if (isset($_SERVER['SCRIPT_NAME']) and strpos($_SERVER['PATH_INFO'], $_SERVER['SCRIPT_NAME']) === 0) {
  825. $relativepath = substr($_SERVER['PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
  826. } else {
  827. $relativepath = $_SERVER['PATH_INFO'];
  828. }
  829. $relativepath = clean_param($relativepath, PARAM_PATH);
  830. }
  831. }
  832. return $relativepath;
  833. }
  834. /**
  835. * Just returns an array of text formats suitable for a popup menu
  836. *
  837. * @uses FORMAT_MOODLE
  838. * @uses FORMAT_HTML
  839. * @uses FORMAT_PLAIN
  840. * @uses FORMAT_MARKDOWN
  841. * @return array
  842. */
  843. function format_text_menu() {
  844. return array (FORMAT_MOODLE => get_string('formattext'),
  845. FORMAT_HTML => get_string('formathtml'),
  846. FORMAT_PLAIN => get_string('formatplain'),
  847. FORMAT_MARKDOWN => get_string('formatmarkdown'));
  848. }
  849. /**
  850. * Given text in a variety of format codings, this function returns
  851. * the text as safe HTML.
  852. *
  853. * This function should mainly be used for long strings like posts,
  854. * answers, glossary items etc. For short strings @see format_string().
  855. *
  856. * <pre>
  857. * Options:
  858. * trusted : If true the string won't be cleaned. Default false required noclean=true.
  859. * noclean : If true the string won't be cleaned. Default false required trusted=true.
  860. * nocache : If true the strign will not be cached and will be formatted every call. Default false.
  861. * filter : If true the string will be run through applicable filters as well. Default true.
  862. * para : If true then the returned string will be wrapped in div tags. Default true.
  863. * newlines : If true then lines newline breaks will be converted to HTML newline breaks. Default true.
  864. * context : The context that will be used for filtering.
  865. * overflowdiv : If set to true the formatted text will be encased in a div
  866. * with the class no-overflow before being returned. Default false.
  867. * allowid : If true then id attributes will not be removed, even when
  868. * using htmlpurifier. Default false.
  869. * </pre>
  870. *
  871. * @todo Finish documenting this function
  872. *
  873. * @staticvar array $croncache
  874. * @param string $text The text to be formatted. This is raw text originally from user input.
  875. * @param int $format Identifier of the text format to be used
  876. * [FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_MARKDOWN]
  877. * @param object/array $options text formatting options
  878. * @param int $courseid_do_not_use deprecated course id, use context option instead
  879. * @return string
  880. */
  881. function format_text($text, $format = FORMAT_MOODLE, $options = NULL, $courseid_do_not_use = NULL) {
  882. global $CFG, $COURSE, $DB, $PAGE;
  883. static $croncache = array();
  884. if ($text === '' || is_null($text)) {
  885. return ''; // no need to do any filters and cleaning
  886. }
  887. $options = (array)$options; // detach object, we can not modify it
  888. if (!isset($options['trusted'])) {
  889. $options['trusted'] = false;
  890. }
  891. if (!isset($options['noclean'])) {
  892. if ($options['trusted'] and trusttext_active()) {
  893. // no cleaning if text trusted and noclean not specified
  894. $options['noclean'] = true;
  895. } else {
  896. $options['noclean'] = false;
  897. }
  898. }
  899. if (!isset($options['nocache'])) {
  900. $options['nocache'] = false;
  901. }
  902. if (!isset($options['filter'])) {
  903. $options['filter'] = true;
  904. }
  905. if (!isset($options['para'])) {
  906. $options['para'] = true;
  907. }
  908. if (!isset($options['newlines'])) {
  909. $options['newlines'] = true;
  910. }
  911. if (!isset($options['overflowdiv'])) {
  912. $options['overflowdiv'] = false;
  913. }
  914. // Calculate best context
  915. if (empty($CFG->version) or $CFG->version < 2010072800 or during_initial_install()) {
  916. // do not filter anything during installation or before upgrade completes
  917. $context = null;
  918. } else if (isset($options['context'])) { // first by explicit passed context option
  919. if (is_object($options['context'])) {
  920. $context = $options['context'];
  921. } else {
  922. $context = get_context_instance_by_id($options['context']);
  923. }
  924. } else if ($courseid_do_not_use) {
  925. // legacy courseid
  926. $context = get_context_instance(CONTEXT_COURSE, $courseid_do_not_use);
  927. } else {
  928. // fallback to $PAGE->context this may be problematic in CLI and other non-standard pages :-(
  929. $context = $PAGE->context;
  930. }
  931. if (!$context) {
  932. // either install/upgrade or something has gone really wrong because context does not exist (yet?)
  933. $options['nocache'] = true;
  934. $options['filter'] = false;
  935. }
  936. if ($options['filter']) {
  937. $filtermanager = filter_manager::instance();
  938. } else {
  939. $filtermanager = new null_filter_manager();
  940. }
  941. if (!empty($CFG->cachetext) and empty($options['nocache'])) {
  942. $hashstr = $text.'-'.$filtermanager->text_filtering_hash($context).'-'.$context->id.'-'.current_language().'-'.
  943. (int)$format.(int)$options['trusted'].(int)$options['noclean'].
  944. (int)$options['para'].(int)$options['newlines'];
  945. $time = time() - $CFG->cachetext;
  946. $md5key = md5($hashstr);
  947. if (CLI_SCRIPT) {
  948. if (isset($croncache[$md5key])) {
  949. return $croncache[$md5key];
  950. }
  951. }
  952. if ($oldcacheitem = $DB->get_record('cache_text', array('md5key'=>$md5key), '*', IGNORE_MULTIPLE)) {
  953. if ($oldcacheitem->timemodified >= $time) {
  954. if (CLI_SCRIPT) {
  955. if (count($croncache) > 150) {
  956. reset($croncache);
  957. $key = key($croncache);
  958. unset($croncache[$key]);
  959. }
  960. $croncache[$md5key] = $oldcacheitem->formattedtext;
  961. }
  962. return $oldcacheitem->formattedtext;
  963. }
  964. }
  965. }
  966. switch ($format) {
  967. case FORMAT_HTML:
  968. if (!$options['noclean']) {
  969. $text = clean_text($text, FORMAT_HTML, $options);
  970. }
  971. $text = $filtermanager->filter_text($text, $context, array('originalformat' => FORMAT_HTML, 'noclean' => $options['noclean']));
  972. break;
  973. case FORMAT_PLAIN:
  974. $text = s($text); // cleans dangerous JS
  975. $text = rebuildnolinktag($text);
  976. $text = str_replace(' ', '&nbsp; ', $text);
  977. $text = nl2br($text);
  978. break;
  979. case FORMAT_WIKI:
  980. // this format is deprecated
  981. $text = '<p>NOTICE: Wiki-like formatting has been removed from Moodle. You should not be seeing
  982. this message as all texts should have been converted to Markdown format instead.
  983. Please post a bug report to http://moodle.org/bugs with information about where you
  984. saw this message.</p>'.s($text);
  985. break;
  986. case FORMAT_MARKDOWN:
  987. $text = markdown_to_html($text);
  988. if (!$options['noclean']) {
  989. $text = clean_text($text, FORMAT_HTML, $options);
  990. }
  991. $text = $filtermanager->filter_text($text, $context, array('originalformat' => FORMAT_MARKDOWN, 'noclean' => $options['noclean']));
  992. break;
  993. default: // FORMAT_MOODLE or anything else
  994. $text = text_to_html($text, null, $options['para'], $options['newlines']);
  995. if (!$options['noclean']) {
  996. $text = clean_text($text, FORMAT_HTML, $options);
  997. }
  998. $text = $filtermanager->filter_text($text, $context, array('originalformat' => $format, 'noclean' => $options['noclean']));
  999. break;
  1000. }
  1001. if ($options['filter']) {
  1002. // at this point there should not be any draftfile links any more,
  1003. // this happens when developers forget to post process the text.
  1004. // The only potential problem is that somebody might try to format
  1005. // the text before storing into database which would be itself big bug.
  1006. $text = str_replace("\"$CFG->httpswwwroot/draftfile.php", "\"$CFG->httpswwwroot/brokenfile.php#", $text);
  1007. }
  1008. // Warn people that we have removed this old mechanism, just in case they
  1009. // were stupid enough to rely on it.
  1010. if (isset($CFG->currenttextiscacheable)) {
  1011. debugging('Once upon a time, Moodle had a truly evil use of global variables ' .
  1012. 'called $CFG->currenttextiscacheable. The good news is that this no ' .
  1013. 'longer exists. The bad news is that you seem to be using a filter that '.
  1014. 'relies on it. Please seek out and destroy that filter code.', DEBUG_DEVELOPER);
  1015. }
  1016. if (!empty($options['overflowdiv'])) {
  1017. $text = html_writer::tag('div', $text, array('class'=>'no-overflow'));
  1018. }
  1019. if (empty($options['nocache']) and !empty($CFG->cachetext)) {
  1020. if (CLI_SCRIPT) {
  1021. // special static cron cache - no need to store it in db if its not already there
  1022. if (count($croncache) > 150) {
  1023. reset($croncache);
  1024. $key = key($croncache);
  1025. unset($croncache[$key]);
  1026. }
  1027. $croncache[$md5key] = $text;
  1028. return $text;
  1029. }
  1030. $newcacheitem = new stdClass();
  1031. $newcacheitem->md5key = $md5key;
  1032. $newcacheitem->formattedtext = $text;
  1033. $newcacheitem->timemodified = time();
  1034. if ($oldcacheitem) { // See bug 4677 for discussion
  1035. $newcacheitem->id = $oldcacheitem->id;
  1036. try {
  1037. $DB->update_record('cache_text', $newcacheitem); // Update existing record in the cache table
  1038. } catch (dml_exception $e) {
  1039. // It's unlikely that the cron cache cleaner could have
  1040. // deleted this entry in the meantime, as it allows
  1041. // some extra time to cover these cases.
  1042. }
  1043. } else {
  1044. try {
  1045. $DB->insert_record('cache_text', $newcacheitem); // Insert a new record in the cache table
  1046. } catch (dml_exception $e) {
  1047. // Again, it's possible that another user has caused this
  1048. // record to be created already in the time that it took
  1049. // to traverse this function. That's OK too, as the
  1050. // call above handles duplicate entries, and eventually
  1051. // the cron cleaner will delete them.
  1052. }
  1053. }
  1054. }
  1055. return $text;
  1056. }
  1057. /**
  1058. * Resets all data related to filters, called during upgrade or when filter settings change.
  1059. *
  1060. * @global object
  1061. * @global object
  1062. * @return void
  1063. */
  1064. function reset_text_filters_cache() {
  1065. global $CFG, $DB;
  1066. $DB->delete_records('cache_text');
  1067. $purifdir = $CFG->dataroot.'/cache/htmlpurifier';
  1068. remove_dir($purifdir, true);
  1069. }
  1070. /**
  1071. * Given a simple string, this function returns the string
  1072. * processed by enabled string filters if $CFG->filterall is enabled
  1073. *
  1074. * This function should be used to print short strings (non html) that
  1075. * need filter processing e.g. activity titles, post subjects,
  1076. * glossary concepts.
  1077. *
  1078. * @global object
  1079. * @global object
  1080. * @global object
  1081. * @staticvar bool $strcache
  1082. * @param string $string The string to be filtered.
  1083. * @param boolean $striplinks To strip any link in the result text.
  1084. Moodle 1.8 default changed from false to true! MDL-8713
  1085. * @param array $options options array/object or courseid
  1086. * @return string
  1087. */
  1088. function format_string($string, $striplinks = true, $options = NULL) {
  1089. global $CFG, $COURSE, $PAGE;
  1090. //We'll use a in-memory cache here to speed up repeated strings
  1091. static $strcache = false;
  1092. if (empty($CFG->version) or $CFG->version < 2010072800 or during_initial_install()) {
  1093. // do not filter anything during installation or before upgrade completes
  1094. return $string = strip_tags($string);
  1095. }
  1096. if ($strcache === false or count($strcache) > 2000) { // this number might need some tuning to limit memory usage in cron
  1097. $strcache = array();
  1098. }
  1099. if (is_numeric($options)) {
  1100. // legacy courseid usage
  1101. $options = array('context'=>get_context_instance(CONTEXT_COURSE, $options));
  1102. } else {
  1103. $options = (array)$options; // detach object, we can not modify it
  1104. }
  1105. if (empty($options['context'])) {
  1106. // fallback to $PAGE->context this may be problematic in CLI and other non-standard pages :-(
  1107. $options['context'] = $PAGE->context;
  1108. } else if (is_numeric($options['context'])) {
  1109. $options['context'] = get_context_instance_by_id($options['context']);
  1110. }
  1111. if (!$options['context']) {
  1112. // we did not find any context? weird
  1113. return $string = strip_tags($string);
  1114. }
  1115. //Calculate md5
  1116. $md5 = md5($string.'<+>'.$striplinks.'<+>'.$options['context']->id.'<+>'.current_language());
  1117. //Fetch from cache if possible
  1118. if (isset($strcache[$md5])) {
  1119. return $strcache[$md5];
  1120. }
  1121. // First replace all ampersands not followed by html entity code
  1122. // Regular expression moved to its own method for easier unit testing
  1123. $string = replace_ampersands_not_followed_by_entity($string);
  1124. if (!empty($CFG->filterall)) {
  1125. $string = filter_manager::instance()->filter_string($string, $options['context']);
  1126. }
  1127. // If the site requires it, strip ALL tags from this string
  1128. if (!empty($CFG->formatstringstriptags)) {
  1129. $string = strip_tags($string);
  1130. } else {
  1131. // Otherwise strip just links if that is required (default)
  1132. if ($striplinks) { //strip links in string
  1133. $string = strip_links($string);
  1134. }
  1135. $string = clean_text($string);
  1136. }
  1137. //Store to cache
  1138. $strcache[$md5] = $string;
  1139. return $string;
  1140. }
  1141. /**
  1142. * Given a string, performs a negative lookahead looking for any ampersand character
  1143. * that is not followed by a proper HTML entity. If any is found, it is replaced
  1144. * by &amp;. The string is then returned.
  1145. *
  1146. * @param string $string
  1147. * @return string
  1148. */
  1149. function replace_ampersands_not_followed_by_entity($string) {
  1150. return preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&amp;", $string);
  1151. }
  1152. /**
  1153. * Given a string, replaces all <a>.*</a> by .* and returns the string.
  1154. *
  1155. * @param string $string
  1156. * @return string
  1157. */
  1158. function strip_links($string) {
  1159. return preg_replace('/(<a\s[^>]+?>)(.+?)(<\/a>)/is','$2',$string);
  1160. }
  1161. /**
  1162. * This expression turns links into something nice in a text format. (Russell Jungwirth)
  1163. *
  1164. * @param string $string
  1165. * @return string
  1166. */
  1167. function wikify_links($string) {
  1168. return preg_replace('~(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)~i','$3 [ $2 ]', $string);
  1169. }
  1170. /**
  1171. * Replaces non-standard HTML entities
  1172. *
  1173. * @param string $string
  1174. * @return string
  1175. */
  1176. function fix_non_standard_entities($string) {
  1177. $text = preg_replace('/&#0*([0-9]+);?/', '&#$1;', $string);
  1178. $text = preg_replace('/&#x0*([0-9a-fA-F]+);?/', '&#x$1;', $text);
  1179. $text = preg_replace('[\x00-\x08\x0b-\x0c\x0e-\x1f]', '', $text);
  1180. return $text;
  1181. }
  1182. /**
  1183. * Given text in a variety of format codings, this function returns
  1184. * the text as plain text suitable for plain email.
  1185. *
  1186. * @uses FORMAT_MOODLE
  1187. * @uses FORMAT_HTML
  1188. * @uses FORMAT_PLAIN
  1189. * @uses FORMAT_WIKI
  1190. * @uses FORMAT_MARKDOWN
  1191. * @param string $text The text to be formatted. This is raw text originally from user input.
  1192. * @param int $format Identifier of the text format to be used
  1193. * [FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN]
  1194. * @return string
  1195. */
  1196. function format_text_email($text, $format) {
  1197. switch ($format) {
  1198. case FORMAT_PLAIN:
  1199. return $text;
  1200. break;
  1201. case FORMAT_WIKI:
  1202. // there should not be any of these any more!
  1203. $text = wikify_links($text);
  1204. return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
  1205. break;
  1206. case FORMAT_HTML:
  1207. return html_to_text($text);
  1208. break;
  1209. case FORMAT_MOODLE:
  1210. case FORMAT_MARKDOWN:
  1211. default:
  1212. $text = wikify_links($text);
  1213. return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
  1214. break;
  1215. }
  1216. }
  1217. /**
  1218. * Formats activity intro text
  1219. *
  1220. * @global object
  1221. * @uses CONTEXT_MODULE
  1222. * @param string $module name of module
  1223. * @param object $activity instance of activity
  1224. * @param int $cmid course module id
  1225. * @param bool $filter filter resulting html text
  1226. * @return text
  1227. */
  1228. function format_module_intro($module, $activity, $cmid, $filter=true) {
  1229. global $CFG;
  1230. require_once("$CFG->libdir/filelib.php");
  1231. $context = get_context_instance(CONTEXT_MODULE, $cmid);
  1232. $options = array('noclean'=>true, 'para'=>false, 'filter'=>$filter, 'context'=>$context, 'overflowdiv'=>true);
  1233. $intro = file_rewrite_pluginfile_urls($activity->intro, 'pluginfile.php', $context->id, 'mod_'.$module, 'intro', null);
  1234. return trim(format_text($intro, $activity->introformat, $options, null));
  1235. }
  1236. /**
  1237. * Legacy function, used for cleaning of old forum and glossary text only.
  1238. *
  1239. * @global object
  1240. * @param string $text text that may contain legacy TRUSTTEXT marker
  1241. * @return text without legacy TRUSTTEXT marker
  1242. */
  1243. function trusttext_strip($text) {
  1244. while (true) { //removing nested TRUSTTEXT
  1245. $orig = $text;
  1246. $text = str_replace('#####TRUSTTEXT#####', '', $text);
  1247. if (strcmp($orig, $text) === 0) {
  1248. return $text;
  1249. }
  1250. }
  1251. }
  1252. /**
  1253. * Must be called before editing of all texts
  1254. * with trust flag. Removes all XSS nasties
  1255. * from texts stored in database if needed.
  1256. *
  1257. * @param object $object data object with xxx, xxxformat and xxxtrust fields
  1258. * @param string $field name of text field
  1259. * @param object $context active context
  1260. * @return object updated $object
  1261. */
  1262. function trusttext_pre_edit($object, $field, $context) {
  1263. $trustfield = $field.'trust';
  1264. $formatfield = $field.'format';
  1265. if (!$object->$trustfield or !trusttext_trusted($context)) {
  1266. $object->$field = clean_text($object->$field, $object->$for

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