PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/weblib.php

https://bitbucket.org/moodle/moodle
PHP | 3735 lines | 1915 code | 423 blank | 1397 comment | 426 complexity | 9df6525c0d06b08e56ca16fc3f9ee31c MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1, BSD-3-Clause, MIT, GPL-3.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');
  38. /**
  39. * Plain HTML (with some tags stripped).
  40. */
  41. define('FORMAT_HTML', '1');
  42. /**
  43. * Plain text (even tags are printed in full).
  44. */
  45. define('FORMAT_PLAIN', '2');
  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. * @deprecated since 2005!
  51. */
  52. define('FORMAT_WIKI', '3');
  53. /**
  54. * Markdown-formatted text http://daringfireball.net/projects/markdown/
  55. */
  56. define('FORMAT_MARKDOWN', '4');
  57. /**
  58. * A moodle_url comparison using this flag will return true if the base URLs match, params are ignored.
  59. */
  60. define('URL_MATCH_BASE', 0);
  61. /**
  62. * A moodle_url comparison using this flag will return true if the base URLs match and the params of url1 are part of url2.
  63. */
  64. define('URL_MATCH_PARAMS', 1);
  65. /**
  66. * A moodle_url comparison using this flag will return true if the two URLs are identical, except for the order of the params.
  67. */
  68. define('URL_MATCH_EXACT', 2);
  69. // Functions.
  70. /**
  71. * Add quotes to HTML characters.
  72. *
  73. * Returns $var with HTML characters (like "<", ">", etc.) properly quoted.
  74. * Related function {@link p()} simply prints the output of this function.
  75. *
  76. * @param string $var the string potentially containing HTML characters
  77. * @return string
  78. */
  79. function s($var) {
  80. if ($var === false) {
  81. return '0';
  82. }
  83. return preg_replace('/&amp;#(\d+|x[0-9a-f]+);/i', '&#$1;',
  84. htmlspecialchars($var, ENT_QUOTES | ENT_HTML401 | ENT_SUBSTITUTE));
  85. }
  86. /**
  87. * Add quotes to HTML characters.
  88. *
  89. * Prints $var with HTML characters (like "<", ">", etc.) properly quoted.
  90. * This function simply calls & displays {@link s()}.
  91. * @see s()
  92. *
  93. * @param string $var the string potentially containing HTML characters
  94. * @return string
  95. */
  96. function p($var) {
  97. echo s($var);
  98. }
  99. /**
  100. * Does proper javascript quoting.
  101. *
  102. * Do not use addslashes anymore, because it does not work when magic_quotes_sybase is enabled.
  103. *
  104. * @param mixed $var String, Array, or Object to add slashes to
  105. * @return mixed quoted result
  106. */
  107. function addslashes_js($var) {
  108. if (is_string($var)) {
  109. $var = str_replace('\\', '\\\\', $var);
  110. $var = str_replace(array('\'', '"', "\n", "\r", "\0"), array('\\\'', '\\"', '\\n', '\\r', '\\0'), $var);
  111. $var = str_replace('</', '<\/', $var); // XHTML compliance.
  112. } else if (is_array($var)) {
  113. $var = array_map('addslashes_js', $var);
  114. } else if (is_object($var)) {
  115. $a = get_object_vars($var);
  116. foreach ($a as $key => $value) {
  117. $a[$key] = addslashes_js($value);
  118. }
  119. $var = (object)$a;
  120. }
  121. return $var;
  122. }
  123. /**
  124. * Remove query string from url.
  125. *
  126. * Takes in a URL and returns it without the querystring portion.
  127. *
  128. * @param string $url the url which may have a query string attached.
  129. * @return string The remaining URL.
  130. */
  131. function strip_querystring($url) {
  132. if ($commapos = strpos($url, '?')) {
  133. return substr($url, 0, $commapos);
  134. } else {
  135. return $url;
  136. }
  137. }
  138. /**
  139. * Returns the name of the current script, WITH the querystring portion.
  140. *
  141. * This function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
  142. * return different things depending on a lot of things like your OS, Web
  143. * server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.)
  144. * <b>NOTE:</b> This function returns false if the global variables needed are not set.
  145. *
  146. * @return mixed String or false if the global variables needed are not set.
  147. */
  148. function me() {
  149. global $ME;
  150. return $ME;
  151. }
  152. /**
  153. * Guesses the full URL of the current script.
  154. *
  155. * This function is using $PAGE->url, but may fall back to $FULLME which
  156. * is constructed from PHP_SELF and REQUEST_URI or SCRIPT_NAME
  157. *
  158. * @return mixed full page URL string or false if unknown
  159. */
  160. function qualified_me() {
  161. global $FULLME, $PAGE, $CFG;
  162. if (isset($PAGE) and $PAGE->has_set_url()) {
  163. // This is the only recommended way to find out current page.
  164. return $PAGE->url->out(false);
  165. } else {
  166. if ($FULLME === null) {
  167. // CLI script most probably.
  168. return false;
  169. }
  170. if (!empty($CFG->sslproxy)) {
  171. // Return only https links when using SSL proxy.
  172. return preg_replace('/^http:/', 'https:', $FULLME, 1);
  173. } else {
  174. return $FULLME;
  175. }
  176. }
  177. }
  178. /**
  179. * Determines whether or not the Moodle site is being served over HTTPS.
  180. *
  181. * This is done simply by checking the value of $CFG->wwwroot, which seems
  182. * to be the only reliable method.
  183. *
  184. * @return boolean True if site is served over HTTPS, false otherwise.
  185. */
  186. function is_https() {
  187. global $CFG;
  188. return (strpos($CFG->wwwroot, 'https://') === 0);
  189. }
  190. /**
  191. * Returns the cleaned local URL of the HTTP_REFERER less the URL query string parameters if required.
  192. *
  193. * @param bool $stripquery if true, also removes the query part of the url.
  194. * @return string The resulting referer or empty string.
  195. */
  196. function get_local_referer($stripquery = true) {
  197. if (isset($_SERVER['HTTP_REFERER'])) {
  198. $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
  199. if ($stripquery) {
  200. return strip_querystring($referer);
  201. } else {
  202. return $referer;
  203. }
  204. } else {
  205. return '';
  206. }
  207. }
  208. /**
  209. * Class for creating and manipulating urls.
  210. *
  211. * It can be used in moodle pages where config.php has been included without any further includes.
  212. *
  213. * It is useful for manipulating urls with long lists of params.
  214. * One situation where it will be useful is a page which links to itself to perform various actions
  215. * and / or to process form data. A moodle_url object :
  216. * can be created for a page to refer to itself with all the proper get params being passed from page call to
  217. * page call and methods can be used to output a url including all the params, optionally adding and overriding
  218. * params and can also be used to
  219. * - output the url without any get params
  220. * - and output the params as hidden fields to be output within a form
  221. *
  222. * @copyright 2007 jamiesensei
  223. * @link http://docs.moodle.org/dev/lib/weblib.php_moodle_url See short write up here
  224. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  225. * @package core
  226. */
  227. class moodle_url {
  228. /**
  229. * Scheme, ex.: http, https
  230. * @var string
  231. */
  232. protected $scheme = '';
  233. /**
  234. * Hostname.
  235. * @var string
  236. */
  237. protected $host = '';
  238. /**
  239. * Port number, empty means default 80 or 443 in case of http.
  240. * @var int
  241. */
  242. protected $port = '';
  243. /**
  244. * Username for http auth.
  245. * @var string
  246. */
  247. protected $user = '';
  248. /**
  249. * Password for http auth.
  250. * @var string
  251. */
  252. protected $pass = '';
  253. /**
  254. * Script path.
  255. * @var string
  256. */
  257. protected $path = '';
  258. /**
  259. * Optional slash argument value.
  260. * @var string
  261. */
  262. protected $slashargument = '';
  263. /**
  264. * Anchor, may be also empty, null means none.
  265. * @var string
  266. */
  267. protected $anchor = null;
  268. /**
  269. * Url parameters as associative array.
  270. * @var array
  271. */
  272. protected $params = array();
  273. /**
  274. * Create new instance of moodle_url.
  275. *
  276. * @param moodle_url|string $url - moodle_url means make a copy of another
  277. * moodle_url and change parameters, string means full url or shortened
  278. * form (ex.: '/course/view.php'). It is strongly encouraged to not include
  279. * query string because it may result in double encoded values. Use the
  280. * $params instead. For admin URLs, just use /admin/script.php, this
  281. * class takes care of the $CFG->admin issue.
  282. * @param array $params these params override current params or add new
  283. * @param string $anchor The anchor to use as part of the URL if there is one.
  284. * @throws moodle_exception
  285. */
  286. public function __construct($url, array $params = null, $anchor = null) {
  287. global $CFG;
  288. if ($url instanceof moodle_url) {
  289. $this->scheme = $url->scheme;
  290. $this->host = $url->host;
  291. $this->port = $url->port;
  292. $this->user = $url->user;
  293. $this->pass = $url->pass;
  294. $this->path = $url->path;
  295. $this->slashargument = $url->slashargument;
  296. $this->params = $url->params;
  297. $this->anchor = $url->anchor;
  298. } else {
  299. // Detect if anchor used.
  300. $apos = strpos($url, '#');
  301. if ($apos !== false) {
  302. $anchor = substr($url, $apos);
  303. $anchor = ltrim($anchor, '#');
  304. $this->set_anchor($anchor);
  305. $url = substr($url, 0, $apos);
  306. }
  307. // Normalise shortened form of our url ex.: '/course/view.php'.
  308. if (strpos($url, '/') === 0) {
  309. $url = $CFG->wwwroot.$url;
  310. }
  311. if ($CFG->admin !== 'admin') {
  312. if (strpos($url, "$CFG->wwwroot/admin/") === 0) {
  313. $url = str_replace("$CFG->wwwroot/admin/", "$CFG->wwwroot/$CFG->admin/", $url);
  314. }
  315. }
  316. // Parse the $url.
  317. $parts = parse_url($url);
  318. if ($parts === false) {
  319. throw new moodle_exception('invalidurl');
  320. }
  321. if (isset($parts['query'])) {
  322. // Note: the values may not be correctly decoded, url parameters should be always passed as array.
  323. parse_str(str_replace('&amp;', '&', $parts['query']), $this->params);
  324. }
  325. unset($parts['query']);
  326. foreach ($parts as $key => $value) {
  327. $this->$key = $value;
  328. }
  329. // Detect slashargument value from path - we do not support directory names ending with .php.
  330. $pos = strpos($this->path, '.php/');
  331. if ($pos !== false) {
  332. $this->slashargument = substr($this->path, $pos + 4);
  333. $this->path = substr($this->path, 0, $pos + 4);
  334. }
  335. }
  336. $this->params($params);
  337. if ($anchor !== null) {
  338. $this->anchor = (string)$anchor;
  339. }
  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. * @throws coding_exception
  349. */
  350. public function params(array $params = null) {
  351. $params = (array)$params;
  352. foreach ($params as $key => $value) {
  353. if (is_int($key)) {
  354. throw new coding_exception('Url parameters can not have numeric keys!');
  355. }
  356. if (!is_string($value)) {
  357. if (is_array($value)) {
  358. throw new coding_exception('Url parameters values can not be arrays!');
  359. }
  360. if (is_object($value) and !method_exists($value, '__toString')) {
  361. throw new coding_exception('Url parameters values can not be objects, unless __toString() is defined!');
  362. }
  363. }
  364. $this->params[$key] = (string)$value;
  365. }
  366. return $this->params;
  367. }
  368. /**
  369. * Remove all params if no arguments passed.
  370. * Remove selected params if arguments are passed.
  371. *
  372. * Can be called as either remove_params('param1', 'param2')
  373. * or remove_params(array('param1', 'param2')).
  374. *
  375. * @param string[]|string $params,... either an array of param names, or 1..n string params to remove as args.
  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. *
  390. * @todo remove the unused param.
  391. * @param array $params Unused param
  392. * @return void
  393. */
  394. public function remove_all_params($params = null) {
  395. $this->params = array();
  396. $this->slashargument = '';
  397. }
  398. /**
  399. * Add a param to the params for this url.
  400. *
  401. * The added param overrides existing one if they have the same name.
  402. *
  403. * @param string $paramname name
  404. * @param string $newvalue Param value. If new value specified current value is overriden or parameter is added
  405. * @return mixed string parameter value, null if parameter does not exist
  406. */
  407. public function param($paramname, $newvalue = '') {
  408. if (func_num_args() > 1) {
  409. // Set new value.
  410. $this->params(array($paramname => $newvalue));
  411. }
  412. if (isset($this->params[$paramname])) {
  413. return $this->params[$paramname];
  414. } else {
  415. return null;
  416. }
  417. }
  418. /**
  419. * Merges parameters and validates them
  420. *
  421. * @param array $overrideparams
  422. * @return array merged parameters
  423. * @throws coding_exception
  424. */
  425. protected function merge_overrideparams(array $overrideparams = null) {
  426. $overrideparams = (array)$overrideparams;
  427. $params = $this->params;
  428. foreach ($overrideparams as $key => $value) {
  429. if (is_int($key)) {
  430. throw new coding_exception('Overridden parameters can not have numeric keys!');
  431. }
  432. if (is_array($value)) {
  433. throw new coding_exception('Overridden parameters values can not be arrays!');
  434. }
  435. if (is_object($value) and !method_exists($value, '__toString')) {
  436. throw new coding_exception('Overridden parameters values can not be objects, unless __toString() is defined!');
  437. }
  438. $params[$key] = (string)$value;
  439. }
  440. return $params;
  441. }
  442. /**
  443. * Get the params as as a query string.
  444. *
  445. * This method should not be used outside of this method.
  446. *
  447. * @param bool $escaped Use &amp; as params separator instead of plain &
  448. * @param array $overrideparams params to add to the output params, these
  449. * override existing ones with the same name.
  450. * @return string query string that can be added to a url.
  451. */
  452. public function get_query_string($escaped = true, array $overrideparams = null) {
  453. $arr = array();
  454. if ($overrideparams !== null) {
  455. $params = $this->merge_overrideparams($overrideparams);
  456. } else {
  457. $params = $this->params;
  458. }
  459. foreach ($params as $key => $val) {
  460. if (is_array($val)) {
  461. foreach ($val as $index => $value) {
  462. $arr[] = rawurlencode($key.'['.$index.']')."=".rawurlencode($value);
  463. }
  464. } else {
  465. if (isset($val) && $val !== '') {
  466. $arr[] = rawurlencode($key)."=".rawurlencode($val);
  467. } else {
  468. $arr[] = rawurlencode($key);
  469. }
  470. }
  471. }
  472. if ($escaped) {
  473. return implode('&amp;', $arr);
  474. } else {
  475. return implode('&', $arr);
  476. }
  477. }
  478. /**
  479. * Shortcut for printing of encoded URL.
  480. *
  481. * @return string
  482. */
  483. public function __toString() {
  484. return $this->out(true);
  485. }
  486. /**
  487. * Output url.
  488. *
  489. * If you use the returned URL in HTML code, you want the escaped ampersands. If you use
  490. * the returned URL in HTTP headers, you want $escaped=false.
  491. *
  492. * @param bool $escaped Use &amp; as params separator instead of plain &
  493. * @param array $overrideparams params to add to the output url, these override existing ones with the same name.
  494. * @return string Resulting URL
  495. */
  496. public function out($escaped = true, array $overrideparams = null) {
  497. global $CFG;
  498. if (!is_bool($escaped)) {
  499. debugging('Escape parameter must be of type boolean, '.gettype($escaped).' given instead.');
  500. }
  501. $url = $this;
  502. // Allow url's to be rewritten by a plugin.
  503. if (isset($CFG->urlrewriteclass) && !isset($CFG->upgraderunning)) {
  504. $class = $CFG->urlrewriteclass;
  505. $pluginurl = $class::url_rewrite($url);
  506. if ($pluginurl instanceof moodle_url) {
  507. $url = $pluginurl;
  508. }
  509. }
  510. return $url->raw_out($escaped, $overrideparams);
  511. }
  512. /**
  513. * Output url without any rewrites
  514. *
  515. * This is identical in signature and use to out() but doesn't call the rewrite handler.
  516. *
  517. * @param bool $escaped Use &amp; as params separator instead of plain &
  518. * @param array $overrideparams params to add to the output url, these override existing ones with the same name.
  519. * @return string Resulting URL
  520. */
  521. public function raw_out($escaped = true, array $overrideparams = null) {
  522. if (!is_bool($escaped)) {
  523. debugging('Escape parameter must be of type boolean, '.gettype($escaped).' given instead.');
  524. }
  525. $uri = $this->out_omit_querystring().$this->slashargument;
  526. $querystring = $this->get_query_string($escaped, $overrideparams);
  527. if ($querystring !== '') {
  528. $uri .= '?' . $querystring;
  529. }
  530. if (!is_null($this->anchor)) {
  531. $uri .= '#'.$this->anchor;
  532. }
  533. return $uri;
  534. }
  535. /**
  536. * Returns url without parameters, everything before '?'.
  537. *
  538. * @param bool $includeanchor if {@link self::anchor} is defined, should it be returned?
  539. * @return string
  540. */
  541. public function out_omit_querystring($includeanchor = false) {
  542. $uri = $this->scheme ? $this->scheme.':'.((strtolower($this->scheme) == 'mailto') ? '':'//'): '';
  543. $uri .= $this->user ? $this->user.($this->pass? ':'.$this->pass:'').'@':'';
  544. $uri .= $this->host ? $this->host : '';
  545. $uri .= $this->port ? ':'.$this->port : '';
  546. $uri .= $this->path ? $this->path : '';
  547. if ($includeanchor and !is_null($this->anchor)) {
  548. $uri .= '#' . $this->anchor;
  549. }
  550. return $uri;
  551. }
  552. /**
  553. * Compares this moodle_url with another.
  554. *
  555. * See documentation of constants for an explanation of the comparison flags.
  556. *
  557. * @param moodle_url $url The moodle_url object to compare
  558. * @param int $matchtype The type of comparison (URL_MATCH_BASE, URL_MATCH_PARAMS, URL_MATCH_EXACT)
  559. * @return bool
  560. */
  561. public function compare(moodle_url $url, $matchtype = URL_MATCH_EXACT) {
  562. $baseself = $this->out_omit_querystring();
  563. $baseother = $url->out_omit_querystring();
  564. // Append index.php if there is no specific file.
  565. if (substr($baseself, -1) == '/') {
  566. $baseself .= 'index.php';
  567. }
  568. if (substr($baseother, -1) == '/') {
  569. $baseother .= 'index.php';
  570. }
  571. // Compare the two base URLs.
  572. if ($baseself != $baseother) {
  573. return false;
  574. }
  575. if ($matchtype == URL_MATCH_BASE) {
  576. return true;
  577. }
  578. $urlparams = $url->params();
  579. foreach ($this->params() as $param => $value) {
  580. if ($param == 'sesskey') {
  581. continue;
  582. }
  583. if (!array_key_exists($param, $urlparams) || $urlparams[$param] != $value) {
  584. return false;
  585. }
  586. }
  587. if ($matchtype == URL_MATCH_PARAMS) {
  588. return true;
  589. }
  590. foreach ($urlparams as $param => $value) {
  591. if ($param == 'sesskey') {
  592. continue;
  593. }
  594. if (!array_key_exists($param, $this->params()) || $this->param($param) != $value) {
  595. return false;
  596. }
  597. }
  598. if ($url->anchor !== $this->anchor) {
  599. return false;
  600. }
  601. return true;
  602. }
  603. /**
  604. * Sets the anchor for the URI (the bit after the hash)
  605. *
  606. * @param string $anchor null means remove previous
  607. */
  608. public function set_anchor($anchor) {
  609. if (is_null($anchor)) {
  610. // Remove.
  611. $this->anchor = null;
  612. } else if ($anchor === '') {
  613. // Special case, used as empty link.
  614. $this->anchor = '';
  615. } else if (preg_match('|[a-zA-Z\_\:][a-zA-Z0-9\_\-\.\:]*|', $anchor)) {
  616. // Match the anchor against the NMTOKEN spec.
  617. $this->anchor = $anchor;
  618. } else {
  619. // Bad luck, no valid anchor found.
  620. $this->anchor = null;
  621. }
  622. }
  623. /**
  624. * Sets the scheme for the URI (the bit before ://)
  625. *
  626. * @param string $scheme
  627. */
  628. public function set_scheme($scheme) {
  629. // See http://www.ietf.org/rfc/rfc3986.txt part 3.1.
  630. if (preg_match('/^[a-zA-Z][a-zA-Z0-9+.-]*$/', $scheme)) {
  631. $this->scheme = $scheme;
  632. } else {
  633. throw new coding_exception('Bad URL scheme.');
  634. }
  635. }
  636. /**
  637. * Sets the url slashargument value.
  638. *
  639. * @param string $path usually file path
  640. * @param string $parameter name of page parameter if slasharguments not supported
  641. * @param bool $supported usually null, then it depends on $CFG->slasharguments, use true or false for other servers
  642. * @return void
  643. */
  644. public function set_slashargument($path, $parameter = 'file', $supported = null) {
  645. global $CFG;
  646. if (is_null($supported)) {
  647. $supported = !empty($CFG->slasharguments);
  648. }
  649. if ($supported) {
  650. $parts = explode('/', $path);
  651. $parts = array_map('rawurlencode', $parts);
  652. $path = implode('/', $parts);
  653. $this->slashargument = $path;
  654. unset($this->params[$parameter]);
  655. } else {
  656. $this->slashargument = '';
  657. $this->params[$parameter] = $path;
  658. }
  659. }
  660. // Static factory methods.
  661. /**
  662. * General moodle file url.
  663. *
  664. * @param string $urlbase the script serving the file
  665. * @param string $path
  666. * @param bool $forcedownload
  667. * @return moodle_url
  668. */
  669. public static function make_file_url($urlbase, $path, $forcedownload = false) {
  670. $params = array();
  671. if ($forcedownload) {
  672. $params['forcedownload'] = 1;
  673. }
  674. $url = new moodle_url($urlbase, $params);
  675. $url->set_slashargument($path);
  676. return $url;
  677. }
  678. /**
  679. * Factory method for creation of url pointing to plugin file.
  680. *
  681. * Please note this method can be used only from the plugins to
  682. * create urls of own files, it must not be used outside of plugins!
  683. *
  684. * @param int $contextid
  685. * @param string $component
  686. * @param string $area
  687. * @param int $itemid
  688. * @param string $pathname
  689. * @param string $filename
  690. * @param bool $forcedownload
  691. * @param mixed $includetoken Whether to use a user token when displaying this group image.
  692. * True indicates to generate a token for current user, and integer value indicates to generate a token for the
  693. * user whose id is the value indicated.
  694. * If the group picture is included in an e-mail or some other location where the audience is a specific
  695. * user who will not be logged in when viewing, then we use a token to authenticate the user.
  696. * @return moodle_url
  697. */
  698. public static function make_pluginfile_url($contextid, $component, $area, $itemid, $pathname, $filename,
  699. $forcedownload = false, $includetoken = false) {
  700. global $CFG, $USER;
  701. $path = [];
  702. if ($includetoken) {
  703. $urlbase = "$CFG->wwwroot/tokenpluginfile.php";
  704. $userid = $includetoken === true ? $USER->id : $includetoken;
  705. $token = get_user_key('core_files', $userid);
  706. if ($CFG->slasharguments) {
  707. $path[] = $token;
  708. }
  709. } else {
  710. $urlbase = "$CFG->wwwroot/pluginfile.php";
  711. }
  712. $path[] = $contextid;
  713. $path[] = $component;
  714. $path[] = $area;
  715. if ($itemid !== null) {
  716. $path[] = $itemid;
  717. }
  718. $path = "/" . implode('/', $path) . "{$pathname}{$filename}";
  719. $url = self::make_file_url($urlbase, $path, $forcedownload, $includetoken);
  720. if ($includetoken && empty($CFG->slasharguments)) {
  721. $url->param('token', $token);
  722. }
  723. return $url;
  724. }
  725. /**
  726. * Factory method for creation of url pointing to plugin file.
  727. * This method is the same that make_pluginfile_url but pointing to the webservice pluginfile.php script.
  728. * It should be used only in external functions.
  729. *
  730. * @since 2.8
  731. * @param int $contextid
  732. * @param string $component
  733. * @param string $area
  734. * @param int $itemid
  735. * @param string $pathname
  736. * @param string $filename
  737. * @param bool $forcedownload
  738. * @return moodle_url
  739. */
  740. public static function make_webservice_pluginfile_url($contextid, $component, $area, $itemid, $pathname, $filename,
  741. $forcedownload = false) {
  742. global $CFG;
  743. $urlbase = "$CFG->wwwroot/webservice/pluginfile.php";
  744. if ($itemid === null) {
  745. return self::make_file_url($urlbase, "/$contextid/$component/$area".$pathname.$filename, $forcedownload);
  746. } else {
  747. return self::make_file_url($urlbase, "/$contextid/$component/$area/$itemid".$pathname.$filename, $forcedownload);
  748. }
  749. }
  750. /**
  751. * Factory method for creation of url pointing to draft file of current user.
  752. *
  753. * @param int $draftid draft item id
  754. * @param string $pathname
  755. * @param string $filename
  756. * @param bool $forcedownload
  757. * @return moodle_url
  758. */
  759. public static function make_draftfile_url($draftid, $pathname, $filename, $forcedownload = false) {
  760. global $CFG, $USER;
  761. $urlbase = "$CFG->wwwroot/draftfile.php";
  762. $context = context_user::instance($USER->id);
  763. return self::make_file_url($urlbase, "/$context->id/user/draft/$draftid".$pathname.$filename, $forcedownload);
  764. }
  765. /**
  766. * Factory method for creating of links to legacy course files.
  767. *
  768. * @param int $courseid
  769. * @param string $filepath
  770. * @param bool $forcedownload
  771. * @return moodle_url
  772. */
  773. public static function make_legacyfile_url($courseid, $filepath, $forcedownload = false) {
  774. global $CFG;
  775. $urlbase = "$CFG->wwwroot/file.php";
  776. return self::make_file_url($urlbase, '/'.$courseid.'/'.$filepath, $forcedownload);
  777. }
  778. /**
  779. * Returns URL a relative path from $CFG->wwwroot
  780. *
  781. * Can be used for passing around urls with the wwwroot stripped
  782. *
  783. * @param boolean $escaped Use &amp; as params separator instead of plain &
  784. * @param array $overrideparams params to add to the output url, these override existing ones with the same name.
  785. * @return string Resulting URL
  786. * @throws coding_exception if called on a non-local url
  787. */
  788. public function out_as_local_url($escaped = true, array $overrideparams = null) {
  789. global $CFG;
  790. $url = $this->out($escaped, $overrideparams);
  791. // Url should be equal to wwwroot. If not then throw exception.
  792. if (($url === $CFG->wwwroot) || (strpos($url, $CFG->wwwroot.'/') === 0)) {
  793. $localurl = substr($url, strlen($CFG->wwwroot));
  794. return !empty($localurl) ? $localurl : '';
  795. } else {
  796. throw new coding_exception('out_as_local_url called on a non-local URL');
  797. }
  798. }
  799. /**
  800. * Returns the 'path' portion of a URL. For example, if the URL is
  801. * http://www.example.org:447/my/file/is/here.txt?really=1 then this will
  802. * return '/my/file/is/here.txt'.
  803. *
  804. * By default the path includes slash-arguments (for example,
  805. * '/myfile.php/extra/arguments') so it is what you would expect from a
  806. * URL path. If you don't want this behaviour, you can opt to exclude the
  807. * slash arguments. (Be careful: if the $CFG variable slasharguments is
  808. * disabled, these URLs will have a different format and you may need to
  809. * look at the 'file' parameter too.)
  810. *
  811. * @param bool $includeslashargument If true, includes slash arguments
  812. * @return string Path of URL
  813. */
  814. public function get_path($includeslashargument = true) {
  815. return $this->path . ($includeslashargument ? $this->slashargument : '');
  816. }
  817. /**
  818. * Returns a given parameter value from the URL.
  819. *
  820. * @param string $name Name of parameter
  821. * @return string Value of parameter or null if not set
  822. */
  823. public function get_param($name) {
  824. if (array_key_exists($name, $this->params)) {
  825. return $this->params[$name];
  826. } else {
  827. return null;
  828. }
  829. }
  830. /**
  831. * Returns the 'scheme' portion of a URL. For example, if the URL is
  832. * http://www.example.org:447/my/file/is/here.txt?really=1 then this will
  833. * return 'http' (without the colon).
  834. *
  835. * @return string Scheme of the URL.
  836. */
  837. public function get_scheme() {
  838. return $this->scheme;
  839. }
  840. /**
  841. * Returns the 'host' portion of a URL. For example, if the URL is
  842. * http://www.example.org:447/my/file/is/here.txt?really=1 then this will
  843. * return 'www.example.org'.
  844. *
  845. * @return string Host of the URL.
  846. */
  847. public function get_host() {
  848. return $this->host;
  849. }
  850. /**
  851. * Returns the 'port' portion of a URL. For example, if the URL is
  852. * http://www.example.org:447/my/file/is/here.txt?really=1 then this will
  853. * return '447'.
  854. *
  855. * @return string Port of the URL.
  856. */
  857. public function get_port() {
  858. return $this->port;
  859. }
  860. }
  861. /**
  862. * Determine if there is data waiting to be processed from a form
  863. *
  864. * Used on most forms in Moodle to check for data
  865. * Returns the data as an object, if it's found.
  866. * This object can be used in foreach loops without
  867. * casting because it's cast to (array) automatically
  868. *
  869. * Checks that submitted POST data exists and returns it as object.
  870. *
  871. * @return mixed false or object
  872. */
  873. function data_submitted() {
  874. if (empty($_POST)) {
  875. return false;
  876. } else {
  877. return (object)fix_utf8($_POST);
  878. }
  879. }
  880. /**
  881. * Given some normal text this function will break up any
  882. * long words to a given size by inserting the given character
  883. *
  884. * It's multibyte savvy and doesn't change anything inside html tags.
  885. *
  886. * @param string $string the string to be modified
  887. * @param int $maxsize maximum length of the string to be returned
  888. * @param string $cutchar the string used to represent word breaks
  889. * @return string
  890. */
  891. function break_up_long_words($string, $maxsize=20, $cutchar=' ') {
  892. // First of all, save all the tags inside the text to skip them.
  893. $tags = array();
  894. filter_save_tags($string, $tags);
  895. // Process the string adding the cut when necessary.
  896. $output = '';
  897. $length = core_text::strlen($string);
  898. $wordlength = 0;
  899. for ($i=0; $i<$length; $i++) {
  900. $char = core_text::substr($string, $i, 1);
  901. if ($char == ' ' or $char == "\t" or $char == "\n" or $char == "\r" or $char == "<" or $char == ">") {
  902. $wordlength = 0;
  903. } else {
  904. $wordlength++;
  905. if ($wordlength > $maxsize) {
  906. $output .= $cutchar;
  907. $wordlength = 0;
  908. }
  909. }
  910. $output .= $char;
  911. }
  912. // Finally load the tags back again.
  913. if (!empty($tags)) {
  914. $output = str_replace(array_keys($tags), $tags, $output);
  915. }
  916. return $output;
  917. }
  918. /**
  919. * Try and close the current window using JavaScript, either immediately, or after a delay.
  920. *
  921. * Echo's out the resulting XHTML & javascript
  922. *
  923. * @param integer $delay a delay in seconds before closing the window. Default 0.
  924. * @param boolean $reloadopener if true, we will see if this window was a pop-up, and try
  925. * to reload the parent window before this one closes.
  926. */
  927. function close_window($delay = 0, $reloadopener = false) {
  928. global $PAGE, $OUTPUT;
  929. if (!$PAGE->headerprinted) {
  930. $PAGE->set_title(get_string('closewindow'));
  931. echo $OUTPUT->header();
  932. } else {
  933. $OUTPUT->container_end_all(false);
  934. }
  935. if ($reloadopener) {
  936. // Trigger the reload immediately, even if the reload is after a delay.
  937. $PAGE->requires->js_function_call('window.opener.location.reload', array(true));
  938. }
  939. $OUTPUT->notification(get_string('windowclosing'), 'notifysuccess');
  940. $PAGE->requires->js_function_call('close_window', array(new stdClass()), false, $delay);
  941. echo $OUTPUT->footer();
  942. exit;
  943. }
  944. /**
  945. * Returns a string containing a link to the user documentation for the current page.
  946. *
  947. * Also contains an icon by default. Shown to teachers and admin only.
  948. *
  949. * @param string $text The text to be displayed for the link
  950. * @return string The link to user documentation for this current page
  951. */
  952. function page_doc_link($text='') {
  953. global $OUTPUT, $PAGE;
  954. $path = page_get_doc_link_path($PAGE);
  955. if (!$path) {
  956. return '';
  957. }
  958. return $OUTPUT->doc_link($path, $text);
  959. }
  960. /**
  961. * Returns the path to use when constructing a link to the docs.
  962. *
  963. * @since Moodle 2.5.1 2.6
  964. * @param moodle_page $page
  965. * @return string
  966. */
  967. function page_get_doc_link_path(moodle_page $page) {
  968. global $CFG;
  969. if (empty($CFG->docroot) || during_initial_install()) {
  970. return '';
  971. }
  972. if (!has_capability('moodle/site:doclinks', $page->context)) {
  973. return '';
  974. }
  975. $path = $page->docspath;
  976. if (!$path) {
  977. return '';
  978. }
  979. return $path;
  980. }
  981. /**
  982. * Validates an email to make sure it makes sense.
  983. *
  984. * @param string $address The email address to validate.
  985. * @return boolean
  986. */
  987. function validate_email($address) {
  988. global $CFG;
  989. require_once($CFG->libdir.'/phpmailer/moodle_phpmailer.php');
  990. return moodle_phpmailer::validateAddress($address) && !preg_match('/[<>]/', $address);
  991. }
  992. /**
  993. * Extracts file argument either from file parameter or PATH_INFO
  994. *
  995. * Note: $scriptname parameter is not needed anymore
  996. *
  997. * @return string file path (only safe characters)
  998. */
  999. function get_file_argument() {
  1000. global $SCRIPT;
  1001. $relativepath = false;
  1002. $hasforcedslashargs = false;
  1003. if (isset($_SERVER['REQUEST_URI']) && !empty($_SERVER['REQUEST_URI'])) {
  1004. // Checks whether $_SERVER['REQUEST_URI'] contains '/pluginfile.php/'
  1005. // instead of '/pluginfile.php?', when serving a file from e.g. mod_imscp or mod_scorm.
  1006. if ((strpos($_SERVER['REQUEST_URI'], '/pluginfile.php/') !== false)
  1007. && isset($_SERVER['PATH_INFO']) && !empty($_SERVER['PATH_INFO'])) {
  1008. // Exclude edge cases like '/pluginfile.php/?file='.
  1009. $args = explode('/', ltrim($_SERVER['PATH_INFO'], '/'));
  1010. $hasforcedslashargs = (count($args) > 2); // Always at least: context, component and filearea.
  1011. }
  1012. }
  1013. if (!$hasforcedslashargs) {
  1014. $relativepath = optional_param('file', false, PARAM_PATH);
  1015. }
  1016. if ($relativepath !== false and $relativepath !== '') {
  1017. return $relativepath;
  1018. }
  1019. $relativepath = false;
  1020. // Then try extract file from the slasharguments.
  1021. if (stripos($_SERVER['SERVER_SOFTWARE'], 'iis') !== false) {
  1022. // NOTE: IIS tends to convert all file paths to single byte DOS encoding,
  1023. // we can not use other methods because they break unicode chars,
  1024. // the only ways are to use URL rewriting
  1025. // OR
  1026. // to properly set the 'FastCGIUtf8ServerVariables' registry key.
  1027. if (isset($_SERVER['PATH_INFO']) and $_SERVER['PATH_INFO'] !== '') {
  1028. // Check that PATH_INFO works == must not contain the script name.
  1029. if (strpos($_SERVER['PATH_INFO'], $SCRIPT) === false) {
  1030. $relativepath = clean_param(urldecode($_SERVER['PATH_INFO']), PARAM_PATH);
  1031. }
  1032. }
  1033. } else {
  1034. // All other apache-like servers depend on PATH_INFO.
  1035. if (isset($_SERVER['PATH_INFO'])) {
  1036. if (isset($_SERVER['SCRIPT_NAME']) and strpos($_SERVER['PATH_INFO'], $_SERVER['SCRIPT_NAME']) === 0) {
  1037. $relativepath = substr($_SERVER['PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
  1038. } else {
  1039. $relativepath = $_SERVER['PATH_INFO'];
  1040. }
  1041. $relativepath = clean_param($relativepath, PARAM_PATH);
  1042. }
  1043. }
  1044. return $relativepath;
  1045. }
  1046. /**
  1047. * Just returns an array of text formats suitable for a popup menu
  1048. *
  1049. * @return array
  1050. */
  1051. function format_text_menu() {
  1052. return array (FORMAT_MOODLE => get_string('formattext'),
  1053. FORMAT_HTML => get_string('formathtml'),
  1054. FORMAT_PLAIN => get_string('formatplain'),
  1055. FORMAT_MARKDOWN => get_string('formatmarkdown'));
  1056. }
  1057. /**
  1058. * Given text in a variety of format codings, this function returns the text as safe HTML.
  1059. *
  1060. * This function should mainly be used for long strings like posts,
  1061. * answers, glossary items etc. For short strings {@link format_string()}.
  1062. *
  1063. * <pre>
  1064. * Options:
  1065. * trusted : If true the string won't be cleaned. Default false required noclean=true.
  1066. * noclean : If true the string won't be cleaned, unless $CFG->forceclean is set. Default false required trusted=true.
  1067. * nocache : If true the strign will not be cached and will be formatted every call. Default false.
  1068. * filter : If true the string will be run through applicable filters as well. Default true.
  1069. * para : If true then the returned string will be wrapped in div tags. Default true.
  1070. * newlines : If true then lines newline breaks will be converted to HTML newline breaks. Default true.
  1071. * context : The context that will be used for filtering.
  1072. * overflowdiv : If set to true the formatted text will be encased in a div
  1073. * with the class no-overflow before being returned. Default false.
  1074. * allowid : If true then id attributes will not be removed, even when
  1075. * using htmlpurifier. Default false.
  1076. * blanktarget : If true all <a> tags will have target="_blank" added unless target is explicitly specified.
  1077. * </pre>
  1078. *
  1079. * @staticvar array $croncache
  1080. * @param string $text The text to be formatted. This is raw text originally from user input.
  1081. * @param int $format Identifier of the text format to be used
  1082. * [FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_MARKDOWN]
  1083. * @param object/array $options text formatting options
  1084. * @param int $courseiddonotuse deprecated course id, use context option instead
  1085. * @return string
  1086. */
  1087. function format_text($text, $format = FORMAT_MOODLE, $options = null, $courseiddonotuse = null) {
  1088. global $CFG, $DB, $PAGE;
  1089. if ($text === '' || is_null($text)) {
  1090. // No need to do any filters and cleaning.
  1091. return '';
  1092. }
  1093. // Detach object, we can not modify it.
  1094. $options = (array)$options;
  1095. if (!isset($options['trusted'])) {
  1096. $options['trusted'] = false;
  1097. }
  1098. if (!isset($options['noclean'])) {
  1099. if ($options['trusted'] and trusttext_active()) {
  1100. // No cleaning if text trusted and noclean not specified.
  1101. $options['noclean'] = true;
  1102. } else {
  1103. $options['noclean'] = false;
  1104. }
  1105. }
  1106. if (!empty($CFG->forceclean)) {
  1107. // Whatever the caller claims, the admin wants all content cleaned anyway.
  1108. $options['noclean'] = false;
  1109. }
  1110. if (!isset($options['nocache'])) {
  1111. $options['nocache'] = false;
  1112. }
  1113. if (!isset($options['filter'])) {
  1114. $options['filter'] = true;
  1115. }
  1116. if (!isset($options['para'])) {
  1117. $options['para'] = true;
  1118. }
  1119. if (!isset($options['newlines'])) {
  1120. $options['newlines'] = true;
  1121. }
  1122. if (!isset($options['overflowdiv'])) {
  1123. $options['overflowdiv'] = false;
  1124. }
  1125. $options['blanktarget'] = !empty($options['blanktarget']);
  1126. // Calculate best context.
  1127. if (empty($CFG->version) or $CFG->version < 2013051400 or during_initial_install()) {
  1128. // Do not filter anything during installation or before upgrade completes.
  1129. $context = null;
  1130. } else if (isset($options['context'])) { // First by explicit passed context option.
  1131. if (is_object($options['context'])) {
  1132. $context = $options['context'];
  1133. } else {
  1134. $context = context::instance_by_id($options['context']);
  1135. }
  1136. } else if ($courseiddonotuse) {
  1137. // Legacy courseid.
  1138. $context = context_course::instance($courseiddonotuse);
  1139. } else {
  1140. // Fallback to $PAGE->context this may be problematic in CLI and other non-standard pages :-(.
  1141. $context = $PAGE->context;
  1142. }
  1143. if (!$context) {
  1144. // Either install/upgrade or something has gone really wrong because context does not exist (yet?).
  1145. $options['nocache'] = true;
  1146. $options['filter'] = false;
  1147. }
  1148. if ($options['filter']) {
  1149. $filtermanager = filter_manager::instance();
  1150. $filtermanager->setup_page_for_filters($PAGE, $context); // Setup global stuff filters may have.
  1151. $filteroptions = array(
  1152. 'originalformat' => $format,
  1153. 'noclean' => $options['noclean'],
  1154. );
  1155. } else {
  1156. $filtermanager = new null_filter_manager();
  1157. $filteroptions = array();
  1158. }
  1159. switch ($format) {
  1160. case FORMAT_HTML:
  1161. if (!$options['noclean']) {
  1162. $text = clean_text($text, FORMAT_HTML, $options);
  1163. }
  1164. $text = $filtermanager->filter_text($text, $context, $filteroptions);
  1165. break;
  1166. case FORMAT_PLAIN:
  1167. $text = s($text); // Cleans dangerous JS.
  1168. $text = rebuildnolinktag($text);
  1169. $text = str_replace(' ', '&nbsp; ', $text);
  1170. $text = nl2br($text);
  1171. break;
  1172. case FORMAT_WIKI:
  1173. // This format is deprecated.
  1174. $text = '<p>NOTICE: Wiki-like formatting has been removed from Moodle. You should not be seeing
  1175. this message as all texts should have been converted to Markdown format instead.
  1176. Please post a bug report to http://moodle.org/bugs with information about where you
  1177. saw this message.</p>'.s($text);
  1178. break;
  1179. case FORMAT_MARKDOWN:
  1180. $text = markdown_to_html($text);
  1181. if (!$options['noclean']) {
  1182. $text = clean_text($text, FORMAT_HTML, $options);
  1183. }
  1184. $text = $filtermanager->filter_text($text, $context, $filteroptions);
  1185. break;
  1186. default: // FORMAT_MOODLE or anything else.
  1187. $text = text_to_html($text, null, $options['para'], $options['newlines']);
  1188. if (!$options['noclean']) {
  1189. $text = clean_text($text, FORMAT_HTML, $options);
  1190. }
  1191. $text = $filtermanager->filter_text($text, $context, $filteroptions);
  1192. break;
  1193. }
  1194. if ($options['filter']) {
  1195. // At this point there should not be any draftfile links any more,
  1196. // this happens when developers forget to post process the text.
  1197. // The only potential problem is that somebody might try to format
  1198. // the text before storing into database which would be itself big bug..
  1199. $text = str_replace("\"$CFG->wwwroot/draftfile.php", "\"$CFG->wwwroot/brokenfile.php#", $text);
  1200. if ($CFG->debugdeveloper) {
  1201. if (strpos($text, '@@PLUGINFILE@@/') !== false) {
  1202. debugging('Before calling format_text(), the content must be processed with file_rewrite_pluginfile_urls()',
  1203. DEBUG_DEVELOPER);
  1204. }
  1205. }
  1206. }
  1207. if (!empty($options['overflowdiv'])) {
  1208. $text = html_writer::tag('div', $text, array('class' => 'no-overflow'));
  1209. }
  1210. if ($options['blanktarget']) {
  1211. $domdoc = new DOMDocument();
  1212. libxml_use_internal_errors(true);
  1213. $domdoc->loadHTML('<?xml version="1.0" encoding="UTF-8" ?>' . $text);
  1214. libxml_clear_errors();
  1215. foreach ($domdoc->getElementsByTagName('a') as $link) {
  1216. if ($link->hasAttribute('target') && strpos($link->getAttribute('target'), '_blank') === false) {
  1217. continue;
  1218. }
  1219. $link->setAttribute('target', '_blank');
  1220. if (strpos($link->getAttribute('rel'), 'noreferrer') === false) {
  1221. $link->setAttribute('rel', trim($link->getAttribute('rel') . ' noreferrer'));
  1222. }
  1223. }
  1224. // This regex is nasty and I don't like it. The correct way to solve this is by loading the HTML like so:
  1225. // $domdoc->loadHTML($text, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); however it seems like the libxml
  1226. // version that travis uses doesn't work properly and ends up leaving <html><body>, so I'm forced to use
  1227. // this regex to remove those tags.
  1228. $text = trim(preg_replace('~<(?:!DOCTYPE|/?(?:html|body))[^>]*>\s*~i', '', $domdoc->saveHTML($domdoc->documentElement)));
  1229. }
  1230. return $text;
  1231. }
  1232. /**
  1233. * Resets some data related to filters, called during upgrade or when general filter settings change.
  1234. *
  1235. * @param bool $phpunitreset true means called from our PHPUnit integration test reset
  1236. * @return void
  1237. */
  1238. function reset_text_filters_cache($phpunitreset = false) {
  1239. global $CFG, $DB;
  1240. if ($phpunitreset) {
  1241. // HTMLPurifier does not change, DB is already reset to defaults,
  1242. // nothing to do here, the dataroot was cleared too.
  1243. return;
  1244. }
  1245. // The purge_all_caches() deals with cachedir and localcachedir purging,
  1246. // the individual filter caches are invalidated as necessary elsewhere.
  1247. // Update $CFG->filterall cache flag.
  1248. if (empty($CFG->stringfilters)) {
  1249. set_config('filterall', 0);
  1250. return;
  1251. }
  1252. $installedfilters = core_component::get_plugin_list('filter');
  1253. $filters = explode(',', $CFG->stringfilters);
  1254. foreach ($filters as $filter) {
  1255. if (isset($installedfilters[$filter])) {
  1256. set_config('filterall', 1);
  1257. return;
  1258. }
  1259. }
  1260. set_config('filterall', 0);
  1261. }
  1262. /**
  1263. * Given a simple string, this function returns the string
  1264. * processed by enabled string filters if $CFG->filterall is enabled
  1265. *
  1266. * This function should be used to print short strings (non html) that
  1267. * need filter processing e.g. activity titles, post subjects,
  1268. * glossary concepts.
  1269. *
  1270. * @staticvar bool $strcache
  1271. * @param string $string The string to be filtered. Should be plain text, expect
  1272. * possibly for multilang tags.
  1273. * @param boolean $striplinks To strip any link in the result text. Moodle 1.8 default changed from false to true! MDL-8713
  1274. * @param array $options options array/object or courseid
  1275. * @return string
  1276. */
  1277. function format_string($string, $striplinks = true, $options = null) {
  1278. global $CFG, $PAGE;
  1279. // We'll use a in-memory cache here to speed up repeated strings.
  1280. static $strcache = false;
  1281. if (empty($CFG->version) or $CFG->version < 2013051400 or during_initial_install()) {
  1282. // Do not filter anything during installation or before upgrade completes.
  1283. return $string = strip_tags($string);
  1284. }
  1285. if ($strcache === false or count($strcache) > 2000) {
  1286. // This number might need some tuning to limit memory usage in cron.
  1287. $strcache = array();
  1288. }
  1289. if (is_numeric($options)) {
  1290. // Legacy courseid usage.
  1291. $options = array('context' => context_course::instance($options));
  1292. } else {
  1293. // Detach object, we can not modify it.
  1294. $options = (array)$options;
  1295. }
  1296. if (empty($options['context'])) {
  1297. // Fallback to $PAGE->context this may be problematic in CLI and other non-standard pages :-(.
  1298. $options['context'] = $PAGE->context;
  1299. } else if (is_numeric($options['context'])) {
  1300. $options['context'] = context::instance_by_id($options['context']);
  1301. }
  1302. if (!isset($options['filter'])) {
  1303. $options['filter'] = true;
  1304. }
  1305. $option

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