[moodle] / moodle / lib / weblib.php Repository:

Annotation of /moodle/lib/weblib.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1339 - (view) (download)

1 : samhemelryk 1.1255 <?php
2 : martin 1.1
3 : samhemelryk 1.1257 // This file is part of Moodle - http://moodle.org/
4 :     //
5 : samhemelryk 1.1255 // Moodle is free software: you can redistribute it and/or modify
6 :     // it under the terms of the GNU General Public License as published by
7 :     // the Free Software Foundation, either version 3 of the License, or
8 :     // (at your option) any later version.
9 :     //
10 :     // Moodle is distributed in the hope that it will be useful,
11 :     // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 :     // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 :     // GNU General Public License for more details.
14 : samhemelryk 1.1257 //
15 : samhemelryk 1.1255 // You should have received a copy of the GNU General Public License
16 :     // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 : martin 1.1
18 : dhawes 1.302 /**
19 :     * Library of functions for web output
20 :     *
21 :     * Library of all general-purpose Moodle PHP functions and constants
22 :     * that produce HTML output
23 :     *
24 :     * Other main libraries:
25 :     * - datalib.php - functions that access the database.
26 :     * - moodlelib.php - general-purpose Moodle functions.
27 : samhemelryk 1.1255 *
28 : samhemelryk 1.1257 * @package moodlecore
29 : samhemelryk 1.1255 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
30 :     * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31 : dhawes 1.302 */
32 : urs_hunkler 1.347
33 : moodler 1.23 /// Constants
34 :    
35 : moodler 1.30 /// Define text formatting types ... eventually we can add Wiki, BBcode etc
36 : dhawes 1.302
37 :     /**
38 :     * Does all sorts of transformations and filtering
39 :     */
40 : dhawes 1.301 define('FORMAT_MOODLE', '0'); // Does all sorts of transformations and filtering
41 : dhawes 1.302
42 :     /**
43 :     * Plain HTML (with some tags stripped)
44 :     */
45 : dhawes 1.301 define('FORMAT_HTML', '1'); // Plain HTML (with some tags stripped)
46 : dhawes 1.302
47 :     /**
48 :     * Plain text (even tags are printed in full)
49 :     */
50 : dhawes 1.301 define('FORMAT_PLAIN', '2'); // Plain text (even tags are printed in full)
51 : dhawes 1.302
52 :     /**
53 :     * Wiki-formatted text
54 : thepurpleblob 1.441 * Deprecated: left here just to note that '3' is not used (at the moment)
55 :     * and to catch any latent wiki-like text (which generates an error)
56 : dhawes 1.302 */
57 : dhawes 1.301 define('FORMAT_WIKI', '3'); // Wiki-formatted text
58 : dhawes 1.302
59 :     /**
60 :     * Markdown-formatted text http://daringfireball.net/projects/markdown/
61 :     */
62 : dhawes 1.301 define('FORMAT_MARKDOWN', '4'); // Markdown-formatted text http://daringfireball.net/projects/markdown/
63 : moodler 1.23
64 : skodak 1.615 /**
65 :     * TRUSTTEXT marker - if present in text, text cleaning should be bypassed
66 :     */
67 :     define('TRUSTTEXT', '#####TRUSTTEXT#####');
68 :    
69 : nicolasconnault 1.1324 /**
70 :     * A moodle_url comparison using this flag will return true if the base URLs match, params are ignored
71 :     */
72 :     define('URL_MATCH_BASE', 0);
73 :     /**
74 :     * A moodle_url comparison using this flag will return true if the base URLs match and the params of url1 are part of url2
75 :     */
76 :     define('URL_MATCH_PARAMS', 1);
77 :     /**
78 : nicolasconnault 1.1325 * A moodle_url comparison using this flag will return true if the two URLs are identical, except for the order of the params
79 : nicolasconnault 1.1324 */
80 :     define('URL_MATCH_EXACT', 2);
81 : dhawes 1.302
82 :     /**
83 :     * Allowed tags - string of html tags that can be tested against for safe html tags
84 :     * @global string $ALLOWED_TAGS
85 : samhemelryk 1.1255 * @name $ALLOWED_TAGS
86 : dhawes 1.302 */
87 : tjhunt 1.868 global $ALLOWED_TAGS;
88 : moodler 1.166 $ALLOWED_TAGS =
89 : skodak 1.1114 '<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>';
90 : moodler 1.471
91 : moodler 1.310 /**
92 :     * Allowed protocols - array of protocols that are safe to use in links and so on
93 :     * @global string $ALLOWED_PROTOCOLS
94 : samhemelryk 1.1255 * @name $ALLOWED_PROTOCOLS
95 : moodler 1.310 */
96 : moodler 1.470 $ALLOWED_PROTOCOLS = array('http', 'https', 'ftp', 'news', 'mailto', 'rtsp', 'teamspeak', 'gopher', 'mms',
97 : stronk7 1.1124 'color', 'callto', 'cursor', 'text-align', 'font-size', 'font-weight', 'font-style', 'font-family',
98 : ericmerrill 1.1181 'border', 'margin', 'padding', 'background', 'background-color', 'text-decoration'); // CSS as well to get through kses
99 : moodler 1.310
100 :    
101 : moodler 1.23 /// Functions
102 :    
103 : dhawes 1.302 /**
104 :     * Add quotes to HTML characters
105 :     *
106 :     * Returns $var with HTML characters (like "<", ">", etc.) properly quoted.
107 :     * This function is very similar to {@link p()}
108 :     *
109 : samhemelryk 1.1255 * @todo Remove obsolete param $obsolete if not used anywhere
110 :     *
111 : dhawes 1.302 * @param string $var the string potentially containing HTML characters
112 : tjhunt 1.1223 * @param boolean $obsolete no longer used.
113 : dhawes 1.302 * @return string
114 :     */
115 : tjhunt 1.1223 function s($var, $obsolete = false) {
116 : stronk7 1.572
117 : skodak 1.483 if ($var == '0') { // for integer 0, boolean false, string '0'
118 :     return '0';
119 : moodler 1.103 }
120 : stronk7 1.572
121 : tjhunt 1.1224 return preg_replace("/&amp;(#\d+);/i", "&$1;", htmlspecialchars($var));
122 : martin 1.1 }
123 :    
124 : dhawes 1.302 /**
125 :     * Add quotes to HTML characters
126 :     *
127 : dhawes 1.304 * Prints $var with HTML characters (like "<", ">", etc.) properly quoted.
128 : samhemelryk 1.1255 * This function simply calls {@link s()}
129 :     * @see s()
130 :     *
131 :     * @todo Remove obsolete param $obsolete if not used anywhere
132 : dhawes 1.302 *
133 :     * @param string $var the string potentially containing HTML characters
134 : tjhunt 1.1223 * @param boolean $obsolete no longer used.
135 : dhawes 1.302 * @return string
136 :     */
137 : tjhunt 1.1223 function p($var, $obsolete = false) {
138 :     echo s($var, $obsolete);
139 : martin 1.1 }
140 :    
141 : skodak 1.721 /**
142 :     * Does proper javascript quoting.
143 : samhemelryk 1.1255 *
144 : jamiesensei 1.739 * Do not use addslashes anymore, because it does not work when magic_quotes_sybase is enabled.
145 :     *
146 : samhemelryk 1.1255 * @param mixed $var String, Array, or Object to add slashes to
147 : skodak 1.721 * @return mixed quoted result
148 :     */
149 :     function addslashes_js($var) {
150 :     if (is_string($var)) {
151 :     $var = str_replace('\\', '\\\\', $var);
152 :     $var = str_replace(array('\'', '"', "\n", "\r", "\0"), array('\\\'', '\\"', '\\n', '\\r', '\\0'), $var);
153 : skodak 1.722 $var = str_replace('</', '<\/', $var); // XHTML compliance
154 : skodak 1.721 } else if (is_array($var)) {
155 :     $var = array_map('addslashes_js', $var);
156 :     } else if (is_object($var)) {
157 :     $a = get_object_vars($var);
158 :     foreach ($a as $key=>$value) {
159 :     $a[$key] = addslashes_js($value);
160 :     }
161 :     $var = (object)$a;
162 :     }
163 :     return $var;
164 :     }
165 : dhawes 1.302
166 :     /**
167 :     * Remove query string from url
168 :     *
169 :     * Takes in a URL and returns it without the querystring portion
170 :     *
171 :     * @param string $url the url which may have a query string attached
172 : samhemelryk 1.1255 * @return string The remaining URL
173 : dhawes 1.302 */
174 :     function strip_querystring($url) {
175 : martin 1.1
176 : moodler 1.43 if ($commapos = strpos($url, '?')) {
177 :     return substr($url, 0, $commapos);
178 :     } else {
179 :     return $url;
180 :     }
181 : martin 1.1 }
182 :    
183 : dhawes 1.302 /**
184 : moodler 1.835 * Returns the URL of the HTTP_REFERER, less the querystring portion if required
185 : samhemelryk 1.1255 *
186 :     * @uses $_SERVER
187 : scyrma 1.1026 * @param boolean $stripquery if true, also removes the query part of the url.
188 : samhemelryk 1.1255 * @return string The resulting referer or emtpy string
189 : dhawes 1.302 */
190 : moodler 1.835 function get_referer($stripquery=true) {
191 : skodak 1.720 if (isset($_SERVER['HTTP_REFERER'])) {
192 : moodler 1.835 if ($stripquery) {
193 :     return strip_querystring($_SERVER['HTTP_REFERER']);
194 :     } else {
195 :     return $_SERVER['HTTP_REFERER'];
196 :     }
197 : skodak 1.720 } else {
198 : jamiesensei 1.739 return '';
199 : skodak 1.720 }
200 : martin 1.1 }
201 :    
202 : moodler 1.30
203 : dhawes 1.302 /**
204 :     * Returns the name of the current script, WITH the querystring portion.
205 : samhemelryk 1.1255 *
206 :     * This function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
207 : dhawes 1.302 * return different things depending on a lot of things like your OS, Web
208 :     * server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.)
209 : dhawes 1.304 * <b>NOTE:</b> This function returns false if the global variables needed are not set.
210 :     *
211 : samhemelryk 1.1255 * @global string
212 :     * @return mixed String, or false if the global variables needed are not set
213 : dhawes 1.302 */
214 : moodler 1.1266 function me() {
215 :     global $ME;
216 :     return $ME;
217 : martin 1.1 }
218 :    
219 : dhawes 1.302 /**
220 : samhemelryk 1.1255 * Returns the name of the current script, WITH the full URL.
221 :     *
222 :     * This function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
223 :     * return different things depending on a lot of things like your OS, Web
224 :     * server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.
225 :     * <b>NOTE:</b> This function returns false if the global variables needed are not set.
226 :     *
227 : dhawes 1.304 * Like {@link me()} but returns a full URL
228 : dhawes 1.302 * @see me()
229 : samhemelryk 1.1255 *
230 :     * @global string
231 :     * @return mixed String, or false if the global variables needed are not set
232 : dhawes 1.302 */
233 : martin 1.1 function qualified_me() {
234 : skodak 1.1198 global $FULLME;
235 :     return $FULLME;
236 : martin 1.1 }
237 :    
238 : jamiesensei 1.874 /**
239 :     * Class for creating and manipulating urls.
240 : jamiesensei 1.894 *
241 : samhemelryk 1.1255 * It can be used in moodle pages where config.php has been included without any further includes.
242 :     *
243 : nicolasconnault 1.1314 * It is useful for manipulating urls with long lists of params.
244 :     * One situation where it will be useful is a page which links to itself to perfrom various actions
245 : samhemelryk 1.1255 * and / or to process form data. A moodle_url object :
246 : nicolasconnault 1.1314 * can be created for a page to refer to itself with all the proper get params being passed from page call to
247 :     * page call and methods can be used to output a url including all the params, optionally adding and overriding
248 : samhemelryk 1.1255 * params and can also be used to
249 :     * - output the url without any get params
250 : nicolasconnault 1.1314 * - and output the params as hidden fields to be output within a form
251 : samhemelryk 1.1255 *
252 :     * One important usage note is that data passed to methods out, out_action, get_query_string and
253 : nicolasconnault 1.1314 * hidden_params_out affect what is returned by the function and do not change the data stored in the object.
254 :     * This is to help with typical usage of these objects where one object is used to output urls
255 :     * in many places in a page.
256 : samhemelryk 1.1255 *
257 :     * @link http://docs.moodle.org/en/Development:lib/weblib.php_moodle_url See short write up here
258 :     * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
259 :     * @package moodlecore
260 : jamiesensei 1.874 */
261 :     class moodle_url {
262 : samhemelryk 1.1255 /**
263 :     * @var string
264 :     * @access protected
265 :     */
266 : tjhunt 1.1243 protected $scheme = ''; // e.g. http
267 :     protected $host = '';
268 :     protected $port = '';
269 :     protected $user = '';
270 :     protected $pass = '';
271 :     protected $path = '';
272 :     protected $fragment = '';
273 : samhemelryk 1.1255 /**
274 : nicolasconnault 1.1314 * @var array
275 : samhemelryk 1.1255 * @access protected
276 :     */
277 : tjhunt 1.1243 protected $params = array(); // Associative array of query string params
278 : jamiesensei 1.894
279 : jamiesensei 1.874 /**
280 : nicolasconnault 1.1314 * Pass no arguments to create a url that refers to this page.
281 : samhemelryk 1.1255 * Use empty string to create empty url.
282 : jamiesensei 1.894 *
283 : samhemelryk 1.1255 * @global string
284 : tjhunt 1.1244 * @param mixed $url a number of different forms are accespted:
285 :     * null - create a URL that is the same as the URL used to load this page, but with no query string
286 :     * '' - and empty URL
287 :     * string - a URL, will be parsed into it's bits, including query string
288 :     * array - as returned from the PHP function parse_url
289 :     * moodle_url - make a copy of another moodle_url
290 : tjhunt 1.1243 * @param array $params these params override anything in the query string
291 :     * where params have the same name.
292 : jamiesensei 1.874 */
293 : tjhunt 1.1243 public function __construct($url = null, $params = array()) {
294 : tjhunt 1.1244 if ($url === '') {
295 :     // Leave URL blank.
296 :     } else if (is_a($url, 'moodle_url')) {
297 :     $this->scheme = $url->scheme;
298 :     $this->host = $url->host;
299 :     $this->port = $url->port;
300 :     $this->user = $url->user;
301 :     $this->pass = $url->pass;
302 : tjhunt 1.1246 $this->path = $url->path;
303 : tjhunt 1.1244 $this->fragment = $url->fragment;
304 :     $this->params = $url->params;
305 :     } else {
306 : tjhunt 1.1243 if ($url === null) {
307 : tjhunt 1.1244 global $ME;
308 : skodak 1.1198 $url = $ME;
309 : jamiesensei 1.874 }
310 : tjhunt 1.1244 if (is_string($url)) {
311 :     $url = parse_url($url);
312 :     }
313 :     $parts = $url;
314 : tjhunt 1.1243 if ($parts === FALSE) {
315 : tjhunt 1.1244 throw new moodle_exception('invalidurl');
316 : jamiesensei 1.874 }
317 : tjhunt 1.1243 if (isset($parts['query'])) {
318 : jamiesensei 1.890 parse_str(str_replace('&amp;', '&', $parts['query']), $this->params);
319 : jamiesensei 1.874 }
320 :     unset($parts['query']);
321 : tjhunt 1.1243 foreach ($parts as $key => $value) {
322 : jamiesensei 1.874 $this->$key = $value;
323 :     }
324 :     }
325 : tjhunt 1.1244 $this->params($params);
326 : jamiesensei 1.894 }
327 : tjhunt 1.1243
328 : jamiesensei 1.874 /**
329 : nicolasconnault 1.1314 * Add an array of params to the params for this page.
330 : samhemelryk 1.1255 *
331 :     * The added params override existing ones if they have the same name.
332 : jamiesensei 1.874 *
333 : nicolasconnault 1.1306 * @param array $params Defaults to null. If null then returns all params.
334 : samhemelryk 1.1255 * @return array Array of Params for url.
335 : jamiesensei 1.874 */
336 : tjhunt 1.1243 public function params($params = null) {
337 :     if (!is_null($params)) {
338 : jamiesensei 1.1110 return $this->params = $params + $this->params;
339 :     } else {
340 :     return $this->params;
341 :     }
342 : jamiesensei 1.874 }
343 : jamiesensei 1.894
344 : jamiesensei 1.874 /**
345 : nicolasconnault 1.1314 * Remove all params if no arguments passed.
346 :     * Remove selected params if arguments are passed.
347 : samhemelryk 1.1255 *
348 :     * Can be called as either remove_params('param1', 'param2')
349 : tjhunt 1.1244 * or remove_params(array('param1', 'param2')).
350 : jamiesensei 1.874 *
351 : tjhunt 1.1244 * @param mixed $params either an array of param names, or a string param name,
352 :     * @param string $params,... any number of additional param names.
353 : jamiesensei 1.874 */
354 : tjhunt 1.1245 public function remove_params($params = NULL) {
355 : tjhunt 1.1244 if (empty($params)) {
356 :     $this->params = array();
357 :     return;
358 :     }
359 :     if (!is_array($params)) {
360 :     $params = func_get_args();
361 :     }
362 :     foreach ($params as $param) {
363 :     if (isset($this->params[$param])) {
364 :     unset($this->params[$param]);
365 : jamiesensei 1.874 }
366 :     }
367 :     }
368 :    
369 :     /**
370 : nicolasconnault 1.1314 * Add a param to the params for this page.
371 : samhemelryk 1.1255 *
372 :     * The added param overrides existing one if theyhave the same name.
373 : jamiesensei 1.874 *
374 :     * @param string $paramname name
375 : samhemelryk 1.1255 * @param string $param Param value. Defaults to null. If null then return value of param 'name'
376 :     * @return void|string If $param was null then the value of $paramname was returned
377 : tjhunt 1.1262 * (null is returned if that param does not exist).
378 : jamiesensei 1.874 */
379 : tjhunt 1.1243 public function param($paramname, $param = null) {
380 :     if (!is_null($param)) {
381 : jamiesensei 1.1110 $this->params = array($paramname => $param) + $this->params;
382 : tjhunt 1.1262 } else if (array_key_exists($paramname, $this->params)) {
383 :     return $this->params[$paramname];
384 : jamiesensei 1.1110 } else {
385 : tjhunt 1.1262 return null;
386 : jamiesensei 1.1110 }
387 : jamiesensei 1.874 }
388 :    
389 : tjhunt 1.1243 /**
390 :     * Get the params as as a query string.
391 : samhemelryk 1.1255 *
392 : tjhunt 1.1243 * @param array $overrideparams params to add to the output params, these
393 :     * override existing ones with the same name.
394 : mudrd8mz 1.1295 * @param boolean $escaped Use &amp; as params separator instead of plain &
395 : tjhunt 1.1243 * @return string query string that can be added to a url.
396 :     */
397 : mudrd8mz 1.1295 public function get_query_string($overrideparams = array(), $escaped = true) {
398 : jamiesensei 1.874 $arr = array();
399 :     $params = $overrideparams + $this->params;
400 : tjhunt 1.1243 foreach ($params as $key => $val) {
401 : jamiesensei 1.874 $arr[] = urlencode($key)."=".urlencode($val);
402 :     }
403 : mudrd8mz 1.1295 if ($escaped) {
404 :     return implode('&amp;', $arr);
405 :     } else {
406 :     return implode('&', $arr);
407 :     }
408 : jamiesensei 1.874 }
409 : tjhunt 1.1243
410 : jamiesensei 1.874 /**
411 :     * Outputs params as hidden form elements.
412 : jamiesensei 1.875 *
413 : samhemelryk 1.1255 * @param array $exclude params to ignore
414 : jamiesensei 1.884 * @param integer $indent indentation
415 : jamiesensei 1.1076 * @param array $overrideparams params to add to the output params, these
416 : tjhunt 1.1243 * override existing ones with the same name.
417 : jamiesensei 1.874 * @return string html for form elements.
418 :     */
419 : tjhunt 1.1243 public function hidden_params_out($exclude = array(), $indent = 0, $overrideparams=array()) {
420 : jamiesensei 1.874 $tabindent = str_repeat("\t", $indent);
421 :     $str = '';
422 : jamiesensei 1.1076 $params = $overrideparams + $this->params;
423 : tjhunt 1.1243 foreach ($params as $key => $val) {
424 : jamiesensei 1.875 if (FALSE === array_search($key, $exclude)) {
425 : jamiesensei 1.885 $val = s($val);
426 : jamiesensei 1.875 $str.= "$tabindent<input type=\"hidden\" name=\"$key\" value=\"$val\" />\n";
427 :     }
428 : jamiesensei 1.874 }
429 :     return $str;
430 :     }
431 : tjhunt 1.1243
432 : jamiesensei 1.874 /**
433 :     * Output url
434 : jamiesensei 1.894 *
435 : mudrd8mz 1.1295 * If you use the returned URL in HTML code, you want the escaped ampersands. If you use
436 :     * the returned URL in HTTP headers, you want $escaped=false.
437 :     *
438 : tjhunt 1.1251 * @param boolean $omitquerystring whether to output page params as a query string in the url.
439 : jamiesensei 1.874 * @param array $overrideparams params to add to the output url, these override existing ones with the same name.
440 : mudrd8mz 1.1295 * @param boolean $escaped Use &amp; as params separator instead of plain &
441 : samhemelryk 1.1255 * @return string Resulting URL
442 : jamiesensei 1.874 */
443 : mudrd8mz 1.1295 public function out($omitquerystring = false, $overrideparams = array(), $escaped = true) {
444 : jamiesensei 1.874 $uri = $this->scheme ? $this->scheme.':'.((strtolower($this->scheme) == 'mailto') ? '':'//'): '';
445 :     $uri .= $this->user ? $this->user.($this->pass? ':'.$this->pass:'').'@':'';
446 :     $uri .= $this->host ? $this->host : '';
447 :     $uri .= $this->port ? ':'.$this->port : '';
448 :     $uri .= $this->path ? $this->path : '';
449 : tjhunt 1.1251 if (!$omitquerystring) {
450 : mudrd8mz 1.1295 $querystring = $this->get_query_string($overrideparams, $escaped);
451 : tjhunt 1.1251 if ($querystring) {
452 :     $uri .= '?' . $querystring;
453 :     }
454 : jamiesensei 1.874 }
455 :     $uri .= $this->fragment ? '#'.$this->fragment : '';
456 : jamiesensei 1.894 return $uri;
457 : jamiesensei 1.874 }
458 : tjhunt 1.1243
459 : jamiesensei 1.874 /**
460 : tjhunt 1.1298 * Return a URL relative to $CFG->wwwroot.
461 :     *
462 :     * Throws an exception if this URL does not start with $CFG->wwwroot.
463 :     *
464 :     * The main use for this is when you want to pass a returnurl from one script to another.
465 :     * In this case the returnurl should be relative to $CFG->wwwroot for two reasons.
466 :     * First, it is shorter. More imporatantly, some web servers (e.g. IIS by default)
467 :     * give a 'security' error if you try to pass a full URL as a GET parameter in another URL.
468 :     *
469 :     * @return string the URL relative to $CFG->wwwroot. Note, you will need to urlencode
470 :     * this result if you are outputting a URL manually (but not if you are adding
471 :     * it to another moodle_url).
472 :     */
473 :     public function out_returnurl() {
474 :     global $CFG;
475 :     $fulluri = $this->out(false, array(), false);
476 :     $uri = str_replace($CFG->wwwroot . '/', '', $fulluri);
477 :     if ($uri == $fulluri) {
478 :     throw new coding_exception('This URL (' . $fulluri . ') is not relative to $CFG->wwwroot.');
479 :     }
480 :     return $uri;
481 :     }
482 :    
483 :     /**
484 : jamiesensei 1.874 * Output action url with sesskey
485 : jamiesensei 1.894 *
486 : samhemelryk 1.1255 * Adds sesskey and overriderparams then calls {@link out()}
487 :     * @see out()
488 :     *
489 :     * @param array $overrideparams Allows you to override params
490 : jamiesensei 1.874 * @return string url
491 :     */
492 : tjhunt 1.1243 public function out_action($overrideparams = array()) {
493 : jamiesensei 1.874 $overrideparams = array('sesskey'=> sesskey()) + $overrideparams;
494 : jamiesensei 1.891 return $this->out(false, $overrideparams);
495 : jamiesensei 1.874 }
496 : nicolasconnault 1.1324
497 :     /**
498 :     * Compares this moodle_url with another
499 :     * See documentation of constants for an explanation of the comparison flags.
500 :     * @param moodle_url $url The moodle_url object to compare
501 :     * @param int $matchtype The type of comparison (URL_MATCH_BASE, URL_MATCH_PARAMS, URL_MATCH_EXACT)
502 :     * @return boolean
503 :     */
504 :     public function compare(moodle_url $url, $matchtype = URL_MATCH_EXACT) {
505 : samhemelryk 1.1338 $baseself = $this->out(true);
506 :     $baseother = $url->out(true);
507 :    
508 :     // Append index.php if there is no specific file
509 :     if (substr($baseself,-1)=='/') {
510 :     $baseself .= 'index.php';
511 :     }
512 :     if (substr($baseother,-1)=='/') {
513 :     $baseother .= 'index.php';
514 :     }
515 :    
516 :     // Compare the two base URLs
517 :     if ($baseself != $baseother) {
518 : nicolasconnault 1.1324 return false;
519 :     }
520 :    
521 :     if ($matchtype == URL_MATCH_BASE) {
522 :     return true;
523 :     }
524 :    
525 :     $urlparams = $url->params();
526 :     foreach ($this->params() as $param => $value) {
527 :     if ($param == 'sesskey') {
528 :     continue;
529 :     }
530 :     if (!array_key_exists($param, $urlparams) || $urlparams[$param] != $value) {
531 :     return false;
532 :     }
533 :     }
534 :    
535 :     if ($matchtype == URL_MATCH_PARAMS) {
536 :     return true;
537 :     }
538 :    
539 :     foreach ($urlparams as $param => $value) {
540 :     if ($param == 'sesskey') {
541 :     continue;
542 :     }
543 :     if (!array_key_exists($param, $this->params()) || $this->param($param) != $value) {
544 :     return false;
545 :     }
546 :     }
547 :    
548 :     return true;
549 :     }
550 : jamiesensei 1.874 }
551 :    
552 : dhawes 1.302 /**
553 : nicolasconnault 1.1306 * Given an unknown $url type (string or moodle_url), returns a string URL.
554 :     * A relative URL is handled with $PAGE->url but gives a debugging error.
555 :     *
556 :     * @param mixed $url The URL (moodle_url or string)
557 :     * @param bool $stripformparams Whether or not to strip the query params from the URL
558 : tjhunt 1.1311 * @return string the URL. &s are unescaped. You must use s(...) to output this to XHTML. ($OUTPUT normally does this automatically.)
559 : nicolasconnault 1.1306 */
560 :     function prepare_url($url, $stripformparams=false) {
561 :     global $CFG, $PAGE;
562 :    
563 :     $output = $url;
564 :    
565 :     if ($url instanceof moodle_url) {
566 : tjhunt 1.1311 $output = $url->out($stripformparams, array(), false);
567 : nicolasconnault 1.1306 }
568 :    
569 :     // Handle relative URLs
570 :     if (substr($output, 0, 4) != 'http' && substr($output, 0, 1) != '/') {
571 :     if (preg_match('/(.*)\/([A-Za-z0-9-_]*\.php)$/', $PAGE->url->out(true), $matches)) {
572 :     return $matches[1] . "/$output";
573 : nicolasconnault 1.1327 } else if ($output == '') {
574 :     return $PAGE->url->out(false, array(), false) . '#';
575 : nicolasconnault 1.1306 } else {
576 : samhemelryk 1.1335 throw new coding_exception('Unrecognied URL scheme. Please check the formatting of the URL passed to this function. Absolute URLs are the preferred scheme.');
577 : nicolasconnault 1.1306 }
578 :     }
579 :    
580 : samhemelryk 1.1336 // Add wwwroot only if the URL does not already start with http:// or https://
581 :     if (!preg_match('|https?://|', $output) ) {
582 :     $output = $CFG->wwwroot . $output;
583 :     }
584 :    
585 : nicolasconnault 1.1306 return $output;
586 :     }
587 :    
588 :     /**
589 : dhawes 1.302 * Determine if there is data waiting to be processed from a form
590 :     *
591 :     * Used on most forms in Moodle to check for data
592 :     * Returns the data as an object, if it's found.
593 :     * This object can be used in foreach loops without
594 :     * casting because it's cast to (array) automatically
595 : urs_hunkler 1.347 *
596 : skodak 1.698 * Checks that submitted POST data exists and returns it as object.
597 : dhawes 1.304 *
598 : samhemelryk 1.1255 * @uses $_POST
599 : skodak 1.698 * @return mixed false or object
600 : dhawes 1.302 */
601 : skodak 1.1082 function data_submitted() {
602 : dhawes 1.304
603 : moodler 1.50 if (empty($_POST)) {
604 :     return false;
605 : moodler 1.47 } else {
606 : skodak 1.1082 return (object)$_POST;
607 : moodler 1.47 }
608 : martin 1.1 }
609 :    
610 : dhawes 1.302 /**
611 : dhawes 1.304 * Given some normal text this function will break up any
612 :     * long words to a given size by inserting the given character
613 :     *
614 : moodler 1.510 * It's multibyte savvy and doesn't change anything inside html tags.
615 :     *
616 : dhawes 1.302 * @param string $string the string to be modified
617 : dhawes 1.308 * @param int $maxsize maximum length of the string to be returned
618 : dhawes 1.302 * @param string $cutchar the string used to represent word breaks
619 :     * @return string
620 :     */
621 : moodler 1.226 function break_up_long_words($string, $maxsize=20, $cutchar=' ') {
622 : julmis 1.436
623 : moodler 1.510 /// Loading the textlib singleton instance. We are going to need it.
624 :     $textlib = textlib_get_instance();
625 : moodler 1.226
626 : moodler 1.510 /// First of all, save all the tags inside the text to skip them
627 :     $tags = array();
628 :     filter_save_tags($string,$tags);
629 : moodler 1.257
630 : moodler 1.510 /// Process the string adding the cut when necessary
631 : moodler 1.226 $output = '';
632 : skodak 1.683 $length = $textlib->strlen($string);
633 : moodler 1.226 $wordlength = 0;
634 :    
635 :     for ($i=0; $i<$length; $i++) {
636 : skodak 1.683 $char = $textlib->substr($string, $i, 1);
637 : moodler 1.510 if ($char == ' ' or $char == "\t" or $char == "\n" or $char == "\r" or $char == "<" or $char == ">") {
638 : moodler 1.226 $wordlength = 0;
639 :     } else {
640 :     $wordlength++;
641 :     if ($wordlength > $maxsize) {
642 :     $output .= $cutchar;
643 :     $wordlength = 0;
644 :     }
645 :     }
646 :     $output .= $char;
647 :     }
648 : moodler 1.510
649 :     /// Finally load the tags back again
650 :     if (!empty($tags)) {
651 :     $output = str_replace(array_keys($tags), $tags, $output);
652 :     }
653 :    
654 : moodler 1.226 return $output;
655 :     }
656 :    
657 : samhemelryk 1.1333 /**
658 : tjhunt 1.1185 * Try and close the current window using JavaScript, either immediately, or after a delay.
659 : samhemelryk 1.1255 *
660 :     * Echo's out the resulting XHTML & javascript
661 :     *
662 :     * @global object
663 :     * @global object
664 : tjhunt 1.1185 * @param integer $delay a delay in seconds before closing the window. Default 0.
665 :     * @param boolean $reloadopener if true, we will see if this window was a pop-up, and try
666 :     * to reload the parent window before this one closes.
667 : moodler 1.408 */
668 : tjhunt 1.1185 function close_window($delay = 0, $reloadopener = false) {
669 : nicolasconnault 1.1323 global $THEME, $PAGE, $OUTPUT;
670 : tjhunt 1.1185
671 : tjhunt 1.1237 if (!$PAGE->headerprinted) {
672 : samhemelryk 1.1333 $PAGE->set_title(get_string('closewindow'));
673 :     echo $OUTPUT->header();
674 : tjhunt 1.1185 } else {
675 :     print_container_end_all(false, $THEME->open_header_containers);
676 :     }
677 :    
678 :     if ($reloadopener) {
679 :     $function = 'close_window_reloading_opener';
680 :     } else {
681 :     $function = 'close_window';
682 : moodler 1.408 }
683 : tjhunt 1.1185 echo '<p class="centerpara">' . get_string('windowclosing') . '</p>';
684 : tjhunt 1.1262
685 :     $PAGE->requires->js_function_call($function)->after_delay($delay);
686 : tjhunt 1.1185
687 : nicolasconnault 1.1323 echo $OUTPUT->footer();
688 : tjhunt 1.1185 exit;
689 : moodler 1.408 }
690 :    
691 : nicolasconnault 1.1321 /**
692 :     * Returns a string containing a link to the user documentation for the current
693 :     * page. Also contains an icon by default. Shown to teachers and admin only.
694 :     *
695 :     * @global object
696 :     * @global object
697 :     * @param string $text The text to be displayed for the link
698 :     * @param string $iconpath The path to the icon to be displayed
699 :     * @return string The link to user documentation for this current page
700 :     */
701 :     function page_doc_link($text='', $iconpath='') {
702 :     global $CFG, $PAGE, $OUTPUT;
703 :    
704 :     if (empty($CFG->docroot) || during_initial_install()) {
705 :     return '';
706 :     }
707 :     if (!has_capability('moodle/site:doclinks', $PAGE->context)) {
708 :     return '';
709 :     }
710 :    
711 :     $path = $PAGE->docspath;
712 :     if (!$path) {
713 :     return '';
714 :     }
715 :     return $OUTPUT->doc_link($path, $text, $iconpath);
716 :     }
717 :    
718 : mjollnir_ 1.513
719 :     /**
720 : dhawes 1.304 * Validates an email to make sure it makes sense.
721 :     *
722 :     * @param string $address The email address to validate.
723 :     * @return boolean
724 :     */
725 : dhawes 1.308 function validate_email($address) {
726 : martin 1.1
727 : martinlanghoff 1.578 return (ereg('^[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+'.
728 :     '(\.[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+)*'.
729 : martin 1.1 '@'.
730 :     '[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.
731 :     '[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$',
732 :     $address));
733 :     }
734 :    
735 : dhawes 1.304 /**
736 : skodak 1.327 * Extracts file argument either from file parameter or PATH_INFO
737 : skodak 1.1198 * Note: $scriptname parameter is not needed anymore
738 : skodak 1.327 *
739 : samhemelryk 1.1255 * @global string
740 :     * @uses $_SERVER
741 :     * @uses PARAM_PATH
742 : skodak 1.327 * @return string file path (only safe characters)
743 :     */
744 : skodak 1.1198 function get_file_argument() {
745 :     global $SCRIPT;
746 : skodak 1.327
747 :     $relativepath = optional_param('file', FALSE, PARAM_PATH);
748 :    
749 :     // then try extract file from PATH_INFO (slasharguments method)
750 : skodak 1.1198 if ($relativepath === false and isset($_SERVER['PATH_INFO']) and $_SERVER['PATH_INFO'] !== '') {
751 : skodak 1.327 // check that PATH_INFO works == must not contain the script name
752 : skodak 1.1198 if (strpos($_SERVER['PATH_INFO'], $SCRIPT) === false) {
753 :     $relativepath = clean_param(urldecode($_SERVER['PATH_INFO']), PARAM_PATH);
754 : skodak 1.327 }
755 :     }
756 :    
757 : skodak 1.1198 // note: we are not using any other way because they are not compatible with unicode file names ;-)
758 : skodak 1.327
759 :     return $relativepath;
760 :     }
761 :    
762 :     /**
763 : dhawes 1.308 * Just returns an array of text formats suitable for a popup menu
764 : dhawes 1.304 *
765 : dhawes 1.308 * @uses FORMAT_MOODLE
766 :     * @uses FORMAT_HTML
767 :     * @uses FORMAT_PLAIN
768 :     * @uses FORMAT_MARKDOWN
769 :     * @return array
770 : dhawes 1.304 */
771 : moodler 1.23 function format_text_menu() {
772 : dhawes 1.304
773 : dhawes 1.301 return array (FORMAT_MOODLE => get_string('formattext'),
774 :     FORMAT_HTML => get_string('formathtml'),
775 :     FORMAT_PLAIN => get_string('formatplain'),
776 :     FORMAT_MARKDOWN => get_string('formatmarkdown'));
777 : moodler 1.23 }
778 :    
779 : dhawes 1.304 /**
780 :     * Given text in a variety of format codings, this function returns
781 : urs_hunkler 1.347 * the text as safe HTML.
782 : dhawes 1.304 *
783 : jamiesensei 1.1023 * This function should mainly be used for long strings like posts,
784 : poltawski 1.1004 * answers, glossary items etc. For short strings @see format_string().
785 :     *
786 : samhemelryk 1.1255 * @todo Finish documenting this function
787 :     *
788 :     * @global object
789 :     * @global object
790 :     * @global object
791 :     * @global object
792 : dhawes 1.308 * @uses FORMAT_MOODLE
793 :     * @uses FORMAT_HTML
794 :     * @uses FORMAT_PLAIN
795 :     * @uses FORMAT_WIKI
796 :     * @uses FORMAT_MARKDOWN
797 : samhemelryk 1.1255 * @uses CLI_SCRIPT
798 :     * @staticvar array $croncache
799 : dhawes 1.308 * @param string $text The text to be formatted. This is raw text originally from user input.
800 : urs_hunkler 1.347 * @param int $format Identifier of the text format to be used
801 : samhemelryk 1.1255 * [FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN]
802 :     * @param object $options ?
803 :     * @param int $courseid The courseid to use, defaults to $COURSE->courseid
804 : dhawes 1.308 * @return string
805 : dhawes 1.304 */
806 : skodak 1.615 function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL) {
807 : tjhunt 1.1238 global $CFG, $COURSE, $DB, $PAGE;
808 : moodler 1.193
809 : skodak 1.1032 static $croncache = array();
810 : skodak 1.1206
811 : dongsheng 1.1188 $hashstr = '';
812 : skodak 1.1032
813 : skodak 1.678 if ($text === '') {
814 :     return ''; // no need to do any filters and cleaning
815 :     }
816 : dongsheng 1.1305 if (!empty($options->comments) && !empty($CFG->usecomments)) {
817 :     require_once($CFG->libdir . '/commentlib.php');
818 :     $comment = new comment($options->comments);
819 :     $cmt = $comment->init(true);
820 :     } else {
821 :     $cmt = '';
822 :     }
823 :    
824 : skodak 1.678
825 : skodak 1.1231 if (!isset($options->trusted)) {
826 :     $options->trusted = false;
827 : skodak 1.615 }
828 : skodak 1.500 if (!isset($options->noclean)) {
829 : skodak 1.1231 if ($options->trusted and trusttext_active()) {
830 :     // no cleaning if text trusted and noclean not specified
831 :     $options->noclean=true;
832 :     } else {
833 :     $options->noclean=false;
834 :     }
835 : skodak 1.500 }
836 : skodak 1.653 if (!isset($options->nocache)) {
837 :     $options->nocache=false;
838 :     }
839 : skodak 1.500 if (!isset($options->smiley)) {
840 :     $options->smiley=true;
841 :     }
842 :     if (!isset($options->filter)) {
843 :     $options->filter=true;
844 :     }
845 :     if (!isset($options->para)) {
846 :     $options->para=true;
847 :     }
848 :     if (!isset($options->newlines)) {
849 :     $options->newlines=true;
850 : moodler 1.206 }
851 : moodler 1.193 if (empty($courseid)) {
852 : skodak 1.802 $courseid = $COURSE->id;
853 : moodler 1.193 }
854 : moodler 1.148
855 : tjhunt 1.1227 if ($options->filter) {
856 :     $filtermanager = filter_manager::instance();
857 :     } else {
858 :     $filtermanager = new null_filter_manager();
859 : dongsheng 1.1188 }
860 : tjhunt 1.1238 $context = $PAGE->context;
861 : tjhunt 1.1227
862 : skodak 1.653 if (!empty($CFG->cachetext) and empty($options->nocache)) {
863 : tjhunt 1.1227 $hashstr .= $text.'-'.$filtermanager->text_filtering_hash($context, $courseid).'-'.(int)$courseid.'-'.current_language().'-'.
864 : skodak 1.1231 (int)$format.(int)$options->trusted.(int)$options->noclean.(int)$options->smiley.
865 : tjhunt 1.1227 (int)$options->filter.(int)$options->para.(int)$options->newlines;
866 : dongsheng 1.1188
867 : skodak 1.500 $time = time() - $CFG->cachetext;
868 : skodak 1.1206 $md5key = md5($hashstr);
869 : skodak 1.1197 if (CLI_SCRIPT) {
870 : skodak 1.1032 if (isset($croncache[$md5key])) {
871 : dongsheng 1.1305 return $croncache[$md5key].$cmt;
872 : skodak 1.1032 }
873 :     }
874 :    
875 : skodak 1.1294 if ($oldcacheitem = $DB->get_record('cache_text', array('md5key'=>$md5key), '*', IGNORE_MULTIPLE)) {
876 : moodler 1.554 if ($oldcacheitem->timemodified >= $time) {
877 : skodak 1.1197 if (CLI_SCRIPT) {
878 : skodak 1.1032 if (count($croncache) > 150) {
879 : skodak 1.1038 reset($croncache);
880 :     $key = key($croncache);
881 :     unset($croncache[$key]);
882 : skodak 1.1032 }
883 :     $croncache[$md5key] = $oldcacheitem->formattedtext;
884 :     }
885 : dongsheng 1.1305 return $oldcacheitem->formattedtext.$cmt;
886 : moodler 1.554 }
887 : skodak 1.500 }
888 :     }
889 :    
890 : moodler 1.23 switch ($format) {
891 : moodler 1.63 case FORMAT_HTML:
892 : skodak 1.615 if ($options->smiley) {
893 : skodak 1.500 replace_smilies($text);
894 :     }
895 : skodak 1.615 if (!$options->noclean) {
896 : skodak 1.790 $text = clean_text($text, FORMAT_HTML);
897 : moodler 1.272 }
898 : tjhunt 1.1227 $text = $filtermanager->filter_text($text, $context, $courseid);
899 : moodler 1.63 break;
900 :    
901 : moodler 1.81 case FORMAT_PLAIN:
902 : skodak 1.790 $text = s($text); // cleans dangerous JS
903 : stronk7 1.241 $text = rebuildnolinktag($text);
904 : dhawes 1.301 $text = str_replace(' ', '&nbsp; ', $text);
905 : moodler 1.81 $text = nl2br($text);
906 :     break;
907 :    
908 : moodler 1.87 case FORMAT_WIKI:
909 : thepurpleblob 1.441 // this format is deprecated
910 : julmis 1.448 $text = '<p>NOTICE: Wiki-like formatting has been removed from Moodle. You should not be seeing
911 :     this message as all texts should have been converted to Markdown format instead.
912 : moodler 1.442 Please post a bug report to http://moodle.org/bugs with information about where you
913 : skodak 1.500 saw this message.</p>'.s($text);
914 : moodler 1.87 break;
915 :    
916 : moodler 1.265 case FORMAT_MARKDOWN:
917 :     $text = markdown_to_html($text);
918 : skodak 1.615 if ($options->smiley) {
919 : skodak 1.500 replace_smilies($text);
920 :     }
921 : skodak 1.615 if (!$options->noclean) {
922 : skodak 1.790 $text = clean_text($text, FORMAT_HTML);
923 : moodler 1.272 }
924 : tjhunt 1.1227 $text = $filtermanager->filter_text($text, $context, $courseid);
925 : moodler 1.265 break;
926 :    
927 : moodler 1.63 default: // FORMAT_MOODLE or anything else
928 : moodler 1.225 $text = text_to_html($text, $options->smiley, $options->para, $options->newlines);
929 : skodak 1.615 if (!$options->noclean) {
930 : skodak 1.790 $text = clean_text($text, FORMAT_HTML);
931 : moodler 1.272 }
932 : tjhunt 1.1227 $text = $filtermanager->filter_text($text, $context, $courseid);
933 :     break;
934 :     }
935 : julmis 1.530
936 : tjhunt 1.1227 // Warn people that we have removed this old mechanism, just in case they
937 :     // were stupid enough to rely on it.
938 :     if (isset($CFG->currenttextiscacheable)) {
939 :     debugging('Once upon a time, Moodle had a truly evil use of global variables ' .
940 :     'called $CFG->currenttextiscacheable. The good news is that this no ' .
941 :     'longer exists. The bad news is that you seem to be using a filter that '.
942 :     'relies on it. Please seek out and destroy that filter code.', DEBUG_DEVELOPER);
943 : moodler 1.206 }
944 : moodler 1.162
945 : tjhunt 1.1227 if (empty($options->nocache) and !empty($CFG->cachetext)) {
946 : skodak 1.1197 if (CLI_SCRIPT) {
947 : skodak 1.1032 // special static cron cache - no need to store it in db if its not already there
948 :     if (count($croncache) > 150) {
949 : skodak 1.1038 reset($croncache);
950 :     $key = key($croncache);
951 :     unset($croncache[$key]);
952 : skodak 1.1032 }
953 :     $croncache[$md5key] = $text;
954 : dongsheng 1.1305 return $text.$cmt;
955 : skodak 1.1032 }
956 :    
957 : skodak 1.670 $newcacheitem = new object();
958 : moodler 1.554 $newcacheitem->md5key = $md5key;
959 : skodak 1.1073 $newcacheitem->formattedtext = $text;
960 : moodler 1.554 $newcacheitem->timemodified = time();
961 :     if ($oldcacheitem) { // See bug 4677 for discussion
962 :     $newcacheitem->id = $oldcacheitem->id;
963 : skodak 1.1229 try {
964 :     $DB->update_record('cache_text', $newcacheitem); // Update existing record in the cache table
965 :     } catch (dml_exception $e) {
966 :     // It's unlikely that the cron cache cleaner could have
967 :     // deleted this entry in the meantime, as it allows
968 :     // some extra time to cover these cases.
969 :     }
970 :     } else {
971 :     try {
972 :     $DB->insert_record('cache_text', $newcacheitem); // Insert a new record in the cache table
973 :     } catch (dml_exception $e) {
974 :     // Again, it's possible that another user has caused this
975 :     // record to be created already in the time that it took
976 :     // to traverse this function. That's OK too, as the
977 :     // call above handles duplicate entries, and eventually
978 :     // the cron cleaner will delete them.
979 :     }
980 : moodler 1.554 }
981 : moodler 1.23 }
982 : dongsheng 1.1305 return $text.$cmt;
983 : nicolasconnault 1.1314
984 : moodler 1.23 }
985 :    
986 : samhemelryk 1.1255 /**
987 :     * Converts the text format from the value to the 'internal'
988 : nicolasconnault 1.1314 * name or vice versa.
989 : samhemelryk 1.1255 *
990 :     * $key can either be the value or the name and you get the other back.
991 : julmis 1.530 *
992 : samhemelryk 1.1255 * @uses FORMAT_MOODLE
993 :     * @uses FORMAT_HTML
994 :     * @uses FORMAT_PLAIN
995 :     * @uses FORMAT_MARKDOWN
996 :     * @param mixed $key int 0-4 or string one of 'moodle','html','plain','markdown'
997 :     * @return mixed as above but the other way around!
998 : thepurpleblob 1.467 */
999 :     function text_format_name( $key ) {
1000 :     $lookup = array();
1001 :     $lookup[FORMAT_MOODLE] = 'moodle';
1002 :     $lookup[FORMAT_HTML] = 'html';
1003 :     $lookup[FORMAT_PLAIN] = 'plain';
1004 :     $lookup[FORMAT_MARKDOWN] = 'markdown';
1005 :     $value = "error";
1006 :     if (!is_numeric($key)) {
1007 :     $key = strtolower( $key );
1008 :     $value = array_search( $key, $lookup );
1009 :     }
1010 :     else {
1011 :     if (isset( $lookup[$key] )) {
1012 :     $value = $lookup[ $key ];
1013 :     }
1014 :     }
1015 :     return $value;
1016 :     }
1017 :    
1018 : skodak 1.1013 /**
1019 :     * Resets all data related to filters, called during upgrade or when filter settings change.
1020 : samhemelryk 1.1255 *
1021 :     * @global object
1022 :     * @global object
1023 : skodak 1.1013 * @return void
1024 :     */
1025 :     function reset_text_filters_cache() {
1026 : skodak 1.1079 global $CFG, $DB;
1027 : skodak 1.1013
1028 : skodak 1.1079 $DB->delete_records('cache_text');
1029 : skodak 1.1013 $purifdir = $CFG->dataroot.'/cache/htmlpurifier';
1030 :     remove_dir($purifdir, true);
1031 :     }
1032 : skodak 1.821
1033 : nicolasconnault 1.1314 /**
1034 : samhemelryk 1.1255 * Given a simple string, this function returns the string
1035 :     * processed by enabled string filters if $CFG->filterall is enabled
1036 :     *
1037 :     * This function should be used to print short strings (non html) that
1038 :     * need filter processing e.g. activity titles, post subjects,
1039 :     * glossary concepts.
1040 :     *
1041 :     * @global object
1042 :     * @global object
1043 :     * @global object
1044 :     * @staticvar bool $strcache
1045 :     * @param string $string The string to be filtered.
1046 :     * @param boolean $striplinks To strip any link in the result text.
1047 :     Moodle 1.8 default changed from false to true! MDL-8713
1048 :     * @param int $courseid Current course as filters can, potentially, use it
1049 :     * @return string
1050 : stronk7 1.410 */
1051 : tjhunt 1.1227 function format_string($string, $striplinks=true, $courseid=NULL ) {
1052 : tjhunt 1.1238 global $CFG, $COURSE, $PAGE;
1053 : skodak 1.832
1054 : stronk7 1.421 //We'll use a in-memory cache here to speed up repeated strings
1055 : skodak 1.821 static $strcache = false;
1056 :    
1057 : skodak 1.832 if ($strcache === false or count($strcache) > 2000 ) { // this number might need some tuning to limit memory usage in cron
1058 : skodak 1.821 $strcache = array();
1059 :     }
1060 : jamiesensei 1.894
1061 : skodak 1.832 //init course id
1062 : skodak 1.833 if (empty($courseid)) {
1063 : skodak 1.832 $courseid = $COURSE->id;
1064 :     }
1065 :    
1066 : stronk7 1.421 //Calculate md5
1067 : skodak 1.832 $md5 = md5($string.'<+>'.$striplinks.'<+>'.$courseid.'<+>'.current_language());
1068 : stronk7 1.421
1069 :     //Fetch from cache if possible
1070 : skodak 1.832 if (isset($strcache[$md5])) {
1071 : stronk7 1.421 return $strcache[$md5];
1072 :     }
1073 :    
1074 : nicolasconnault 1.838 // First replace all ampersands not followed by html entity code
1075 : nicolasconnault 1.1271 // Regular expression moved to its own method for easier unit testing
1076 :     $string = replace_ampersands_not_followed_by_entity($string);
1077 : nicolasconnault 1.849
1078 : tjhunt 1.1228 if (!empty($CFG->filterall) && $CFG->version >= 2009040600) { // Avoid errors during the upgrade to the new system.
1079 : tjhunt 1.1238 $context = $PAGE->context;
1080 : tjhunt 1.1227 $string = filter_manager::instance()->filter_string($string, $context, $courseid);
1081 : stronk7 1.410 }
1082 : jamiesensei 1.894
1083 : moodler 1.847 // If the site requires it, strip ALL tags from this string
1084 :     if (!empty($CFG->formatstringstriptags)) {
1085 :     $string = strip_tags($string);
1086 :    
1087 : skodak 1.1113 } else {
1088 :     // Otherwise strip just links if that is required (default)
1089 :     if ($striplinks) { //strip links in string
1090 : nicolasconnault 1.1272 $string = strip_links($string);
1091 : skodak 1.1113 }
1092 :     $string = clean_text($string);
1093 : stronk7 1.412 }
1094 :    
1095 : stronk7 1.421 //Store to cache
1096 :     $strcache[$md5] = $string;
1097 : jamiesensei 1.894
1098 : stronk7 1.410 return $string;
1099 :     }
1100 :    
1101 : dhawes 1.304 /**
1102 : nicolasconnault 1.1271 * Given a string, performs a negative lookahead looking for any ampersand character
1103 :     * that is not followed by a proper HTML entity. If any is found, it is replaced
1104 :     * by &amp;. The string is then returned.
1105 :     *
1106 :     * @param string $string
1107 :     * @return string
1108 :     */
1109 :     function replace_ampersands_not_followed_by_entity($string) {
1110 :     return preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&amp;", $string);
1111 :     }
1112 :    
1113 :     /**
1114 : nicolasconnault 1.1272 * Given a string, replaces all <a>.*</a> by .* and returns the string.
1115 : nicolasconnault 1.1314 *
1116 : nicolasconnault 1.1272 * @param string $string
1117 :     * @return string
1118 :     */
1119 :     function strip_links($string) {
1120 :     return preg_replace('/(<a\s[^>]+?>)(.+?)(<\/a>)/is','$2',$string);
1121 :     }
1122 :    
1123 :     /**
1124 :     * This expression turns links into something nice in a text format. (Russell Jungwirth)
1125 :     *
1126 :     * @param string $string
1127 :     * @return string
1128 :     */
1129 :     function wikify_links($string) {
1130 :     return preg_replace('~(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)~i','$3 [ $2 ]', $string);
1131 :     }
1132 :    
1133 :     /**
1134 :     * Replaces non-standard HTML entities
1135 : nicolasconnault 1.1314 *
1136 : nicolasconnault 1.1272 * @param string $string
1137 :     * @return string
1138 :     */
1139 :     function fix_non_standard_entities($string) {
1140 :     $text = preg_replace('/(&#[0-9]+)(;?)/', '$1;', $string);
1141 : nicolasconnault 1.1314 $text = preg_replace('/(&#x[0-9a-fA-F]+)(;?)/', '$1;', $text);
1142 : nicolasconnault 1.1272 return $text;
1143 :     }
1144 :    
1145 :     /**
1146 : dhawes 1.304 * Given text in a variety of format codings, this function returns
1147 :     * the text as plain text suitable for plain email.
1148 :     *
1149 : dhawes 1.308 * @uses FORMAT_MOODLE
1150 :     * @uses FORMAT_HTML
1151 :     * @uses FORMAT_PLAIN
1152 :     * @uses FORMAT_WIKI
1153 :     * @uses FORMAT_MARKDOWN
1154 :     * @param string $text The text to be formatted. This is raw text originally from user input.
1155 : urs_hunkler 1.347 * @param int $format Identifier of the text format to be used
1156 : samhemelryk 1.1255 * [FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN]
1157 : dhawes 1.308 * @return string
1158 : dhawes 1.304 */
1159 : moodler 1.87 function format_text_email($text, $format) {
1160 :    
1161 :     switch ($format) {
1162 :    
1163 :     case FORMAT_PLAIN:
1164 :     return $text;
1165 :     break;
1166 :    
1167 :     case FORMAT_WIKI:
1168 :     $text = wiki_to_html($text);
1169 : nicolasconnault 1.1272 $text = wikify_links($text);
1170 : moodler 1.116 return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
1171 : moodler 1.87 break;
1172 :    
1173 : moodler 1.176 case FORMAT_HTML:
1174 :     return html_to_text($text);
1175 :     break;
1176 :    
1177 : moodler 1.265 case FORMAT_MOODLE:
1178 :     case FORMAT_MARKDOWN:
1179 : julmis 1.279 default:
1180 : nicolasconnault 1.1272 $text = wikify_links($text);
1181 : moodler 1.116 return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
1182 : moodler 1.87 break;
1183 :     }
1184 :     }
1185 : martin 1.1
1186 : dhawes 1.304 /**
1187 :     * Given some text in HTML format, this function will pass it
1188 : tjhunt 1.1227 * through any filters that have been configured for this context.
1189 : dhawes 1.304 *
1190 : samhemelryk 1.1255 * @global object
1191 :     * @global object
1192 :     * @global object
1193 : dhawes 1.308 * @param string $text The text to be passed through format filters
1194 : tjhunt 1.1227 * @param int $courseid The current course.
1195 :     * @return string the filtered string.
1196 : dhawes 1.304 */
1197 : moodler 1.193 function filter_text($text, $courseid=NULL) {
1198 : tjhunt 1.1238 global $CFG, $COURSE, $PAGE;
1199 : skodak 1.802
1200 :     if (empty($courseid)) {
1201 :     $courseid = $COURSE->id; // (copied from format_text)
1202 :     }
1203 : moodler 1.162
1204 : tjhunt 1.1238 $context = $PAGE->context;
1205 : moodler 1.847
1206 : tjhunt 1.1227 return filter_manager::instance()->filter_text($text, $context, $courseid);
1207 : moodler 1.843 }
1208 : skodak 1.1233 /**
1209 :     * Formats activity intro text
1210 : samhemelryk 1.1255 *
1211 :     * @global object
1212 :     * @uses CONTEXT_MODULE
1213 : skodak 1.1233 * @param string $module name of module
1214 :     * @param object $activity instance of activity
1215 :     * @param int $cmid course module id
1216 : skodak 1.1235 * @param bool $filter filter resulting html text
1217 : skodak 1.1233 * @return text
1218 :     */
1219 : skodak 1.1235 function format_module_intro($module, $activity, $cmid, $filter=true) {
1220 : skodak 1.1234 global $CFG;
1221 :     require_once("$CFG->libdir/filelib.php");
1222 : skodak 1.1235 $options = (object)array('noclean'=>true, 'para'=>false, 'filter'=>false);
1223 : skodak 1.1233 $context = get_context_instance(CONTEXT_MODULE, $cmid);
1224 : skodak 1.1236 $intro = file_rewrite_pluginfile_urls($activity->intro, 'pluginfile.php', $context->id, $module.'_intro', null);
1225 : skodak 1.1234 return trim(format_text($intro, $activity->introformat, $options));
1226 : skodak 1.1233 }
1227 : moodler 1.843
1228 : dhawes 1.304 /**
1229 : skodak 1.1231 * Legacy function, used for cleaning of old forum and glossary text only.
1230 : samhemelryk 1.1255 *
1231 :     * @global object
1232 : jamiesensei 1.739 * @param string $text text that may contain TRUSTTEXT marker
1233 : skodak 1.615 * @return text without any TRUSTTEXT marker
1234 :     */
1235 :     function trusttext_strip($text) {
1236 :     global $CFG;
1237 :    
1238 :     while (true) { //removing nested TRUSTTEXT
1239 : jamiesensei 1.739 $orig = $text;
1240 : skodak 1.1231 $text = str_replace('#####TRUSTTEXT#####', '', $text);
1241 : skodak 1.615 if (strcmp($orig, $text) === 0) {
1242 :     return $text;
1243 :     }
1244 :     }
1245 :     }
1246 :    
1247 :     /**
1248 : skodak 1.1231 * Must be called before editing of all texts
1249 :     * with trust flag. Removes all XSS nasties
1250 :     * from texts stored in database if needed.
1251 : samhemelryk 1.1255 *
1252 : skodak 1.1231 * @param object $object data object with xxx, xxxformat and xxxtrust fields
1253 :     * @param string $field name of text field
1254 :     * @param object $context active context
1255 :     * @return object updated $object
1256 :     */
1257 :     function trusttext_pre_edit($object, $field, $context) {
1258 :     $trustfield = $field.'trust';
1259 : nicolasconnault 1.1314 $formatfield = $field.'format';
1260 :    
1261 : skodak 1.1231 if (!$object->$trustfield or !trusttext_trusted($context)) {
1262 :     $object->$field = clean_text($object->$field, $object->$formatfield);
1263 :     }
1264 :    
1265 :     return $object;
1266 :     }
1267 :    
1268 :     /**
1269 : samhemelryk 1.1255 * Is current user trusted to enter no dangerous XSS in this context?
1270 :     *
1271 : skodak 1.1231 * Please note the user must be in fact trusted everywhere on this server!!
1272 : samhemelryk 1.1255 *
1273 :     * @param object $context
1274 : skodak 1.1231 * @return bool true if user trusted
1275 :     */
1276 :     function trusttext_trusted($context) {
1277 : nicolasconnault 1.1314 return (trusttext_active() and has_capability('moodle/site:trustcontent', $context));
1278 : skodak 1.1231 }
1279 :    
1280 :     /**
1281 :     * Is trusttext feature active?
1282 : samhemelryk 1.1255 *
1283 :     * @global object
1284 :     * @param object $context
1285 : skodak 1.1231 * @return bool
1286 :     */
1287 :     function trusttext_active() {
1288 :     global $CFG;
1289 :    
1290 : nicolasconnault 1.1314 return !empty($CFG->enabletrusttext);
1291 : skodak 1.1231 }
1292 :    
1293 :     /**
1294 : dhawes 1.304 * Given raw text (eg typed in by a user), this function cleans it up
1295 :     * and removes any nasty tags that could mess up Moodle pages.
1296 :     *
1297 : dhawes 1.308 * @uses FORMAT_MOODLE
1298 :     * @uses FORMAT_PLAIN
1299 : samhemelryk 1.1255 * @global string
1300 :     * @global object
1301 : dhawes 1.308 * @param string $text The text to be cleaned
1302 : urs_hunkler 1.347 * @param int $format Identifier of the text format to be used
1303 : samhemelryk 1.1255 * [FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN]
1304 : dhawes 1.308 * @return string The cleaned up text
1305 : dhawes 1.304 */
1306 : moodler 1.192 function clean_text($text, $format=FORMAT_MOODLE) {
1307 : martin 1.2
1308 : skodak 1.866 global $ALLOWED_TAGS, $CFG;
1309 :    
1310 : skodak 1.865 if (empty($text) or is_numeric($text)) {
1311 : jamiesensei 1.894 return (string)$text;
1312 : skodak 1.865 }
1313 : moodler 1.28
1314 : defacer 1.242 switch ($format) {
1315 : moodler 1.265 case FORMAT_PLAIN:
1316 : skodak 1.862 case FORMAT_MARKDOWN:
1317 : moodler 1.265 return $text;
1318 :    
1319 :     default:
1320 :    
1321 : skodak 1.865 if (!empty($CFG->enablehtmlpurifier)) {
1322 :     $text = purify_html($text);
1323 :     } else {
1324 :     /// Fix non standard entity notations
1325 : nicolasconnault 1.1272 $text = fix_non_standard_entities($text);
1326 : jamiesensei 1.894
1327 : skodak 1.865 /// Remove tags that are not allowed
1328 :     $text = strip_tags($text, $ALLOWED_TAGS);
1329 : jamiesensei 1.894
1330 : skodak 1.865 /// Clean up embedded scripts and , using kses
1331 :     $text = cleanAttributes($text);
1332 : skodak 1.898
1333 :     /// Again remove tags that are not allowed
1334 :     $text = strip_tags($text, $ALLOWED_TAGS);
1335 :    
1336 : skodak 1.865 }
1337 : skodak 1.351
1338 : skodak 1.865 /// Remove potential script events - some extra protection for undiscovered bugs in our code
1339 : nicolasconnault 1.1271 $text = preg_replace("~([^a-z])language([[:space:]]*)=~i", "$1Xlanguage=", $text);
1340 :     $text = preg_replace("~([^a-z])on([a-z]+)([[:space:]]*)=~i", "$1Xon$2=", $text);
1341 : moodler 1.81
1342 : moodler 1.28 return $text;
1343 : moodler 1.23 }
1344 : martin 1.2 }
1345 : moodler 1.23
1346 : dhawes 1.304 /**
1347 : skodak 1.865 * KSES replacement cleaning function - uses HTML Purifier.
1348 : samhemelryk 1.1255 *
1349 :     * @global object
1350 :     * @param string $text The (X)HTML string to purify
1351 : skodak 1.865 */
1352 :     function purify_html($text) {
1353 :     global $CFG;
1354 :    
1355 : skodak 1.1013 // this can not be done only once because we sometimes need to reset the cache
1356 : skodak 1.1088 $cachedir = $CFG->dataroot.'/cache/htmlpurifier';
1357 : skodak 1.1013 $status = check_dir_exists($cachedir, true, true);
1358 :    
1359 : skodak 1.865 static $purifier = false;
1360 : skodak 1.1088 static $config;
1361 : skodak 1.1013 if ($purifier === false) {
1362 : skodak 1.1088 require_once $CFG->libdir.'/htmlpurifier/HTMLPurifier.safe-includes.php';
1363 : skodak 1.865 $config = HTMLPurifier_Config::createDefault();
1364 : skodak 1.1304 $config->set('Core.ConvertDocumentToFragment', true);
1365 :     $config->set('Core.Encoding', 'UTF-8');
1366 :     $config->set('HTML.Doctype', 'XHTML 1.0 Transitional');
1367 :     $config->set('Cache.SerializerPath', $cachedir);
1368 :     $config->set('URI.AllowedSchemes', array('http'=>1, 'https'=>1, 'ftp'=>1, 'irc'=>1, 'nntp'=>1, 'news'=>1, 'rtsp'=>1, 'teamspeak'=>1, 'gopher'=>1, 'mms'=>1));
1369 :     $config->set('Attr.AllowedFrameTargets', array('_blank'));
1370 : skodak 1.865 $purifier = new HTMLPurifier($config);
1371 :     }
1372 :     return $purifier->purify($text);
1373 :     }
1374 :    
1375 :     /**
1376 : dhawes 1.308 * This function takes a string and examines it for HTML tags.
1377 : samhemelryk 1.1255 *
1378 : dhawes 1.304 * If tags are detected it passes the string to a helper function {@link cleanAttributes2()}
1379 : samhemelryk 1.1255 * which checks for attributes and filters them for malicious content
1380 : dhawes 1.304 *
1381 :     * @param string $str The string to be examined for html tags
1382 :     * @return string
1383 :     */
1384 : moodler 1.276 function cleanAttributes($str){
1385 : stronk7 1.454 $result = preg_replace_callback(
1386 :     '%(<[^>]*(>|$)|>)%m', #search for html tags
1387 :     "cleanAttributes2",
1388 : moodler 1.276 $str
1389 : julmis 1.279 );
1390 : moodler 1.276 return $result;
1391 : julmis 1.279 }
1392 :    
1393 : dhawes 1.304 /**
1394 :     * This function takes a string with an html tag and strips out any unallowed
1395 :     * protocols e.g. javascript:
1396 : samhemelryk 1.1255 *
1397 : dhawes 1.304 * It calls ancillary functions in kses which are prefixed by kses
1398 :     *
1399 : samhemelryk 1.1255 * @global object
1400 :     * @global string
1401 : stronk7 1.454 * @param array $htmlArray An array from {@link cleanAttributes()}, containing in its 1st
1402 :     * element the html to be cleared
1403 : dhawes 1.304 * @return string
1404 :     */
1405 : stronk7 1.454 function cleanAttributes2($htmlArray){
1406 : moodler 1.276
1407 : moodler 1.310 global $CFG, $ALLOWED_PROTOCOLS;
1408 : dhawes 1.301 require_once($CFG->libdir .'/kses.php');
1409 : moodler 1.276
1410 : stronk7 1.454 $htmlTag = $htmlArray[1];
1411 : moodler 1.310 if (substr($htmlTag, 0, 1) != '<') {
1412 : moodler 1.276 return '&gt;'; //a single character ">" detected
1413 :     }
1414 : moodler 1.310 if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $htmlTag, $matches)) {
1415 : julmis 1.279 return ''; // It's seriously malformed
1416 :     }
1417 : moodler 1.276 $slash = trim($matches[1]); //trailing xhtml slash
1418 : julmis 1.279 $elem = $matches[2]; //the element name
1419 : moodler 1.276 $attrlist = $matches[3]; // the list of attributes as a string
1420 :    
1421 : moodler 1.310 $attrArray = kses_hair($attrlist, $ALLOWED_PROTOCOLS);
1422 : moodler 1.276
1423 : julmis 1.279 $attStr = '';
1424 : moodler 1.310 foreach ($attrArray as $arreach) {
1425 : skodak 1.527 $arreach['name'] = strtolower($arreach['name']);
1426 :     if ($arreach['name'] == 'style') {
1427 :     $value = $arreach['value'];
1428 :     while (true) {
1429 :     $prevvalue = $value;
1430 :     $value = kses_no_null($value);
1431 :     $value = preg_replace("/\/\*.*\*\//Us", '', $value);
1432 :     $value = kses_decode_entities($value);
1433 :     $value = preg_replace('/(&#[0-9]+)(;?)/', "\\1;", $value);
1434 :     $value = preg_replace('/(&#x[0-9a-fA-F]+)(;?)/', "\\1;", $value);
1435 :     if ($value === $prevvalue) {
1436 :     $arreach['value'] = $value;
1437 :     break;
1438 :     }
1439 :     }
1440 :     $arreach['value'] = preg_replace("/j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t/i", "Xjavascript", $arreach['value']);
1441 :     $arreach['value'] = preg_replace("/e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n/i", "Xexpression", $arreach['value']);
1442 : skodak 1.1041 $arreach['value'] = preg_replace("/b\s*i\s*n\s*d\s*i\s*n\s*g/i", "Xbinding", $arreach['value']);
1443 : skodak 1.734 } else if ($arreach['name'] == 'href') {
1444 : skodak 1.760 //Adobe Acrobat Reader XSS protection
1445 : skodak 1.1189 $arreach['value'] = preg_replace('/(\.(pdf|fdf|xfdf|xdp|xfd)[^#]*)#.*$/i', '$1', $arreach['value']);
1446 : skodak 1.527 }
1447 : skodak 1.703 $attStr .= ' '.$arreach['name'].'="'.$arreach['value'].'"';
1448 : moodler 1.276 }
1449 : julmis 1.357
1450 : moodler 1.276 $xhtml_slash = '';
1451 : moodler 1.310 if (preg_match('%/\s*$%', $attrlist)) {
1452 : julmis 1.279 $xhtml_slash = ' /';
1453 : moodler 1.276 }
1454 : dhawes 1.301 return '<'. $slash . $elem . $attStr . $xhtml_slash .'>';
1455 : moodler 1.276 }
1456 :    
1457 : dhawes 1.304 /**
1458 :     * Replaces all known smileys in the text with image equivalents
1459 :     *
1460 : samhemelryk 1.1255 * @global object
1461 :     * @staticvar array $e
1462 :     * @staticvar array $img
1463 :     * @staticvar array $emoticons
1464 : dhawes 1.304 * @param string $text Passed by reference. The string to search for smily strings.
1465 :     * @return string
1466 :     */
1467 : moodler 1.92 function replace_smilies(&$text) {
1468 : tjhunt 1.1286 global $CFG, $OUTPUT;
1469 : stronk7 1.1069
1470 :     if (empty($CFG->emoticons)) { /// No emoticons defined, nothing to process here
1471 :     return;
1472 :     }
1473 :    
1474 : skodak 1.853 $lang = current_language();
1475 : toyomoyo 1.998 $emoticonstring = $CFG->emoticons;
1476 : gregb_cc 1.72 static $e = array();
1477 :     static $img = array();
1478 : toyomoyo 1.998 static $emoticons = null;
1479 :    
1480 :     if (is_null($emoticons)) {
1481 :     $emoticons = array();
1482 :     if ($emoticonstring) {
1483 :     $items = explode('{;}', $CFG->emoticons);
1484 :     foreach ($items as $item) {
1485 :     $item = explode('{:}', $item);
1486 : jamiesensei 1.1023 $emoticons[$item[0]] = $item[1];
1487 : toyomoyo 1.998 }
1488 :     }
1489 :     }
1490 :    
1491 : skodak 1.853 if (empty($img[$lang])) { /// After the first time this is not run again
1492 :     $e[$lang] = array();
1493 :     $img[$lang] = array();
1494 : gregb_cc 1.71 foreach ($emoticons as $emoticon => $image){
1495 : moodler 1.179 $alttext = get_string($image, 'pix');
1496 : moodler 1.1177 $alttext = preg_replace('/^\[\[(.*)\]\]$/', '$1', $alttext); /// Clean alttext in case there isn't lang string for it.
1497 : skodak 1.853 $e[$lang][] = $emoticon;
1498 : tjhunt 1.1286 $img[$lang][] = '<img alt="'. $alttext .'" width="15" height="15" src="'. $OUTPUT->old_icon_url('s/' . $image) . '" />';
1499 : gregb_cc 1.71 }
1500 : gregb_cc 1.73 }
1501 : martin 1.2
1502 : moodler 1.231 // Exclude from transformations all the code inside <script> tags
1503 :     // Needed to solve Bug 1185. Thanks to jouse 2001 detecting it. :-)
1504 :     // Based on code from glossary fiter by Williams Castillo.
1505 :     // - Eloy
1506 :    
1507 :     // Detect all the <script> zones to take out
1508 :     $excludes = array();
1509 :     preg_match_all('/<script language(.+?)<\/script>/is',$text,$list_of_excludes);
1510 :    
1511 :     // Take out all the <script> zones from text
1512 :     foreach (array_unique($list_of_excludes[0]) as $key=>$value) {
1513 :     $excludes['<+'.$key.'+>'] = $value;
1514 :     }
1515 :     if ($excludes) {
1516 :     $text = str_replace($excludes,array_keys($excludes),$text);
1517 :     }
1518 :    
1519 : moodler 1.179 /// this is the meat of the code - this is run every time
1520 : skodak 1.853 $text = str_replace($e[$lang], $img[$lang], $text);
1521 : moodler 1.231
1522 :     // Recover all the <script> zones to text
1523 :     if ($excludes) {
1524 :     $text = str_replace(array_keys($excludes),$excludes,$text);
1525 :     }
1526 : moodler 1.25 }
1527 : martin 1.2
1528 : dhawes 1.308 /**
1529 : tjhunt 1.1153 * This code is called from help.php to inject a list of smilies into the
1530 :     * emoticons help file.
1531 :     *
1532 : samhemelryk 1.1255 * @global object
1533 :     * @global object
1534 : tjhunt 1.1153 * @return string HTML for a list of smilies.
1535 :     */
1536 : tjhunt 1.1262 function get_emoticons_list_for_help_file() {
1537 : tjhunt 1.1290 global $CFG, $SESSION, $PAGE, $OUTPUT;
1538 : tjhunt 1.1153 if (empty($CFG->emoticons)) {
1539 :     return '';
1540 :     }
1541 :    
1542 :     $items = explode('{;}', $CFG->emoticons);
1543 :     $output = '<ul id="emoticonlist">';
1544 :     foreach ($items as $item) {
1545 :     $item = explode('{:}', $item);
1546 : tjhunt 1.1290 $output .= '<li><img src="' . $OUTPUT->old_icon_url('s/' . $item[1]) . '" alt="' .
1547 : tjhunt 1.1153 $item[0] . '" /><code>' . $item[0] . '</code></li>';
1548 :     }
1549 :     $output .= '</ul>';
1550 :     if (!empty($SESSION->inserttextform)) {
1551 :     $formname = $SESSION->inserttextform;
1552 :     $fieldname = $SESSION->inserttextfield;
1553 :     } else {
1554 :     $formname = 'theform';
1555 :     $fieldname = 'message';
1556 :     }
1557 : tjhunt 1.1171
1558 : tjhunt 1.1262 $PAGE->requires->yui_lib('event');
1559 :     $PAGE->requires->js_function_call('emoticons_help.init', array($formname, $fieldname, 'emoticonlist'));
1560 : tjhunt 1.1153 return $output;
1561 :    
1562 :     }
1563 :    
1564 :     /**
1565 : dhawes 1.308 * Given plain text, makes it into HTML as nicely as possible.
1566 :     * May contain HTML tags already
1567 :     *
1568 : samhemelryk 1.1255 * @global object
1569 : dhawes 1.308 * @param string $text The string to convert.
1570 :     * @param boolean $smiley Convert any smiley characters to smiley images?
1571 :     * @param boolean $para If true then the returned string will be wrapped in paragraph tags
1572 :     * @param boolean $newlines If true then lines newline breaks will be converted to HTML newline breaks.
1573 :     * @return string
1574 :     */
1575 :    
1576 : moodler 1.225 function text_to_html($text, $smiley=true, $para=true, $newlines=true) {
1577 : urs_hunkler 1.347 ///
1578 : martin 1.2
1579 : moodler 1.149 global $CFG;
1580 :    
1581 : moodler 1.30 /// Remove any whitespace that may be between HTML tags
1582 : nicolasconnault 1.1271 $text = preg_replace("~>([[:space:]]+)<~i", "><", $text);
1583 : martin 1.15
1584 : moodler 1.30 /// Remove any returns that precede or follow HTML tags
1585 : nicolasconnault 1.1271 $text = preg_replace("~([\n\r])<~i", " <", $text);
1586 :     $text = preg_replace("~>([\n\r])~i", "> ", $text);
1587 : martin 1.15
1588 : moodler 1.92 convert_urls_into_links($text);
1589 : martin 1.1
1590 : moodler 1.30 /// Make returns into HTML newlines.
1591 : moodler 1.225 if ($newlines) {
1592 :     $text = nl2br($text);
1593 :     }
1594 : martin 1.1
1595 : moodler 1.30 /// Turn smileys into images.
1596 : martin 1.4 if ($smiley) {
1597 : moodler 1.92 replace_smilies($text);
1598 : martin 1.4 }
1599 : martin 1.1
1600 : moodler 1.30 /// Wrap the whole thing in a paragraph tag if required
1601 : martin 1.13 if ($para) {
1602 : dhawes 1.301 return '<p>'.$text.'</p>';
1603 : martin 1.13 } else {
1604 :     return $text;
1605 :     }
1606 : moodler 1.84 }
1607 :    
1608 : dhawes 1.304 /**
1609 :     * Given Markdown formatted text, make it into XHTML using external function
1610 :     *
1611 : samhemelryk 1.1255 * @global object
1612 : dhawes 1.308 * @param string $text The markdown formatted text to be converted.
1613 :     * @return string Converted text
1614 : dhawes 1.304 */
1615 : moodler 1.265 function markdown_to_html($text) {
1616 :     global $CFG;
1617 :    
1618 : dhawes 1.301 require_once($CFG->libdir .'/markdown.php');
1619 : moodler 1.265
1620 :     return Markdown($text);
1621 :     }
1622 :    
1623 : dhawes 1.304 /**
1624 : dhawes 1.308 * Given HTML text, make it into plain text using external function
1625 : dhawes 1.304 *
1626 : samhemelryk 1.1255 * @global object
1627 : dhawes 1.304 * @param string $html The text to be converted.
1628 :     * @return string
1629 :     */
1630 : moodler 1.176 function html_to_text($html) {
1631 : dhawes 1.308
1632 : moodler 1.177 global $CFG;
1633 : moodler 1.176
1634 : dhawes 1.301 require_once($CFG->libdir .'/html2text.php');
1635 : moodler 1.176
1636 : fmarier 1.1187 $h2t = new html2text($html);
1637 :     $result = $h2t->get_text();
1638 : dongsheng 1.1103
1639 : sam_marshall 1.1087 return $result;
1640 : moodler 1.176 }
1641 :    
1642 : dhawes 1.304 /**
1643 :     * Given some text this function converts any URLs it finds into HTML links
1644 :     *
1645 :     * @param string $text Passed in by reference. The string to be searched for urls.
1646 :     */
1647 : moodler 1.92 function convert_urls_into_links(&$text) {
1648 :     /// Make lone URLs into links. eg http://moodle.com/
1649 : nicolasconnault 1.1271 $text = preg_replace("~([[:space:]]|^|\(|\[)([[:alnum:]]+)://([^[:space:]]*)([[:alnum:]#?/&=])~i",
1650 : nicolasconnault 1.1272 '$1<a href="$2://$3$4">$2://$3$4</a>', $text);
1651 : moodler 1.92
1652 :     /// eg www.moodle.com
1653 : nicolasconnault 1.1271 $text = preg_replace("~([[:space:]]|^|\(|\[)www\.([^[:space:]]*)([[:alnum:]#?/&=])~i",
1654 : nicolasconnault 1.1272 '$1<a href="http://www.$2$3">www.$2$3</a>', $text);
1655 : martin 1.9 }
1656 :    
1657 : dhawes 1.304 /**
1658 :     * This function will highlight search words in a given string
1659 : samhemelryk 1.1255 *
1660 : dhawes 1.304 * It cares about HTML and will not ruin links. It's best to use
1661 :     * this function after performing any conversions to HTML.
1662 :     *
1663 : tjhunt 1.1186 * @param string $needle The search string. Syntax like "word1 +word2 -word3" is dealt with correctly.
1664 :     * @param string $haystack The string (HTML) within which to highlight the search terms.
1665 :     * @param boolean $matchcase whether to do case-sensitive. Default case-insensitive.
1666 :     * @param string $prefix the string to put before each search term found.
1667 :     * @param string $suffix the string to put after each search term found.
1668 :     * @return string The highlighted HTML.
1669 : dhawes 1.304 */
1670 : tjhunt 1.1186 function highlight($needle, $haystack, $matchcase = false,
1671 :     $prefix = '<span class="highlight">', $suffix = '</span>') {
1672 : skodak 1.1015
1673 : tjhunt 1.1186 /// Quick bail-out in trivial cases.
1674 : skodak 1.1015 if (empty($needle) or empty($haystack)) {
1675 : moodler 1.184 return $haystack;
1676 :     }
1677 : moodler 1.123
1678 : tjhunt 1.1186 /// Break up the search term into words, discard any -words and build a regexp.
1679 :     $words = preg_split('/ +/', trim($needle));
1680 :     foreach ($words as $index => $word) {
1681 :     if (strpos($word, '-') === 0) {
1682 :     unset($words[$index]);
1683 :     } else if (strpos($word, '+') === 0) {
1684 :     $words[$index] = '\b' . preg_quote(ltrim($word, '+'), '/') . '\b'; // Match only as a complete word.
1685 :     } else {
1686 :     $words[$index] = preg_quote($word, '/');
1687 : moodler 1.123 }
1688 :     }
1689 : tjhunt 1.1186 $regexp = '/(' . implode('|', $words) . ')/u'; // u is do UTF-8 matching.
1690 :     if (!$matchcase) {
1691 :     $regexp .= 'i';
1692 :     }
1693 : moodler 1.123
1694 : tjhunt 1.1186 /// Another chance to bail-out if $search was only -words
1695 :     if (empty($words)) {
1696 :     return $haystack;
1697 : moodler 1.123 }
1698 :    
1699 : tjhunt 1.1186 /// Find all the HTML tags in the input, and store them in a placeholders array.
1700 :     $placeholders = array();
1701 :     $matches = array();
1702 :     preg_match_all('/<[^>]*>/', $haystack, $matches);
1703 :     foreach (array_unique($matches[0]) as $key => $htmltag) {
1704 :     $placeholders['<|' . $key . '|>'] = $htmltag;
1705 : moodler 1.123 }
1706 :    
1707 : tjhunt 1.1186 /// In $hastack, replace each HTML tag with the corresponding placeholder.
1708 :     $haystack = str_replace($placeholders, array_keys($placeholders), $haystack);
1709 : fiedorow 1.333
1710 : tjhunt 1.1186 /// In the resulting string, Do the highlighting.
1711 :     $haystack = preg_replace($regexp, $prefix . '$1' . $suffix, $haystack);
1712 : fiedorow 1.333
1713 : tjhunt 1.1186 /// Turn the placeholders back into HTML tags.
1714 :     $haystack = str_replace(array_keys($placeholders), $placeholders, $haystack);
1715 : moodler 1.123
1716 : moodler 1.305 return $haystack;
1717 : moodler 1.123 }
1718 :    
1719 : dhawes 1.304 /**
1720 :     * This function will highlight instances of $needle in $haystack
1721 : samhemelryk 1.1255 *
1722 :     * It's faster that the above function {@link highlight()} and doesn't care about
1723 : dhawes 1.304 * HTML or anything.
1724 :     *
1725 :     * @param string $needle The string to search for
1726 :     * @param string $haystack The string to search for $needle in
1727 : samhemelryk 1.1255 * @return string The highlighted HTML
1728 : dhawes 1.304 */
1729 : moodler 1.123 function highlightfast($needle, $haystack) {
1730 : martin 1.9
1731 : skodak 1.1015 if (empty($needle) or empty($haystack)) {
1732 :     return $haystack;
1733 :     }
1734 :    
1735 : skodak 1.673 $parts = explode(moodle_strtolower($needle), moodle_strtolower($haystack));
1736 : martin 1.9
1737 : skodak 1.1015 if (count($parts) === 1) {
1738 :     return $haystack;
1739 :     }
1740 :    
1741 : martin 1.9 $pos = 0;
1742 :    
1743 :     foreach ($parts as $key => $part) {
1744 :     $parts[$key] = substr($haystack, $pos, strlen($part));
1745 :     $pos += strlen($part);
1746 :    
1747 : dhawes 1.301 $parts[$key] .= '<span class="highlight">'.substr($haystack, $pos, strlen($needle)).'</span>';
1748 : martin 1.9 $pos += strlen($needle);
1749 : defacer 1.242 }
1750 : martin 1.9
1751 : skodak 1.1015 return str_replace('<span class="highlight"></span>', '', join('', $parts));
1752 : moodler 1.39 }
1753 :    
1754 : nfreear 1.817 /**
1755 :     * Return a string containing 'lang', xml:lang and optionally 'dir' HTML attributes.
1756 :     * Internationalisation, for print_header and backup/restorelib.
1757 : samhemelryk 1.1255 *
1758 :     * @param bool $dir Default false
1759 :     * @return string Attributes
1760 : nfreear 1.817 */
1761 :     function get_html_lang($dir = false) {
1762 :     $direction = '';
1763 :     if ($dir) {
1764 :     if (get_string('thisdirection') == 'rtl') {
1765 :     $direction = ' dir="rtl"';
1766 :     } else {
1767 :     $direction = ' dir="ltr"';
1768 :     }
1769 :     }
1770 :     //Accessibility: added the 'lang' attribute to $direction, used in theme <html> tag.
1771 :     $language = str_replace('_', '-', str_replace('_utf8', '', current_language()));
1772 : nfreear 1.836 @header('Content-Language: '.$language);
1773 : jamiesensei 1.894 return ($direction.' lang="'.$language.'" xml:lang="'.$language.'"');
1774 : nfreear 1.817 }
1775 :    
1776 : tjhunt 1.1278
1777 :     /// STANDARD WEB PAGE PARTS ///////////////////////////////////////////////////
1778 :    
1779 : nfreear 1.979 /**
1780 : tjhunt 1.1278 * Send the HTTP headers that Moodle requires.
1781 :     * @param $cacheable Can this page be cached on back?
1782 : nfreear 1.979 */
1783 : tjhunt 1.1278 function send_headers($contenttype, $cacheable = true) {
1784 :     @header('Content-Type: ' . $contenttype);
1785 :     @header('Content-Script-Type: text/javascript');
1786 :     @header('Content-Style-Type: text/css');
1787 :    
1788 :     if ($cacheable) {
1789 :     // Allow caching on "back" (but not on normal clicks)
1790 :     @header('Cache-Control: private, pre-check=0, post-check=0, max-age=0');
1791 :     @header('Pragma: no-cache');
1792 :     @header('Expires: ');
1793 :     } else {
1794 :     // Do everything we can to always prevent clients and proxies caching
1795 :     @header('Cache-Control: no-store, no-cache, must-revalidate');
1796 :     @header('Cache-Control: post-check=0, pre-check=0', false);
1797 :     @header('Pragma: no-cache');
1798 :     @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT');
1799 :     @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
1800 :     }
1801 :     @header('Accept-Ranges: none');
1802 : nfreear 1.979 }
1803 :    
1804 : dhawes 1.304 /**
1805 :     * Returns text to be displayed to the user which reflects their login status
1806 :     *
1807 : samhemelryk 1.1255 * @global object
1808 :     * @global object
1809 :     * @global object
1810 :     * @global object
1811 :     * @uses CONTEXT_COURSE
1812 : dhawes 1.308 * @param course $course {@link $COURSE} object containing course information
1813 :     * @param user $user {@link $USER} object containing user information
1814 : samhemelryk 1.1255 * @return string HTML
1815 : dhawes 1.304 */
1816 : moodler 1.389 function user_login_string($course=NULL, $user=NULL) {
1817 : skodak 1.1073 global $USER, $CFG, $SITE, $DB;
1818 : moodler 1.80
1819 : tjhunt 1.1278 if (during_initial_install()) {
1820 :     return '';
1821 :     }
1822 :    
1823 : skodak 1.620 if (empty($user) and !empty($USER->id)) {
1824 : moodler 1.80 $user = $USER;
1825 :     }
1826 :    
1827 : moodler 1.389 if (empty($course)) {
1828 :     $course = $SITE;
1829 :     }
1830 :    
1831 : skodak 1.1194 if (session_is_loggedinas()) {
1832 :     $realuser = session_get_realuser();
1833 : skodak 1.1193 $fullname = fullname($realuser, true);
1834 :     $realuserinfo = " [<a $CFG->frametarget
1835 :     href=\"$CFG->wwwroot/course/loginas.php?id=$course->id&amp;return=1&amp;sesskey=".sesskey()."\">$fullname</a>] ";
1836 : moodler 1.41 } else {
1837 : dhawes 1.301 $realuserinfo = '';
1838 : moodler 1.39 }
1839 :    
1840 : skodak 1.1195 $loginurl = get_login_url();
1841 : julmis 1.255
1842 : skodak 1.640 if (empty($course->id)) {
1843 :     // $course->id is not defined during installation
1844 :     return '';
1845 : skodak 1.852 } else if (!empty($user->id)) {
1846 : moodler 1.647 $context = get_context_instance(CONTEXT_COURSE, $course->id);
1847 :    
1848 : moodler 1.181 $fullname = fullname($user, true);
1849 : skodak 1.743 $username = "<a $CFG->frametarget href=\"$CFG->wwwroot/user/view.php?id=$user->id&amp;course=$course->id\">$fullname</a>";
1850 : skodak 1.1073 if (is_mnet_remote_user($user) and $idprovider = $DB->get_record('mnet_host', array('id'=>$user->mnethostid))) {
1851 : skodak 1.743 $username .= " from <a $CFG->frametarget href=\"{$idprovider->wwwroot}\">{$idprovider->name}</a>";
1852 : martinlanghoff 1.735 }
1853 : moodler 1.639 if (isset($user->username) && $user->username == 'guest') {
1854 : moodler 1.456 $loggedinas = $realuserinfo.get_string('loggedinasguest').
1855 : skodak 1.1195 " (<a $CFG->frametarget href=\"$loginurl\">".get_string('login').'</a>)';
1856 : martinlanghoff 1.944 } else if (!empty($user->access['rsw'][$context->path])) {
1857 : moodler 1.645 $rolename = '';
1858 : skodak 1.1073 if ($role = $DB->get_record('role', array('id'=>$user->access['rsw'][$context->path]))) {
1859 : moodler 1.645 $rolename = ': '.format_string($role->name);
1860 :     }
1861 :     $loggedinas = get_string('loggedinas', 'moodle', $username).$rolename.
1862 : skodak 1.743 " (<a $CFG->frametarget
1863 : moodler 1.645 href=\"$CFG->wwwroot/course/view.php?id=$course->id&amp;switchrole=0&amp;sesskey=".sesskey()."\">".get_string('switchrolereturn').'</a>)';
1864 : gustav_delius 1.244 } else {
1865 : moodler 1.621 $loggedinas = $realuserinfo.get_string('loggedinas', 'moodle', $username).' '.
1866 : skodak 1.828 " (<a $CFG->frametarget href=\"$CFG->wwwroot/login/logout.php?sesskey=".sesskey()."\">".get_string('logout').'</a>)';
1867 : gustav_delius 1.244 }
1868 : moodler 1.39 } else {
1869 : dhawes 1.301 $loggedinas = get_string('loggedinnot', 'moodle').
1870 : skodak 1.1195 " (<a $CFG->frametarget href=\"$loginurl\">".get_string('login').'</a>)';
1871 : moodler 1.39 }
1872 : tjhunt 1.1278
1873 :     $loggedinas = '<div class="logininfo">'.$loggedinas.'</div>';
1874 :    
1875 :     if (isset($SESSION->justloggedin)) {
1876 :     unset($SESSION->justloggedin);
1877 :     if (!empty($CFG->displayloginfailures)) {
1878 :     if (!empty($USER->username) and $USER->username != 'guest') {
1879 :     if ($count = count_login_failures($CFG->displayloginfailures, $USER->username, $USER->lastlogin)) {
1880 :     $loggedinas .= '&nbsp;<div class="loginfailures">';
1881 :     if (empty($count->accounts)) {
1882 :     $loggedinas .= get_string('failedloginattempts', '', $count);
1883 :     } else {
1884 :     $loggedinas .= get_string('failedloginattemptsall', '', $count);
1885 :     }
1886 :     if (has_capability('coursereport/log:view', get_context_instance(CONTEXT_SYSTEM))) {
1887 :     $loggedinas .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php'.
1888 :     '?chooselog=1&amp;id=1&amp;modid=site_errors">'.get_string('logs').'</a>)';
1889 :     }
1890 :     $loggedinas .= '</div>';
1891 :     }
1892 :     }
1893 :     }
1894 :     }
1895 :    
1896 :     return $loggedinas;
1897 : moodler 1.39 }
1898 :    
1899 : dhawes 1.304 /**
1900 : nfreear 1.641 * Tests whether $THEME->rarrow, $THEME->larrow have been set (theme/-/config.php).
1901 :     * If not it applies sensible defaults.
1902 :     *
1903 :     * Accessibility: right and left arrow Unicode characters for breadcrumb, calendar,
1904 : jamiesensei 1.739 * search forum block, etc. Important: these are 'silent' in a screen-reader
1905 : nfreear 1.641 * (unlike &gt; &raquo;), and must be accompanied by text.
1906 : samhemelryk 1.1255 *
1907 :     * @global object
1908 :     * @uses $_SERVER
1909 : nfreear 1.641 */
1910 :     function check_theme_arrows() {
1911 :     global $THEME;
1912 : jamiesensei 1.739
1913 : nfreear 1.641 if (!isset($THEME->rarrow) and !isset($THEME->larrow)) {
1914 : nfreear 1.692 // Default, looks good in Win XP/IE 6, Win/Firefox 1.5, Win/Netscape 8...
1915 :     // Also OK in Win 9x/2K/IE 5.x
1916 : nfreear 1.641 $THEME->rarrow = '&#x25BA;';
1917 :     $THEME->larrow = '&#x25C4;';
1918 : moodler 1.1100 if (empty($_SERVER['HTTP_USER_AGENT'])) {
1919 :     $uagent = '';
1920 :     } else {
1921 :     $uagent = $_SERVER['HTTP_USER_AGENT'];
1922 :     }
1923 : nfreear 1.692 if (false !== strpos($uagent, 'Opera')
1924 :     || false !== strpos($uagent, 'Mac')) {
1925 :     // Looks good in Win XP/Mac/Opera 8/9, Mac/Firefox 2, Camino, Safari.
1926 :     // Not broken in Mac/IE 5, Mac/Netscape 7 (?).
1927 : nfreear 1.641 $THEME->rarrow = '&#x25B6;';
1928 :     $THEME->larrow = '&#x25C0;';
1929 : nfreear 1.692 }
1930 :     elseif (false !== strpos($uagent, 'Konqueror')) {
1931 :     $THEME->rarrow = '&rarr;';
1932 :     $THEME->larrow = '&larr;';
1933 :     }
1934 :     elseif (isset($_SERVER['HTTP_ACCEPT_CHARSET'])
1935 :     && false === stripos($_SERVER['HTTP_ACCEPT_CHARSET'], 'utf-8')) {
1936 :     // (Win/IE 5 doesn't set ACCEPT_CHARSET, but handles Unicode.)
1937 :     // To be safe, non-Unicode browsers!
1938 :     $THEME->rarrow = '&gt;';
1939 :     $THEME->larrow = '&lt;';
1940 :     }
1941 : jamiesensei 1.1023
1942 : moodler 1.922 /// RTL support - in RTL languages, swap r and l arrows
1943 : jamiesensei 1.1023 if (right_to_left()) {
1944 :     $t = $THEME->rarrow;
1945 :     $THEME->rarrow = $THEME->larrow;
1946 :     $THEME->larrow = $t;
1947 :     }
1948 : nfreear 1.641 }
1949 :     }
1950 :    
1951 : moodler 1.922
1952 : nfreear 1.641 /**
1953 : nfreear 1.881 * Return the right arrow with text ('next'), and optionally embedded in a link.
1954 :     * See function above, check_theme_arrows.
1955 : samhemelryk 1.1255 *
1956 :     * @global object
1957 : nfreear 1.886 * @param string $text HTML/plain text label (set to blank only for breadcrumb separator cases).
1958 : nfreear 1.881 * @param string $url An optional link to use in a surrounding HTML anchor.
1959 :     * @param bool $accesshide True if text should be hidden (for screen readers only).
1960 :     * @param string $addclass Additional class names for the link, or the arrow character.
1961 :     * @return string HTML string.
1962 : nfreear 1.879 */
1963 : nfreear 1.881 function link_arrow_right($text, $url='', $accesshide=false, $addclass='') {
1964 : nfreear 1.879 global $THEME;
1965 :     check_theme_arrows();
1966 : nfreear 1.881 $arrowclass = 'arrow ';
1967 :     if (! $url) {
1968 :     $arrowclass .= $addclass;
1969 :     }
1970 :     $arrow = '<span class="'.$arrowclass.'">'.$THEME->rarrow.'</span>';
1971 :     $htmltext = '';
1972 :     if ($text) {
1973 : sam_marshall 1.1071 $htmltext = '<span class="arrow_text">'.$text.'</span>&nbsp;';
1974 : nfreear 1.881 if ($accesshide) {
1975 : nfreear 1.954 $htmltext = get_accesshide($htmltext);
1976 : nfreear 1.881 }
1977 :     }
1978 :     if ($url) {
1979 : sam_marshall 1.1071 $class = 'arrow_link';
1980 : nfreear 1.881 if ($addclass) {
1981 : sam_marshall 1.1071 $class .= ' '.$addclass;
1982 : nfreear 1.881 }
1983 : sam_marshall 1.1071 return '<a class="'.$class.'" href="'.$url.'" title="'.preg_replace('/<.*?>/','',$text).'">'.$htmltext.$arrow.'</a>';
1984 : nfreear 1.879