Fixed bug 5187 that led to error when creating cloze question
[moodle.git] / lib / weblib.php
CommitLineData
abf45bed 1<?php // $Id$
f9903ed0 2
9fa49e22 3///////////////////////////////////////////////////////////////////////////
4// //
5// NOTICE OF COPYRIGHT //
6// //
7// Moodle - Modular Object-Oriented Dynamic Learning Environment //
8// http://moodle.com //
9// //
10// Copyright (C) 2001-2003 Martin Dougiamas http://dougiamas.com //
11// //
12// This program is free software; you can redistribute it and/or modify //
13// it under the terms of the GNU General Public License as published by //
14// the Free Software Foundation; either version 2 of the License, or //
15// (at your option) any later version. //
16// //
17// This program is distributed in the hope that it will be useful, //
18// but WITHOUT ANY WARRANTY; without even the implied warranty of //
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
20// GNU General Public License for more details: //
21// //
22// http://www.gnu.org/copyleft/gpl.html //
23// //
24///////////////////////////////////////////////////////////////////////////
f9903ed0 25
7cf1c7bd 26/**
27 * Library of functions for web output
28 *
29 * Library of all general-purpose Moodle PHP functions and constants
30 * that produce HTML output
31 *
32 * Other main libraries:
33 * - datalib.php - functions that access the database.
34 * - moodlelib.php - general-purpose Moodle functions.
35 * @author Martin Dougiamas
36 * @version $Id$
89dcb99d 37 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
7cf1c7bd 38 * @package moodlecore
39 */
772e78be 40
6aaa17c7 41/// We are going to uses filterlib functions here
42require_once("$CFG->libdir/filterlib.php");
43
0095d5cd 44/// Constants
45
c1d57101 46/// Define text formatting types ... eventually we can add Wiki, BBcode etc
7cf1c7bd 47
48/**
49 * Does all sorts of transformations and filtering
50 */
b0ccd3fb 51define('FORMAT_MOODLE', '0'); // Does all sorts of transformations and filtering
7cf1c7bd 52
53/**
54 * Plain HTML (with some tags stripped)
55 */
b0ccd3fb 56define('FORMAT_HTML', '1'); // Plain HTML (with some tags stripped)
7cf1c7bd 57
58/**
59 * Plain text (even tags are printed in full)
60 */
b0ccd3fb 61define('FORMAT_PLAIN', '2'); // Plain text (even tags are printed in full)
7cf1c7bd 62
63/**
64 * Wiki-formatted text
6a6495ff 65 * Deprecated: left here just to note that '3' is not used (at the moment)
66 * and to catch any latent wiki-like text (which generates an error)
7cf1c7bd 67 */
b0ccd3fb 68define('FORMAT_WIKI', '3'); // Wiki-formatted text
7cf1c7bd 69
70/**
71 * Markdown-formatted text http://daringfireball.net/projects/markdown/
72 */
b0ccd3fb 73define('FORMAT_MARKDOWN', '4'); // Markdown-formatted text http://daringfireball.net/projects/markdown/
0095d5cd 74
7cf1c7bd 75
76/**
77 * Allowed tags - string of html tags that can be tested against for safe html tags
78 * @global string $ALLOWED_TAGS
79 */
39dda0fc 80$ALLOWED_TAGS =
d046ae55 81'<p><br><b><i><u><font><table><tbody><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>';
82
037dcbb6 83/**
84 * Allowed protocols - array of protocols that are safe to use in links and so on
85 * @global string $ALLOWED_PROTOCOLS
86 */
f941df22 87$ALLOWED_PROTOCOLS = array('http', 'https', 'ftp', 'news', 'mailto', 'rtsp', 'teamspeak', 'gopher', 'mms',
c06c8492 88 'color', 'callto', 'cursor', 'text-align', 'font-size', 'font-weight', 'font-style',
cd76de7e 89 'border', 'margin', 'padding'); // CSS as well to get through kses
037dcbb6 90
91
0095d5cd 92/// Functions
93
7cf1c7bd 94/**
95 * Add quotes to HTML characters
96 *
97 * Returns $var with HTML characters (like "<", ">", etc.) properly quoted.
98 * This function is very similar to {@link p()}
99 *
100 * @param string $var the string potentially containing HTML characters
d4a42ff4 101 * @param boolean $strip to decide if we want to strip slashes or no. Default to false.
102 * true should be used to print data from forms and false for data from DB.
7cf1c7bd 103 * @return string
104 */
d4a42ff4 105function s($var, $strip=false) {
106
63e554d0 107 if ($var == '0') { // for integer 0, boolean false, string '0'
108 return '0';
3662bce5 109 }
d4a42ff4 110
111 if ($strip) {
112 return preg_replace("/&amp;(#\d+);/i", "&$1;", htmlspecialchars(stripslashes_safe($var)));
113 } else {
114 return preg_replace("/&amp;(#\d+);/i", "&$1;", htmlspecialchars($var));
115 }
f9903ed0 116}
117
7cf1c7bd 118/**
119 * Add quotes to HTML characters
120 *
d48b00b4 121 * Prints $var with HTML characters (like "<", ">", etc.) properly quoted.
7cf1c7bd 122 * This function is very similar to {@link s()}
123 *
124 * @param string $var the string potentially containing HTML characters
d4a42ff4 125 * @param boolean $strip to decide if we want to strip slashes or no. Default to false.
126 * true should be used to print data from forms and false for data from DB.
7cf1c7bd 127 * @return string
128 */
d4a42ff4 129function p($var, $strip=false) {
130 echo s($var, $strip);
f9903ed0 131}
132
7cf1c7bd 133
134/**
135 * Ensure that a variable is set
136 *
772e78be 137 * Return $var if it is defined, otherwise return $default,
7cf1c7bd 138 * This function is very similar to {@link optional_variable()}
139 *
140 * @param mixed $var the variable which may be unset
141 * @param mixed $default the value to return if $var is unset
142 * @return mixed
143 */
b0ccd3fb 144function nvl(&$var, $default='') {
8553b700 145
146 return isset($var) ? $var : $default;
147}
f9903ed0 148
7cf1c7bd 149/**
150 * Remove query string from url
151 *
152 * Takes in a URL and returns it without the querystring portion
153 *
154 * @param string $url the url which may have a query string attached
155 * @return string
156 */
157 function strip_querystring($url) {
f9903ed0 158
b9b8ab69 159 if ($commapos = strpos($url, '?')) {
160 return substr($url, 0, $commapos);
161 } else {
162 return $url;
163 }
f9903ed0 164}
165
7cf1c7bd 166/**
167 * Returns the URL of the HTTP_REFERER, less the querystring portion
168 * @return string
169 */
f9903ed0 170function get_referer() {
f9903ed0 171
b0ccd3fb 172 return strip_querystring(nvl($_SERVER['HTTP_REFERER']));
f9903ed0 173}
174
c1d57101 175
7cf1c7bd 176/**
177 * Returns the name of the current script, WITH the querystring portion.
178 * this function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
179 * return different things depending on a lot of things like your OS, Web
180 * server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.)
d48b00b4 181 * <b>NOTE:</b> This function returns false if the global variables needed are not set.
182 *
7cf1c7bd 183 * @return string
184 */
185 function me() {
f9903ed0 186
b0ccd3fb 187 if (!empty($_SERVER['REQUEST_URI'])) {
188 return $_SERVER['REQUEST_URI'];
c1d57101 189
b0ccd3fb 190 } else if (!empty($_SERVER['PHP_SELF'])) {
191 if (!empty($_SERVER['QUERY_STRING'])) {
192 return $_SERVER['PHP_SELF'] .'?'. $_SERVER['QUERY_STRING'];
fced815c 193 }
b0ccd3fb 194 return $_SERVER['PHP_SELF'];
c1d57101 195
b0ccd3fb 196 } else if (!empty($_SERVER['SCRIPT_NAME'])) {
197 if (!empty($_SERVER['QUERY_STRING'])) {
198 return $_SERVER['SCRIPT_NAME'] .'?'. $_SERVER['QUERY_STRING'];
fced815c 199 }
b0ccd3fb 200 return $_SERVER['SCRIPT_NAME'];
fced815c 201
b0ccd3fb 202 } else if (!empty($_SERVER['URL'])) { // May help IIS (not well tested)
203 if (!empty($_SERVER['QUERY_STRING'])) {
204 return $_SERVER['URL'] .'?'. $_SERVER['QUERY_STRING'];
16c4d82a 205 }
b0ccd3fb 206 return $_SERVER['URL'];
16c4d82a 207
b9b8ab69 208 } else {
b0ccd3fb 209 notify('Warning: Could not find any of these web server variables: $REQUEST_URI, $PHP_SELF, $SCRIPT_NAME or $URL');
bcdfe14e 210 return false;
7fbd6b1c 211 }
f9903ed0 212}
213
7cf1c7bd 214/**
d48b00b4 215 * Like {@link me()} but returns a full URL
7cf1c7bd 216 * @see me()
7cf1c7bd 217 * @return string
218 */
f9903ed0 219function qualified_me() {
f9903ed0 220
b6e22603 221 global $CFG;
222
68796e6b 223 if (!empty($CFG->wwwroot)) {
224 $url = parse_url($CFG->wwwroot);
225 }
b6e22603 226
227 if (!empty($url['host'])) {
228 $hostname = $url['host'];
229 } else if (!empty($_SERVER['SERVER_NAME'])) {
b0ccd3fb 230 $hostname = $_SERVER['SERVER_NAME'];
231 } else if (!empty($_ENV['SERVER_NAME'])) {
232 $hostname = $_ENV['SERVER_NAME'];
233 } else if (!empty($_SERVER['HTTP_HOST'])) {
234 $hostname = $_SERVER['HTTP_HOST'];
235 } else if (!empty($_ENV['HTTP_HOST'])) {
236 $hostname = $_ENV['HTTP_HOST'];
39e018b3 237 } else {
b0ccd3fb 238 notify('Warning: could not find the name of this server!');
bcdfe14e 239 return false;
c1d57101 240 }
dc28eede 241
242 if (!empty($url['port'])) {
243 $hostname .= ':'.$url['port'];
244 } else if (!empty($_SERVER['SERVER_PORT'])) {
245 if ($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
246 $hostname .= ':'.$_SERVER['SERVER_PORT'];
247 }
248 }
249
f77c261e 250 if (isset($_SERVER['HTTPS'])) {
251 $protocol = ($_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
252 } else if (isset($_SERVER['SERVER_PORT'])) { # Apache2 does not export $_SERVER['HTTPS']
253 $protocol = ($_SERVER['SERVER_PORT'] == '443') ? 'https://' : 'http://';
254 } else {
255 $protocol = 'http://';
256 }
f9903ed0 257
39e018b3 258 $url_prefix = $protocol.$hostname;
b9b8ab69 259 return $url_prefix . me();
f9903ed0 260}
261
7cf1c7bd 262/**
263 * Determine if a web referer is valid
264 *
265 * Returns true if the referer is the same as the goodreferer. If
266 * the referer to test is not specified, use {@link qualified_me()}.
267 * If the admin has not set secure forms ($CFG->secureforms) then
268 * this function returns true regardless of a match.
d48b00b4 269 *
7cf1c7bd 270 * @uses $CFG
271 * @param string $goodreferer the url to compare to referer
272 * @return boolean
273 */
b0ccd3fb 274function match_referer($goodreferer = '') {
60f18531 275 global $CFG;
276
ae384ef1 277 if (empty($CFG->secureforms)) { // Don't bother checking referer
60f18531 278 return true;
279 }
f9903ed0 280
b0ccd3fb 281 if ($goodreferer == 'nomatch') { // Don't bother checking referer
a0deb5db 282 return true;
283 }
284
ab9f24ad 285 if (empty($goodreferer)) {
286 $goodreferer = qualified_me();
c1d57101 287 }
67b1b6c2 288
9d54c2fb 289 $referer = get_referer();
290
ad489e94 291 return (($referer == $goodreferer) or ($referer == $CFG->wwwroot .'/') or ($referer == $CFG->wwwroot .'/index.php'));
f9903ed0 292}
293
7cf1c7bd 294/**
295 * Determine if there is data waiting to be processed from a form
296 *
297 * Used on most forms in Moodle to check for data
298 * Returns the data as an object, if it's found.
299 * This object can be used in foreach loops without
300 * casting because it's cast to (array) automatically
772e78be 301 *
7cf1c7bd 302 * Checks that submitted POST data exists, and also
303 * checks the referer against the given url (it uses
d48b00b4 304 * the current page if none was specified.
305 *
7cf1c7bd 306 * @uses $CFG
307 * @param string $url the url to compare to referer for secure forms
308 * @return boolean
309 */
b0ccd3fb 310function data_submitted($url='') {
d48b00b4 311
36b4f985 312
37208cd2 313 global $CFG;
314
607809b3 315 if (empty($_POST)) {
36b4f985 316 return false;
607809b3 317
36b4f985 318 } else {
319 if (match_referer($url)) {
607809b3 320 return (object)$_POST;
36b4f985 321 } else {
322 if ($CFG->debug > 10) {
b0ccd3fb 323 notice('The form did not come from this page! (referer = '. get_referer() .')');
36b4f985 324 }
325 return false;
326 }
327 }
328}
329
7cf1c7bd 330/**
331 * Moodle replacement for php stripslashes() function
332 *
772e78be 333 * The standard php stripslashes() removes ALL backslashes
7cf1c7bd 334 * even from strings - so C:\temp becomes C:temp - this isn't good.
335 * This function should work as a fairly safe replacement
336 * to be called on quoted AND unquoted strings (to be sure)
d48b00b4 337 *
7cf1c7bd 338 * @param string the string to remove unsafe slashes from
339 * @return string
340 */
7d8f674d 341function stripslashes_safe($string) {
7d8f674d 342
343 $string = str_replace("\\'", "'", $string);
344 $string = str_replace('\\"', '"', $string);
b403c32a 345 $string = str_replace('\\\\', '\\', $string);
7d8f674d 346 return $string;
347}
f9903ed0 348
9b4b78fd 349/**
350 * Recursive implementation of stripslashes()
351 *
352 * This function will allow you to strip the slashes from a variable.
353 * If the variable is an array or object, slashes will be stripped
354 * from the items (or properties) it contains, even if they are arrays
355 * or objects themselves.
356 *
357 * @param mixed the variable to remove slashes from
358 * @return mixed
359 */
360function stripslashes_recursive($var) {
361 if(is_object($var)) {
362 $properties = get_object_vars($var);
363 foreach($properties as $property => $value) {
364 $var->$property = stripslashes_recursive($value);
365 }
366 }
367 else if(is_array($var)) {
368 foreach($var as $property => $value) {
369 $var[$property] = stripslashes_recursive($value);
370 }
371 }
372 else if(is_string($var)) {
373 $var = stripslashes($var);
374 }
375 return $var;
376}
377
7cf1c7bd 378/**
d48b00b4 379 * Given some normal text this function will break up any
380 * long words to a given size by inserting the given character
381 *
6aaa17c7 382 * It's multibyte savvy and doesn't change anything inside html tags.
383 *
7cf1c7bd 384 * @param string $string the string to be modified
89dcb99d 385 * @param int $maxsize maximum length of the string to be returned
7cf1c7bd 386 * @param string $cutchar the string used to represent word breaks
387 * @return string
388 */
4a5644e5 389function break_up_long_words($string, $maxsize=20, $cutchar=' ') {
a2b3f884 390
6aaa17c7 391/// Loading the textlib singleton instance. We are going to need it.
392 $textlib = textlib_get_instance();
8f7dc7f1 393
6aaa17c7 394/// First of all, save all the tags inside the text to skip them
395 $tags = array();
396 filter_save_tags($string,$tags);
5b07d990 397
6aaa17c7 398/// Process the string adding the cut when necessary
4a5644e5 399 $output = '';
6aaa17c7 400 $length = $textlib->strlen($string, current_charset());
4a5644e5 401 $wordlength = 0;
402
403 for ($i=0; $i<$length; $i++) {
6aaa17c7 404 $char = $textlib->substr($string, $i, 1, current_charset());
405 if ($char == ' ' or $char == "\t" or $char == "\n" or $char == "\r" or $char == "<" or $char == ">") {
4a5644e5 406 $wordlength = 0;
407 } else {
408 $wordlength++;
409 if ($wordlength > $maxsize) {
410 $output .= $cutchar;
411 $wordlength = 0;
412 }
413 }
414 $output .= $char;
415 }
6aaa17c7 416
417/// Finally load the tags back again
418 if (!empty($tags)) {
419 $output = str_replace(array_keys($tags), $tags, $output);
420 }
421
4a5644e5 422 return $output;
423}
424
7cf1c7bd 425/**
426 * This does a search and replace, ignoring case
427 * This function is only used for versions of PHP older than version 5
428 * which do not have a native version of this function.
429 * Taken from the PHP manual, by bradhuizenga @ softhome.net
d48b00b4 430 *
7cf1c7bd 431 * @param string $find the string to search for
432 * @param string $replace the string to replace $find with
433 * @param string $string the string to search through
434 * return string
435 */
ce57cc79 436if (!function_exists('str_ireplace')) { /// Only exists in PHP 5
7ec2fc00 437 function str_ireplace($find, $replace, $string) {
7ec2fc00 438
439 if (!is_array($find)) {
440 $find = array($find);
441 }
442
443 if(!is_array($replace)) {
444 if (!is_array($find)) {
445 $replace = array($replace);
446 } else {
447 // this will duplicate the string into an array the size of $find
448 $c = count($find);
449 $rString = $replace;
450 unset($replace);
451 for ($i = 0; $i < $c; $i++) {
452 $replace[$i] = $rString;
453 }
454 }
455 }
456
457 foreach ($find as $fKey => $fItem) {
458 $between = explode(strtolower($fItem),strtolower($string));
459 $pos = 0;
460 foreach($between as $bKey => $bItem) {
461 $between[$bKey] = substr($string,$pos,strlen($bItem));
462 $pos += strlen($bItem) + strlen($fItem);
463 }
464 $string = implode($replace[$fKey],$between);
72e4eac6 465 }
7ec2fc00 466 return ($string);
3fe3851d 467 }
3fe3851d 468}
469
7cf1c7bd 470/**
471 * Locate the position of a string in another string
472 *
473 * This function is only used for versions of PHP older than version 5
474 * which do not have a native version of this function.
475 * Taken from the PHP manual, by dmarsh @ spscc.ctc.edu
d48b00b4 476 *
7cf1c7bd 477 * @param string $haystack The string to be searched
478 * @param string $needle The string to search for
89dcb99d 479 * @param int $offset The position in $haystack where the search should begin.
7cf1c7bd 480 */
ce57cc79 481if (!function_exists('stripos')) { /// Only exists in PHP 5
482 function stripos($haystack, $needle, $offset=0) {
d48b00b4 483
ce57cc79 484 return strpos(strtoupper($haystack), strtoupper($needle), $offset);
485 }
486}
487
7cf1c7bd 488/**
489 * Load a template from file
490 *
491 * Returns a (big) string containing the contents of a template file with all
492 * the variables interpolated. all the variables must be in the $var[] array or
493 * object (whatever you decide to use).
494 *
495 * <b>WARNING: do not use this on big files!!</b>
d48b00b4 496 *
7cf1c7bd 497 * @param string $filename Location on the server's filesystem where template can be found.
498 * @param mixed $var Passed in by reference. An array or object which will be loaded with data from the template file.
499 */
f9903ed0 500function read_template($filename, &$var) {
f9903ed0 501
b0ccd3fb 502 $temp = str_replace("\\", "\\\\", implode(file($filename), ''));
b9b8ab69 503 $temp = str_replace('"', '\"', $temp);
504 eval("\$template = \"$temp\";");
505 return $template;
f9903ed0 506}
507
7cf1c7bd 508/**
509 * Set a variable's value depending on whether or not it already has a value.
510 *
772e78be 511 * If variable is set, set it to the set_value otherwise set it to the
7cf1c7bd 512 * unset_value. used to handle checkboxes when you are expecting them from
513 * a form
d48b00b4 514 *
7cf1c7bd 515 * @param mixed $var Passed in by reference. The variable to check.
516 * @param mixed $set_value The value to set $var to if $var already has a value.
517 * @param mixed $unset_value The value to set $var to if $var does not already have a value.
518 */
f9903ed0 519function checked(&$var, $set_value = 1, $unset_value = 0) {
f9903ed0 520
b9b8ab69 521 if (empty($var)) {
522 $var = $unset_value;
523 } else {
524 $var = $set_value;
525 }
f9903ed0 526}
527
7cf1c7bd 528/**
529 * Prints the word "checked" if a variable is true, otherwise prints nothing,
d48b00b4 530 * used for printing the word "checked" in a checkbox form element.
531 *
7cf1c7bd 532 * @param boolean $var Variable to be checked for true value
533 * @param string $true_value Value to be printed if $var is true
534 * @param string $false_value Value to be printed if $var is false
535 */
b0ccd3fb 536function frmchecked(&$var, $true_value = 'checked', $false_value = '') {
f9903ed0 537
b9b8ab69 538 if ($var) {
539 echo $true_value;
540 } else {
541 echo $false_value;
542 }
f9903ed0 543}
544
7cf1c7bd 545/**
546 * This function will create a HTML link that will work on both
547 * Javascript and non-javascript browsers.
548 * Relies on the Javascript function openpopup in javascript.php
d48b00b4 549 *
7cf1c7bd 550 * $url must be relative to home page eg /mod/survey/stuff.php
551 * @param string $url Web link relative to home page
552 * @param string $name Name to be assigned to the popup window
553 * @param string $linkname Text to be displayed as web link
89dcb99d 554 * @param int $height Height to assign to popup window
555 * @param int $width Height to assign to popup window
7cf1c7bd 556 * @param string $title Text to be displayed as popup page title
557 * @param string $options List of additional options for popup window
558 * @todo Add code examples and list of some options that might be used.
559 * @param boolean $return Should the link to the popup window be returned as a string (true) or printed immediately (false)?
560 * @return string
561 * @uses $CFG
562 */
b0ccd3fb 563function link_to_popup_window ($url, $name='popup', $linkname='click here',
564 $height=400, $width=500, $title='Popup window', $options='none', $return=false) {
f9903ed0 565
ff80e012 566 global $CFG;
567
b0ccd3fb 568 if ($options == 'none') {
569 $options = 'menubar=0,location=0,scrollbars,resizable,width='. $width .',height='. $height;
b48f834c 570 }
86aa7ccf 571 $fullscreen = 0;
f9903ed0 572
c80b7585 573 if (!(strpos($url,$CFG->wwwroot) === false)) { // some log url entries contain _SERVER[HTTP_REFERRER] in which case wwwroot is already there.
d2fa35a8 574 $url = substr($url, strlen($CFG->wwwroot));
c80b7585 575 }
576
b0ccd3fb 577 $link = '<a target="'. $name .'" title="'. $title .'" href="'. $CFG->wwwroot . $url .'" '.
9de39eae 578 "onclick=\"return openpopup('$url', '$name', '$options', $fullscreen);\">$linkname</a>";
1f2eec7b 579 if ($return) {
580 return $link;
581 } else {
582 echo $link;
583 }
f9903ed0 584}
585
7cf1c7bd 586/**
587 * This function will print a button submit form element
588 * that will work on both Javascript and non-javascript browsers.
589 * Relies on the Javascript function openpopup in javascript.php
d48b00b4 590 *
7cf1c7bd 591 * $url must be relative to home page eg /mod/survey/stuff.php
592 * @param string $url Web link relative to home page
593 * @param string $name Name to be assigned to the popup window
594 * @param string $linkname Text to be displayed as web link
89dcb99d 595 * @param int $height Height to assign to popup window
596 * @param int $width Height to assign to popup window
7cf1c7bd 597 * @param string $title Text to be displayed as popup page title
598 * @param string $options List of additional options for popup window
dc28eede 599 * @param string $return If true, return as a string, otherwise print
7cf1c7bd 600 * @return string
601 * @uses $CFG
602 */
b0ccd3fb 603function button_to_popup_window ($url, $name='popup', $linkname='click here',
572fe9ab 604 $height=400, $width=500, $title='Popup window', $options='none', $return=false,
0f7d4e5e 605 $id='', $class='') {
52f1b496 606
607 global $CFG;
608
b0ccd3fb 609 if ($options == 'none') {
610 $options = 'menubar=0,location=0,scrollbars,resizable,width='. $width .',height='. $height;
52f1b496 611 }
0f7d4e5e 612
613 if ($id) {
614 $id = ' id="'.$id.'" ';
615 }
616 if ($class) {
617 $class = ' class="'.$class.'" ';
618 }
52f1b496 619 $fullscreen = 0;
620
0f7d4e5e 621 $button = '<input type="button" name="'.$name.'" title="'. $title .'" value="'. $linkname .' ..." '.$id.$class.
dc28eede 622 "onclick=\"return openpopup('$url', '$name', '$options', $fullscreen);\" />\n";
623 if ($return) {
624 return $button;
625 } else {
626 echo $button;
627 }
52f1b496 628}
629
630
7cf1c7bd 631/**
632 * Prints a simple button to close a window
633 */
08396bb2 634function close_window_button($name='closewindow') {
c1d57101 635
b0ccd3fb 636 echo '<center>' . "\n";
637 echo '<script type="text/javascript">' . "\n";
638 echo '<!--' . "\n";
86aa7ccf 639 echo "document.write('<form>');\n";
d7d21c38 640 echo "document.write('<input type=\"button\" onclick=\"self.close();\" value=\"".get_string("closewindow")."\" />');\n";
c01f71d4 641 echo "document.write('<\/form>');\n";
b0ccd3fb 642 echo '-->' . "\n";
643 echo '</script>' . "\n";
644 echo '<noscript>' . "\n";
08396bb2 645 print_string($name);
b0ccd3fb 646 echo '</noscript>' . "\n";
647 echo '</center>' . "\n";
f9903ed0 648}
649
08396bb2 650/*
651 * Try and close the current window immediately using Javascript
652 */
653function close_window($delay=0) {
654 echo '<script language="JavaScript" type="text/javascript">'."\n";
655 echo '<!--'."\n";
656 if ($delay) {
657 sleep($delay);
658 }
659 echo 'self.close();'."\n";
660 echo '-->'."\n";
661 echo '</script>'."\n";
662 exit;
663}
664
665
d48b00b4 666/**
667 * Given an array of value, creates a popup menu to be part of a form
668 * $options["value"]["label"]
669 *
670 * @param type description
671 * @todo Finish documenting this function
672 */
c06c8492 673function choose_from_menu ($options, $name, $selected='', $nothing='choose', $script='',
25e5dbf9 674 $nothingvalue='0', $return=false, $disabled=false, $tabindex=0) {
ab9f24ad 675
b0ccd3fb 676 if ($nothing == 'choose') {
677 $nothing = get_string('choose') .'...';
618b22c5 678 }
679
48e535bc 680 $attributes = ($script) ? 'onchange="'. $script .'"' : '';
681 if ($disabled) {
682 $attributes .= ' disabled="disabled"';
f9903ed0 683 }
9c9f7d77 684
25e5dbf9 685 if ($tabindex) {
686 $attributes .= ' tabindex="'.$tabindex.'"';
687 }
688
dc28eede 689 $output = '<select id="menu'.$name.'" name="'. $name .'" '. $attributes .'>' . "\n";
bda8d43a 690 if ($nothing) {
b0ccd3fb 691 $output .= ' <option value="'. $nothingvalue .'"'. "\n";
cec0a0fc 692 if ($nothingvalue === $selected) {
b0ccd3fb 693 $output .= ' selected="selected"';
bda8d43a 694 }
b0ccd3fb 695 $output .= '>'. $nothing .'</option>' . "\n";
873960de 696 }
607809b3 697 if (!empty($options)) {
698 foreach ($options as $value => $label) {
b0ccd3fb 699 $output .= ' <option value="'. $value .'"';
bd905b45 700 if ((string)$value == (string)$selected) {
b0ccd3fb 701 $output .= ' selected="selected"';
607809b3 702 }
b0ccd3fb 703 if ($label === '') {
704 $output .= '>'. $value .'</option>' . "\n";
a20c1090 705 } else {
b0ccd3fb 706 $output .= '>'. $label .'</option>' . "\n";
607809b3 707 }
f9903ed0 708 }
709 }
b0ccd3fb 710 $output .= '</select>' . "\n";
08056730 711
712 if ($return) {
713 return $output;
714 } else {
715 echo $output;
716 }
ab9f24ad 717}
f9903ed0 718
14040797 719/**
720 * Just like choose_from_menu, but takes a nested array (2 levels) and makes a dropdown menu
721 * including option headings with the first level.
722 */
723function choose_from_menu_nested($options,$name,$selected='',$nothing='choose',$script = '',
724 $nothingvalue=0,$return=false,$disabled=false,$tabindex=0) {
725
726 if ($nothing == 'choose') {
727 $nothing = get_string('choose') .'...';
728 }
729
730 $attributes = ($script) ? 'onchange="'. $script .'"' : '';
731 if ($disabled) {
732 $attributes .= ' disabled="disabled"';
733 }
734
735 if ($tabindex) {
736 $attributes .= ' tabindex="'.$tabindex.'"';
737 }
738
739 $output = '<select id="menu'.$name.'" name="'. $name .'" '. $attributes .'>' . "\n";
740 if ($nothing) {
741 $output .= ' <option value="'. $nothingvalue .'"'. "\n";
742 if ($nothingvalue === $selected) {
743 $output .= ' selected="selected"';
744 }
745 $output .= '>'. $nothing .'</option>' . "\n";
746 }
747 if (!empty($options)) {
748 foreach ($options as $section => $values) {
749 $output .= ' <optgroup label="'.$section.'">'."\n";
750 foreach ($values as $value => $label) {
751 $output .= ' <option value="'. $value .'"';
f332bd02 752 if ((string)$value == (string)$selected) {
14040797 753 $output .= ' selected="selected"';
754 }
755 if ($label === '') {
756 $output .= '>'. $value .'</option>' . "\n";
757 } else {
758 $output .= '>'. $label .'</option>' . "\n";
759 }
760 }
761 $output .= ' </optgroup>'."\n";
762 }
763 }
764 $output .= '</select>' . "\n";
765
766 if ($return) {
767 return $output;
768 } else {
769 echo $output;
770 }
771}
772
773
531a3cb2 774/**
775 * Given an array of values, creates a group of radio buttons to be part of a form
c06c8492 776 *
531a3cb2 777 * @param array $options An array of value-label pairs for the radio group (values as keys)
778 * @param string $name Name of the radiogroup (unique in the form)
779 * @param string $checked The value that is already checked
780 */
781function choose_from_radio ($options, $name, $checked='') {
782
20cbef63 783 static $idcounter = 0;
784
531a3cb2 785 if (!$name) {
786 $name = 'unnamed';
787 }
788
789 $output = '<span class="radiogroup '.$name."\">\n";
790
791 if (!empty($options)) {
792 $currentradio = 0;
793 foreach ($options as $value => $label) {
20cbef63 794 $htmlid = 'auto-rb'.sprintf('%04d', ++$idcounter);
795 $output .= ' <span class="radioelement '.$name.' rb'.$currentradio."\">";
796 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="radio" value="'.$value.'"';
531a3cb2 797 if ($value == $checked) {
798 $output .= ' checked="checked"';
799 }
800 if ($label === '') {
20cbef63 801 $output .= ' /> <label for="'.$htmlid.'">'. $value .'</label></span>' . "\n";
531a3cb2 802 } else {
20cbef63 803 $output .= ' /> <label for="'.$htmlid.'">'. $label .'</label></span>' . "\n";
531a3cb2 804 }
805 $currentradio = ($currentradio + 1) % 2;
806 }
807 }
808
809 $output .= '</span>' . "\n";
810
811 echo $output;
812}
813
2481037f 814/** Display an standard html checkbox with an optional label
815 *
816 * @param string $name The name of the checkbox
817 * @param string $value The valus that the checkbox will pass when checked
818 * @param boolean $checked The flag to tell the checkbox initial state
819 * @param string $label The label to be showed near the checkbox
820 * @param string $alt The info to be inserted in the alt tag
821 */
d0d272e7 822function print_checkbox ($name, $value, $checked = true, $label = '', $alt = '', $script='',$return=false) {
2481037f 823
20cbef63 824 static $idcounter = 0;
825
2481037f 826 if (!$name) {
827 $name = 'unnamed';
828 }
829
830 if (!$alt) {
831 $alt = 'checkbox';
832 }
833
834 if ($checked) {
835 $strchecked = ' checked="checked"';
f89f924e 836 } else {
837 $strchecked = '';
2481037f 838 }
839
20cbef63 840 $htmlid = 'auto-cb'.sprintf('%04d', ++$idcounter);
2481037f 841 $output = '<span class="checkbox '.$name."\">";
d0d272e7 842 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="checkbox" value="'.$value.'" alt="'.$alt.'"'.$strchecked.' '.((!empty($script)) ? ' onClick="'.$script.'" ' : '').' />';
20cbef63 843 if(!empty($label)) {
844 $output .= ' <label for="'.$htmlid.'">'.$label.'</label>';
845 }
2481037f 846 $output .= '</span>'."\n";
847
d0d272e7 848 if (empty($return)) {
849 echo $output;
850 } else {
851 return $output;
852 }
2481037f 853
854}
855
d0d272e7 856/** Display an standard html text field with an optional label
857 *
858 * @param string $name The name of the text field
859 * @param string $value The value of the text field
860 * @param string $label The label to be showed near the text field
861 * @param string $alt The info to be inserted in the alt tag
862 */
863function print_textfield ($name, $value, $alt = '',$size=50,$maxlength= 0,$return=false) {
864
865 static $idcounter = 0;
866
867 if (empty($name)) {
868 $name = 'unnamed';
869 }
870
871 if (empty($alt)) {
872 $alt = 'textfield';
873 }
874
875 if (!empty($maxlength)) {
876 $maxlength = ' maxlength="'.$maxlength.'" ';
877 }
878
ce432524 879 $htmlid = 'auto-tf'.sprintf('%04d', ++$idcounter);
d0d272e7 880 $output = '<span class="textfield '.$name."\">";
881 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="text" value="'.$value.'" size="'.$size.'" '.$maxlength.' alt="'.$alt.'" />';
c06c8492 882
d0d272e7 883 $output .= '</span>'."\n";
884
885 if (empty($return)) {
886 echo $output;
887 } else {
888 return $output;
889 }
890
891}
892
893
d48b00b4 894/**
895 * Implements a complete little popup form
896 *
89dcb99d 897 * @uses $CFG
898 * @param string $common The URL up to the point of the variable that changes
899 * @param array $options Alist of value-label pairs for the popup list
900 * @param string $formname Name must be unique on the page
901 * @param string $selected The option that is already selected
902 * @param string $nothing The label for the "no choice" option
903 * @param string $help The name of a help page if help is required
904 * @param string $helptext The name of the label for the help button
905 * @param boolean $return Indicates whether the function should return the text
906 * as a string or echo it directly to the page being rendered
772e78be 907 * @param string $targetwindow The name of the target page to open the linked page in.
89dcb99d 908 * @return string If $return is true then the entire form is returned as a string.
909 * @todo Finish documenting this function<br>
89dcb99d 910 */
911function popup_form($common, $options, $formname, $selected='', $nothing='choose', $help='', $helptext='', $return=false, $targetwindow='self') {
912
772e78be 913 global $CFG;
b0542a1e 914 static $go, $choose; /// Locally cached, in case there's lots on a page
87180677 915
6f9f3b69 916 if (empty($options)) {
917 return '';
918 }
0d0baabf 919
b0542a1e 920 if (!isset($go)) {
921 $go = get_string('go');
037dcbb6 922 }
923
b0ccd3fb 924 if ($nothing == 'choose') {
037dcbb6 925 if (!isset($choose)) {
926 $choose = get_string('choose');
927 }
928 $nothing = $choose.'...';
618b22c5 929 }
930
037dcbb6 931 $startoutput = '<form action="'.$CFG->wwwroot.'/course/jumpto.php"'.
932 ' method="get"'.
933 ' target="'.$CFG->framename.'"'.
934 ' name="'.$formname.'"'.
c4d951e1 935 ' class="popupform">';
037dcbb6 936
937 $output = '<select name="jump" onchange="'.$targetwindow.'.location=document.'.$formname.
16570a27 938 '.jump.options[document.'.$formname.'.jump.selectedIndex].value;">'."\n";
f9903ed0 939
b0ccd3fb 940 if ($nothing != '') {
dfec7b01 941 $output .= " <option value=\"javascript:void(0)\">$nothing</option>\n";
f9903ed0 942 }
943
72b4e283 944 $inoptgroup = false;
f9903ed0 945 foreach ($options as $value => $label) {
772e78be 946
2a003a90 947 if (substr($label,0,2) == '--') { /// we are starting a new optgroup
772e78be 948
2a003a90 949 /// Check to see if we already have a valid open optgroup
950 /// XHTML demands that there be at least 1 option within an optgroup
951 if ($inoptgroup and (count($optgr) > 1) ) {
952 $output .= implode('', $optgr);
72b4e283 953 $output .= ' </optgroup>';
72b4e283 954 }
2a003a90 955
956 unset($optgr);
957 $optgr = array();
958
959 $optgr[] = ' <optgroup label="'. substr($label,2) .'">'; // Plain labels
772e78be 960
2a003a90 961 $inoptgroup = true; /// everything following will be in an optgroup
3326450b 962 continue;
772e78be 963
d897cae4 964 } else {
fd78420b 965 if (!empty($CFG->usesid) && !isset($_COOKIE[session_name()]))
966 {
967 $url=sid_process_url( $common . $value );
968 } else
969 {
970 $url=$common . $value;
971 }
972 $optstr = ' <option value="' . $url . '"';
772e78be 973
d897cae4 974 if ($value == $selected) {
2a003a90 975 $optstr .= ' selected="selected"';
976 }
772e78be 977
2a003a90 978 if ($label) {
979 $optstr .= '>'. $label .'</option>' . "\n";
980 } else {
981 $optstr .= '>'. $value .'</option>' . "\n";
982 }
772e78be 983
2a003a90 984 if ($inoptgroup) {
985 $optgr[] = $optstr;
986 } else {
987 $output .= $optstr;
d897cae4 988 }
f9903ed0 989 }
772e78be 990
f9903ed0 991 }
2a003a90 992
993 /// catch the final group if not closed
994 if ($inoptgroup and count($optgr) > 1) {
995 $output .= implode('', $optgr);
72b4e283 996 $output .= ' </optgroup>';
997 }
2a003a90 998
b0ccd3fb 999 $output .= '</select>';
037dcbb6 1000 $output .= '<noscript id="noscript'.$formname.'" style="display: inline;">';
b0542a1e 1001 $output .= '<input type="submit" value="'.$go.'" /></noscript>';
037dcbb6 1002 $output .= '<script type="text/javascript">'.
1003 "\n<!--\n".
1004 'document.getElementById("noscript'.$formname.'").style.display = "none";'.
1005 "\n-->\n".'</script>';
b0ccd3fb 1006 $output .= '</form>' . "\n";
d897cae4 1007
1f2eec7b 1008 if ($help) {
1009 $button = helpbutton($help, $helptext, 'moodle', true, false, '', true);
1010 } else {
1011 $button = '';
1012 }
1013
d897cae4 1014 if ($return) {
1f2eec7b 1015 return $startoutput.$button.$output;
d897cae4 1016 } else {
1f2eec7b 1017 echo $startoutput.$button.$output;
d897cae4 1018 }
f9903ed0 1019}
1020
1021
d48b00b4 1022/**
1023 * Prints some red text
1024 *
1025 * @param string $error The text to be displayed in red
1026 */
f9903ed0 1027function formerr($error) {
d48b00b4 1028
f9903ed0 1029 if (!empty($error)) {
b0ccd3fb 1030 echo '<font color="#ff0000">'. $error .'</font>';
f9903ed0 1031 }
1032}
1033
d48b00b4 1034/**
1035 * Validates an email to make sure it makes sense.
1036 *
1037 * @param string $address The email address to validate.
1038 * @return boolean
1039 */
89dcb99d 1040function validate_email($address) {
d48b00b4 1041
f9903ed0 1042 return (ereg('^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.
1043 '@'.
1044 '[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.
1045 '[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$',
1046 $address));
1047}
1048
690f358b 1049/**
1050 * Extracts file argument either from file parameter or PATH_INFO
1051 *
1052 * @param string $scriptname name of the calling script
1053 * @return string file path (only safe characters)
1054 */
1055function get_file_argument($scriptname) {
1056 global $_SERVER;
1057
1058 $relativepath = FALSE;
1059
1060 // first try normal parameter (compatible method == no relative links!)
1061 $relativepath = optional_param('file', FALSE, PARAM_PATH);
48283ff6 1062 if ($relativepath === '/testslasharguments') {
1063 echo 'test -1: Incorrect use - try "file.php/testslasharguments" instead'; //indicate fopen/fread works for health center
1064 die;
1065 }
690f358b 1066
1067 // then try extract file from PATH_INFO (slasharguments method)
1068 if (!$relativepath and !empty($_SERVER['PATH_INFO'])) {
1069 $path_info = $_SERVER['PATH_INFO'];
1070 // check that PATH_INFO works == must not contain the script name
1071 if (!strpos($path_info, $scriptname)) {
1072 $relativepath = clean_param(rawurldecode($path_info), PARAM_PATH);
48283ff6 1073 if ($relativepath === '/testslasharguments') {
1074 echo 'test 1: Slasharguments test passed.'; //indicate ok for health center
690f358b 1075 die;
1076 }
1077 }
1078 }
1079
1080 // now if both fail try the old way
1081 // (for compatibility with misconfigured or older buggy php implementations)
1082 if (!$relativepath) {
1083 $arr = explode($scriptname, me());
1084 if (!empty($arr[1])) {
1085 $path_info = strip_querystring($arr[1]);
1086 $relativepath = clean_param(rawurldecode($path_info), PARAM_PATH);
48283ff6 1087 if ($relativepath === '/testslasharguments') {
1088 echo 'test 2:Slasharguments test passed (compatibility hack).'; //indicate ok for health center
690f358b 1089 die;
1090 }
1091 }
1092 }
1093
1094 return $relativepath;
1095}
1096
d48b00b4 1097/**
1098 * Check for bad characters ?
1099 *
1100 * @param string $string ?
89dcb99d 1101 * @param int $allowdots ?
1102 * @todo Finish documenting this function - more detail needed in description as well as details on arguments
d48b00b4 1103 */
80035a89 1104function detect_munged_arguments($string, $allowdots=1) {
1105 if (substr_count($string, '..') > $allowdots) { // Sometimes we allow dots in references
6c8e8b5e 1106 return true;
1107 }
393c9b4f 1108 if (ereg('[\|\`]', $string)) { // check for other bad characters
6c8e8b5e 1109 return true;
1110 }
f038d9a3 1111 if (empty($string) or $string == '/') {
1112 return true;
1113 }
1114
6c8e8b5e 1115 return false;
1116}
1117
d48b00b4 1118/**
1119 * Searches the current environment variables for some slash arguments
1120 *
1121 * @param string $file ?
1122 * @todo Finish documenting this function
1123 */
b0ccd3fb 1124function get_slash_arguments($file='file.php') {
f9903ed0 1125
eaa50dbc 1126 if (!$string = me()) {
f9903ed0 1127 return false;
1128 }
eaa50dbc 1129
6ed3da1d 1130 $pathinfo = explode($file, $string);
ab9f24ad 1131
bcdfe14e 1132 if (!empty($pathinfo[1])) {
9b74055f 1133 return addslashes($pathinfo[1]);
6ed3da1d 1134 } else {
1135 return false;
1136 }
1137}
1138
d48b00b4 1139/**
1140 * Extracts arguments from "/foo/bar/something"
1141 * eg http://mysite.com/script.php/foo/bar/something
1142 *
89dcb99d 1143 * @param string $string ?
1144 * @param int $i ?
1145 * @return array|string
d48b00b4 1146 * @todo Finish documenting this function
1147 */
6ed3da1d 1148function parse_slash_arguments($string, $i=0) {
f9903ed0 1149
6c8e8b5e 1150 if (detect_munged_arguments($string)) {
780db230 1151 return false;
1152 }
b0ccd3fb 1153 $args = explode('/', $string);
f9903ed0 1154
1155 if ($i) { // return just the required argument
1156 return $args[$i];
1157
1158 } else { // return the whole array
1159 array_shift($args); // get rid of the empty first one
1160 return $args;
1161 }
1162}
1163
d48b00b4 1164/**
89dcb99d 1165 * Just returns an array of text formats suitable for a popup menu
d48b00b4 1166 *
89dcb99d 1167 * @uses FORMAT_MOODLE
1168 * @uses FORMAT_HTML
1169 * @uses FORMAT_PLAIN
89dcb99d 1170 * @uses FORMAT_MARKDOWN
1171 * @return array
d48b00b4 1172 */
0095d5cd 1173function format_text_menu() {
d48b00b4 1174
b0ccd3fb 1175 return array (FORMAT_MOODLE => get_string('formattext'),
1176 FORMAT_HTML => get_string('formathtml'),
1177 FORMAT_PLAIN => get_string('formatplain'),
b0ccd3fb 1178 FORMAT_MARKDOWN => get_string('formatmarkdown'));
0095d5cd 1179}
1180
d48b00b4 1181/**
1182 * Given text in a variety of format codings, this function returns
772e78be 1183 * the text as safe HTML.
d48b00b4 1184 *
1185 * @uses $CFG
89dcb99d 1186 * @uses FORMAT_MOODLE
1187 * @uses FORMAT_HTML
1188 * @uses FORMAT_PLAIN
1189 * @uses FORMAT_WIKI
1190 * @uses FORMAT_MARKDOWN
1191 * @param string $text The text to be formatted. This is raw text originally from user input.
772e78be 1192 * @param int $format Identifier of the text format to be used
89dcb99d 1193 * (FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN)
1194 * @param array $options ?
1195 * @param int $courseid ?
1196 * @return string
d48b00b4 1197 * @todo Finish documenting this function
1198 */
c4ae4fa1 1199function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL ) {
0095d5cd 1200
ab9f24ad 1201 global $CFG, $course;
c4ae4fa1 1202
e7a47153 1203 if (!isset($options->noclean)) {
1204 $options->noclean=false;
1205 }
1206 if (!isset($options->smiley)) {
1207 $options->smiley=true;
1208 }
1209 if (!isset($options->filter)) {
1210 $options->filter=true;
1211 }
1212 if (!isset($options->para)) {
1213 $options->para=true;
1214 }
1215 if (!isset($options->newlines)) {
1216 $options->newlines=true;
f0aa2fed 1217 }
1218
c4ae4fa1 1219 if (empty($courseid)) {
8eaa4c61 1220 if (!empty($course->id)) { // An ugly hack for better compatibility
c4ae4fa1 1221 $courseid = $course->id;
1222 }
1223 }
a751a4e5 1224
e7a47153 1225 if (!empty($CFG->cachetext)) {
1226 $time = time() - $CFG->cachetext;
1227 $md5key = md5($text.'-'.$courseid.$options->noclean.$options->smiley.$options->filter.$options->para.$options->newlines);
a9743837 1228 if ($oldcacheitem = get_record_sql('SELECT * FROM '.$CFG->prefix.'cache_text WHERE md5key = \''.$md5key.'\'', true)) {
1229 if ($oldcacheitem->timemodified >= $time) {
1230 return $oldcacheitem->formattedtext;
1231 }
e7a47153 1232 }
1233 }
1234
8eaa4c61 1235 $CFG->currenttextiscacheable = true; // Default status - can be changed by any filter
c06c8492 1236
0095d5cd 1237 switch ($format) {
73f8658c 1238 case FORMAT_HTML:
e7a47153 1239 if (!empty($options->smiley)) {
1240 replace_smilies($text);
1241 }
1242 if (empty($options->noclean)) {
9d40806d 1243 $text = clean_text($text, $format);
1244 }
e7a47153 1245 if (!empty($options->filter)) {
1246 $text = filter_text($text, $courseid);
1247 }
73f8658c 1248 break;
1249
6901fa79 1250 case FORMAT_PLAIN:
c06c8492 1251 $text = s($text);
ab892a4f 1252 $text = rebuildnolinktag($text);
b0ccd3fb 1253 $text = str_replace(' ', '&nbsp; ', $text);
6901fa79 1254 $text = nl2br($text);
6901fa79 1255 break;
1256
d342c763 1257 case FORMAT_WIKI:
6a6495ff 1258 // this format is deprecated
572fe9ab 1259 $text = '<p>NOTICE: Wiki-like formatting has been removed from Moodle. You should not be seeing
1260 this message as all texts should have been converted to Markdown format instead.
ce50cc70 1261 Please post a bug report to http://moodle.org/bugs with information about where you
e7a47153 1262 saw this message.</p>'.s($text);
d342c763 1263 break;
1264
e7cdcd18 1265 case FORMAT_MARKDOWN:
1266 $text = markdown_to_html($text);
e7a47153 1267 if (!empty($options->smiley)) {
1268 replace_smilies($text);
1269 }
1270 if (empty($options->noclean)) {
9d40806d 1271 $text = clean_text($text, $format);
1272 }
c06c8492 1273
e7a47153 1274 if (!empty($options->filter)) {
1275 $text = filter_text($text, $courseid);
1276 }
e7cdcd18 1277 break;
1278
73f8658c 1279 default: // FORMAT_MOODLE or anything else
b7a3d3b2 1280 $text = text_to_html($text, $options->smiley, $options->para, $options->newlines);
e7a47153 1281 if (empty($options->noclean)) {
9d40806d 1282 $text = clean_text($text, $format);
1283 }
c06c8492 1284
e7a47153 1285 if (!empty($options->filter)) {
1286 $text = filter_text($text, $courseid);
1287 }
0095d5cd 1288 break;
0095d5cd 1289 }
f0aa2fed 1290
8eaa4c61 1291 if (!empty($CFG->cachetext) and $CFG->currenttextiscacheable) {
a9743837 1292 $newcacheitem->md5key = $md5key;
1293 $newcacheitem->formattedtext = addslashes($text);
1294 $newcacheitem->timemodified = time();
1295 if ($oldcacheitem) { // See bug 4677 for discussion
1296 $newcacheitem->id = $oldcacheitem->id;
1297 @update_record('cache_text', $newcacheitem); // Update existing record in the cache table
1298 // It's unlikely that the cron cache cleaner could have
1299 // deleted this entry in the meantime, as it allows
1300 // some extra time to cover these cases.
1301 } else {
1302 @insert_record('cache_text', $newcacheitem); // Insert a new record in the cache table
1303 // Again, it's possible that another user has caused this
1304 // record to be created already in the time that it took
1305 // to traverse this function. That's OK too, as the
1306 // call above handles duplicate entries, and eventually
1307 // the cron cleaner will delete them.
1308 }
f0aa2fed 1309 }
1310
1311 return $text;
0095d5cd 1312}
1313
4a28b5ca 1314/** Converts the text format from the value to the 'internal'
1315 * name or vice versa. $key can either be the value or the name
1316 * and you get the other back.
c06c8492 1317 *
4a28b5ca 1318 * @param mixed int 0-4 or string one of 'moodle','html','plain','markdown'
1319 * @return mixed as above but the other way around!
1320 */
1321function text_format_name( $key ) {
1322 $lookup = array();
1323 $lookup[FORMAT_MOODLE] = 'moodle';
1324 $lookup[FORMAT_HTML] = 'html';
1325 $lookup[FORMAT_PLAIN] = 'plain';
1326 $lookup[FORMAT_MARKDOWN] = 'markdown';
1327 $value = "error";
1328 if (!is_numeric($key)) {
1329 $key = strtolower( $key );
1330 $value = array_search( $key, $lookup );
1331 }
1332 else {
1333 if (isset( $lookup[$key] )) {
1334 $value = $lookup[ $key ];
1335 }
1336 }
1337 return $value;
1338}
1339
7b2c5e72 1340/** Given a simple string, this function returns the string
1341 * processed by enabled filters if $CFG->filterall is enabled
1342 *
3e6691ee 1343 * @param string $string The string to be filtered.
1344 * @param boolean $striplinks To strip any link in the result text.
1345 * @param int $courseid Current course as filters can, potentially, use it
7b2c5e72 1346 * @return string
1347 */
3e6691ee 1348function format_string ($string, $striplinks = false, $courseid=NULL ) {
7b2c5e72 1349
1350 global $CFG, $course;
1351
2a3affe9 1352 //We'll use a in-memory cache here to speed up repeated strings
1353 static $strcache;
1354
1355 //Calculate md5
1c58f440 1356 $md5 = md5($string.'<+>'.$striplinks);
2a3affe9 1357
1358 //Fetch from cache if possible
1359 if(isset($strcache[$md5])) {
1360 return $strcache[$md5];
1361 }
1362
7b2c5e72 1363 if (empty($courseid)) {
1364 if (!empty($course->id)) { // An ugly hack for better compatibility
1365 $courseid = $course->id; // (copied from format_text)
1366 }
1367 }
1368
45daee10 1369 if (!empty($CFG->filterall)) {
7b2c5e72 1370 $string = filter_text($string, $courseid);
1371 }
1372
3e6691ee 1373 if ($striplinks) { //strip links in string
1374 $string = preg_replace('/(<a[^>]+?>)(.+?)(<\/a>)/is','$2',$string);
1375 }
1376
2a3affe9 1377 //Store to cache
1378 $strcache[$md5] = $string;
1379
7b2c5e72 1380 return $string;
1381}
1382
d48b00b4 1383/**
1384 * Given text in a variety of format codings, this function returns
1385 * the text as plain text suitable for plain email.
d48b00b4 1386 *
89dcb99d 1387 * @uses FORMAT_MOODLE
1388 * @uses FORMAT_HTML
1389 * @uses FORMAT_PLAIN
1390 * @uses FORMAT_WIKI
1391 * @uses FORMAT_MARKDOWN
1392 * @param string $text The text to be formatted. This is raw text originally from user input.
772e78be 1393 * @param int $format Identifier of the text format to be used
89dcb99d 1394 * (FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN)
1395 * @return string
d48b00b4 1396 */
d342c763 1397function format_text_email($text, $format) {
d342c763 1398
1399 switch ($format) {
1400
1401 case FORMAT_PLAIN:
1402 return $text;
1403 break;
1404
1405 case FORMAT_WIKI:
1406 $text = wiki_to_html($text);
5b472756 1407 /// This expression turns links into something nice in a text format. (Russell Jungwirth)
1408 /// From: http://php.net/manual/en/function.eregi-replace.php and simplified
76add072 1409 $text = eregi_replace('(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)','\\3 [ \\2 ]', $text);
7c55a29b 1410 return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
d342c763 1411 break;
1412
6ff45b59 1413 case FORMAT_HTML:
1414 return html_to_text($text);
1415 break;
1416
e7cdcd18 1417 case FORMAT_MOODLE:
1418 case FORMAT_MARKDOWN:
67ccec43 1419 default:
76add072 1420 $text = eregi_replace('(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)','\\3 [ \\2 ]', $text);
7c55a29b 1421 return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
d342c763 1422 break;
1423 }
1424}
0095d5cd 1425
d48b00b4 1426/**
1427 * Given some text in HTML format, this function will pass it
1428 * through any filters that have been defined in $CFG->textfilterx
1429 * The variable defines a filepath to a file containing the
1430 * filter function. The file must contain a variable called
1431 * $textfilter_function which contains the name of the function
1432 * with $courseid and $text parameters
1433 *
89dcb99d 1434 * @param string $text The text to be passed through format filters
1435 * @param int $courseid ?
d48b00b4 1436 * @return string
1437 * @todo Finish documenting this function
1438 */
c4ae4fa1 1439function filter_text($text, $courseid=NULL) {
e67b9e31 1440
c4ae4fa1 1441 global $CFG;
e67b9e31 1442
01af49bb 1443 require_once($CFG->libdir.'/filterlib.php');
d523d2ea 1444 if (!empty($CFG->textfilters)) {
1445 $textfilters = explode(',', $CFG->textfilters);
1446 foreach ($textfilters as $textfilter) {
b0ccd3fb 1447 if (is_readable($CFG->dirroot .'/'. $textfilter .'/filter.php')) {
1448 include_once($CFG->dirroot .'/'. $textfilter .'/filter.php');
df1c4611 1449 $functionname = basename($textfilter).'_filter';
1450 if (function_exists($functionname)) {
1451 $text = $functionname($courseid, $text);
1452 }
d523d2ea 1453 }
e67b9e31 1454 }
1455 }
d523d2ea 1456
c7444a36 1457 /// <nolink> tags removed for XHTML compatibility
1458 $text = str_replace('<nolink>', '', $text);
1459 $text = str_replace('</nolink>', '', $text);
1460
e67b9e31 1461 return $text;
1462}
1463
d48b00b4 1464/**
1465 * Given raw text (eg typed in by a user), this function cleans it up
1466 * and removes any nasty tags that could mess up Moodle pages.
1467 *
89dcb99d 1468 * @uses FORMAT_MOODLE
1469 * @uses FORMAT_PLAIN
1470 * @uses ALLOWED_TAGS
1471 * @param string $text The text to be cleaned
772e78be 1472 * @param int $format Identifier of the text format to be used
89dcb99d 1473 * (FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN)
1474 * @return string The cleaned up text
d48b00b4 1475 */
3da47524 1476function clean_text($text, $format=FORMAT_MOODLE) {
b7a3cf49 1477
fc120758 1478 global $ALLOWED_TAGS;
3fe3851d 1479
ab9f24ad 1480 switch ($format) {
e7cdcd18 1481 case FORMAT_PLAIN:
1482 return $text;
1483
1484 default:
1485
29939bea 1486 /// Fix non standard entity notations
1487 $text = preg_replace('/(&#[0-9]+)(;?)/', "\\1;", $text);
1488 $text = preg_replace('/(&#x[0-9a-fA-F]+)(;?)/', "\\1;", $text);
1489
09cbeb40 1490 /// Remove tags that are not allowed
3fe3851d 1491 $text = strip_tags($text, $ALLOWED_TAGS);
e7cdcd18 1492
7789ffbf 1493 /// Clean up embedded scripts and , using kses
1494 $text = cleanAttributes($text);
1495
5b472756 1496 /// Remove script events
ab9f24ad 1497 $text = eregi_replace("([^a-z])language([[:space:]]*)=", "\\1Xlanguage=", $text);
1498 $text = eregi_replace("([^a-z])on([a-z]+)([[:space:]]*)=", "\\1Xon\\2=", $text);
6901fa79 1499
6901fa79 1500 return $text;
0095d5cd 1501 }
b7a3cf49 1502}
f9903ed0 1503
d48b00b4 1504/**
89dcb99d 1505 * This function takes a string and examines it for HTML tags.
d48b00b4 1506 * If tags are detected it passes the string to a helper function {@link cleanAttributes2()}
1507 * which checks for attributes and filters them for malicious content
1508 * 17/08/2004 :: Eamon DOT Costello AT dcu DOT ie
1509 *
1510 * @param string $str The string to be examined for html tags
1511 * @return string
1512 */
3bd7ffec 1513function cleanAttributes($str){
4e8f2e6b 1514 $result = preg_replace_callback(
1515 '%(<[^>]*(>|$)|>)%m', #search for html tags
1516 "cleanAttributes2",
3bd7ffec 1517 $str
67ccec43 1518 );
3bd7ffec 1519 return $result;
67ccec43 1520}
1521
d48b00b4 1522/**
1523 * This function takes a string with an html tag and strips out any unallowed
1524 * protocols e.g. javascript:
1525 * It calls ancillary functions in kses which are prefixed by kses
1526* 17/08/2004 :: Eamon DOT Costello AT dcu DOT ie
1527 *
4e8f2e6b 1528 * @param array $htmlArray An array from {@link cleanAttributes()}, containing in its 1st
1529 * element the html to be cleared
d48b00b4 1530 * @return string
1531 */
4e8f2e6b 1532function cleanAttributes2($htmlArray){
3bd7ffec 1533
037dcbb6 1534 global $CFG, $ALLOWED_PROTOCOLS;
b0ccd3fb 1535 require_once($CFG->libdir .'/kses.php');
3bd7ffec 1536
4e8f2e6b 1537 $htmlTag = $htmlArray[1];
037dcbb6 1538 if (substr($htmlTag, 0, 1) != '<') {
3bd7ffec 1539 return '&gt;'; //a single character ">" detected
1540 }
037dcbb6 1541 if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $htmlTag, $matches)) {
67ccec43 1542 return ''; // It's seriously malformed
1543 }
3bd7ffec 1544 $slash = trim($matches[1]); //trailing xhtml slash
67ccec43 1545 $elem = $matches[2]; //the element name
3bd7ffec 1546 $attrlist = $matches[3]; // the list of attributes as a string
1547
037dcbb6 1548 $attrArray = kses_hair($attrlist, $ALLOWED_PROTOCOLS);
3bd7ffec 1549
67ccec43 1550 $attStr = '';
037dcbb6 1551 foreach ($attrArray as $arreach) {
29939bea 1552 $arreach['name'] = strtolower($arreach['name']);
1553 if ($arreach['name'] == 'style') {
1554 $value = $arreach['value'];
1555 while (true) {
1556 $prevvalue = $value;
1557 $value = kses_no_null($value);
1558 $value = preg_replace("/\/\*.*\*\//Us", '', $value);
1559 $value = kses_decode_entities($value);
1560 $value = preg_replace('/(&#[0-9]+)(;?)/', "\\1;", $value);
1561 $value = preg_replace('/(&#x[0-9a-fA-F]+)(;?)/', "\\1;", $value);
1562 if ($value === $prevvalue) {
1563 $arreach['value'] = $value;
1564 break;
1565 }
1566 }
1567 $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']);
1568 $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']);
1569 }
1570 $attStr .= ' '.$arreach['name'].'="'.$arreach['value'].'" ';
3bd7ffec 1571 }
713126cd 1572
1573 // Remove last space from attribute list
1574 $attStr = rtrim($attStr);
1575
3bd7ffec 1576 $xhtml_slash = '';
037dcbb6 1577 if (preg_match('%/\s*$%', $attrlist)) {
67ccec43 1578 $xhtml_slash = ' /';
3bd7ffec 1579 }
b0ccd3fb 1580 return '<'. $slash . $elem . $attStr . $xhtml_slash .'>';
3bd7ffec 1581}
1582
d48b00b4 1583/**
1584 * Replaces all known smileys in the text with image equivalents
1585 *
1586 * @uses $CFG
1587 * @param string $text Passed by reference. The string to search for smily strings.
1588 * @return string
1589 */
5f350e8f 1590function replace_smilies(&$text) {
772e78be 1591///
2ea9027b 1592 global $CFG;
c1d57101 1593
5b472756 1594/// this builds the mapping array only once
617778f2 1595 static $runonce = false;
69081931 1596 static $e = array();
1597 static $img = array();
617778f2 1598 static $emoticons = array(
fbfc2675 1599 ':-)' => 'smiley',
1600 ':)' => 'smiley',
1601 ':-D' => 'biggrin',
1602 ';-)' => 'wink',
1603 ':-/' => 'mixed',
1604 'V-.' => 'thoughtful',
1605 ':-P' => 'tongueout',
1606 'B-)' => 'cool',
1607 '^-)' => 'approve',
1608 '8-)' => 'wideeyes',
1609 ':o)' => 'clown',
1610 ':-(' => 'sad',
1611 ':(' => 'sad',
1612 '8-.' => 'shy',
1613 ':-I' => 'blush',
1614 ':-X' => 'kiss',
1615 '8-o' => 'surprise',
1616 'P-|' => 'blackeye',
1617 '8-[' => 'angry',
1618 'xx-P' => 'dead',
1619 '|-.' => 'sleepy',
1620 '}-]' => 'evil',
2ea9027b 1621 );
1622
fbfc2675 1623 if ($runonce == false) { /// After the first time this is not run again
617778f2 1624 foreach ($emoticons as $emoticon => $image){
fbfc2675 1625 $alttext = get_string($image, 'pix');
1626
69081931 1627 $e[] = $emoticon;
d48b00b4 1628 $img[] = '<img alt="'. $alttext .'" width="15" height="15" src="'. $CFG->pixpath .'/s/'. $image .'.gif" />';
617778f2 1629 }
1630 $runonce = true;
c0f728ba 1631 }
b7a3cf49 1632
8dcd43f3 1633 // Exclude from transformations all the code inside <script> tags
1634 // Needed to solve Bug 1185. Thanks to jouse 2001 detecting it. :-)
1635 // Based on code from glossary fiter by Williams Castillo.
1636 // - Eloy
1637
1638 // Detect all the <script> zones to take out
1639 $excludes = array();
1640 preg_match_all('/<script language(.+?)<\/script>/is',$text,$list_of_excludes);
1641
1642 // Take out all the <script> zones from text
1643 foreach (array_unique($list_of_excludes[0]) as $key=>$value) {
1644 $excludes['<+'.$key.'+>'] = $value;
1645 }
1646 if ($excludes) {
1647 $text = str_replace($excludes,array_keys($excludes),$text);
1648 }
1649
fbfc2675 1650/// this is the meat of the code - this is run every time
5f350e8f 1651 $text = str_replace($e, $img, $text);
8dcd43f3 1652
1653 // Recover all the <script> zones to text
1654 if ($excludes) {
1655 $text = str_replace(array_keys($excludes),$excludes,$text);
1656 }
1a072208 1657}
0095d5cd 1658
89dcb99d 1659/**
1660 * Given plain text, makes it into HTML as nicely as possible.
1661 * May contain HTML tags already
1662 *
1663 * @uses $CFG
1664 * @param string $text The string to convert.
1665 * @param boolean $smiley Convert any smiley characters to smiley images?
1666 * @param boolean $para If true then the returned string will be wrapped in paragraph tags
1667 * @param boolean $newlines If true then lines newline breaks will be converted to HTML newline breaks.
1668 * @return string
1669 */
1670
b7a3d3b2 1671function text_to_html($text, $smiley=true, $para=true, $newlines=true) {
772e78be 1672///
f9903ed0 1673
27326a3e 1674 global $CFG;
1675
c1d57101 1676/// Remove any whitespace that may be between HTML tags
7b3be1b1 1677 $text = eregi_replace(">([[:space:]]+)<", "><", $text);
1678
c1d57101 1679/// Remove any returns that precede or follow HTML tags
0eae8049 1680 $text = eregi_replace("([\n\r])<", " <", $text);
1681 $text = eregi_replace(">([\n\r])", "> ", $text);
7b3be1b1 1682
5f350e8f 1683 convert_urls_into_links($text);
f9903ed0 1684
c1d57101 1685/// Make returns into HTML newlines.
b7a3d3b2 1686 if ($newlines) {
1687 $text = nl2br($text);
1688 }
f9903ed0 1689
c1d57101 1690/// Turn smileys into images.
d69cb7f4 1691 if ($smiley) {
5f350e8f 1692 replace_smilies($text);
d69cb7f4 1693 }
f9903ed0 1694
c1d57101 1695/// Wrap the whole thing in a paragraph tag if required
909f539d 1696 if ($para) {
b0ccd3fb 1697 return '<p>'.$text.'</p>';
909f539d 1698 } else {
1699 return $text;
1700 }
f9903ed0 1701}
1702
d48b00b4 1703/**
1704 * Given Markdown formatted text, make it into XHTML using external function
1705 *
89dcb99d 1706 * @uses $CFG
1707 * @param string $text The markdown formatted text to be converted.
1708 * @return string Converted text
d48b00b4 1709 */
e7cdcd18 1710function markdown_to_html($text) {
e7cdcd18 1711 global $CFG;
1712
b0ccd3fb 1713 require_once($CFG->libdir .'/markdown.php');
e7cdcd18 1714
1715 return Markdown($text);
1716}
1717
d48b00b4 1718/**
89dcb99d 1719 * Given HTML text, make it into plain text using external function
d48b00b4 1720 *
1721 * @uses $CFG
1722 * @param string $html The text to be converted.
1723 * @return string
1724 */
6ff45b59 1725function html_to_text($html) {
89dcb99d 1726
428aaa29 1727 global $CFG;
6ff45b59 1728
b0ccd3fb 1729 require_once($CFG->libdir .'/html2text.php');
6ff45b59 1730
1731 return html2text($html);
1732}
1733
d48b00b4 1734/**
1735 * Given some text this function converts any URLs it finds into HTML links
1736 *
1737 * @param string $text Passed in by reference. The string to be searched for urls.
1738 */
5f350e8f 1739function convert_urls_into_links(&$text) {
5f350e8f 1740/// Make lone URLs into links. eg http://moodle.com/
3405b212 1741 $text = eregi_replace("([[:space:]]|^|\(|\[)([[:alnum:]]+)://([^[:space:]]*)([[:alnum:]#?/&=])",
bc01a2b8 1742 "\\1<a href=\"\\2://\\3\\4\" target=\"_blank\">\\2://\\3\\4</a>", $text);
5f350e8f 1743
1744/// eg www.moodle.com
ab9f24ad 1745 $text = eregi_replace("([[:space:]]|^|\(|\[)www\.([^[:space:]]*)([[:alnum:]#?/&=])",
bc01a2b8 1746 "\\1<a href=\"http://www.\\2\\3\" target=\"_blank\">www.\\2\\3</a>", $text);
5f350e8f 1747}
1748
d48b00b4 1749/**
1750 * This function will highlight search words in a given string
1751 * It cares about HTML and will not ruin links. It's best to use
1752 * this function after performing any conversions to HTML.
1753 * Function found here: http://forums.devshed.com/t67822/scdaa2d1c3d4bacb4671d075ad41f0854.html
1754 *
89dcb99d 1755 * @param string $needle The string to search for
1756 * @param string $haystack The string to search for $needle in
1757 * @param int $case ?
1758 * @return string
d48b00b4 1759 * @todo Finish documenting this function
1760 */
ab9f24ad 1761function highlight($needle, $haystack, $case=0,
b0ccd3fb 1762 $left_string='<span class="highlight">', $right_string='</span>') {
69d51d3a 1763 if (empty($needle)) {
1764 return $haystack;
1765 }
1766
5eecb8cb 1767 //$list_of_words = eregi_replace("[^-a-zA-Z0-9&.']", " ", $needle); // bug 3101
1768 $list_of_words = $needle;
b0ccd3fb 1769 $list_array = explode(' ', $list_of_words);
88438a58 1770 for ($i=0; $i<sizeof($list_array); $i++) {
1771 if (strlen($list_array[$i]) == 1) {
b0ccd3fb 1772 $list_array[$i] = '';
88438a58 1773 }
1774 }
b0ccd3fb 1775 $list_of_words = implode(' ', $list_array);
88438a58 1776 $list_of_words_cp = $list_of_words;
1777 $final = array();
1778 preg_match_all('/<(.+?)>/is',$haystack,$list_of_words);
1779
1780 foreach (array_unique($list_of_words[0]) as $key=>$value) {
1781 $final['<|'.$key.'|>'] = $value;
1782 }
1783
1784 $haystack = str_replace($final,array_keys($final),$haystack);
b0ccd3fb 1785 $list_of_words_cp = eregi_replace(' +', '|', $list_of_words_cp);
88438a58 1786
b0ccd3fb 1787 if ($list_of_words_cp{0}=='|') {
1788 $list_of_words_cp{0} = '';
88438a58 1789 }
b0ccd3fb 1790 if ($list_of_words_cp{strlen($list_of_words_cp)-1}=='|') {
1791 $list_of_words_cp{strlen($list_of_words_cp)-1}='';
88438a58 1792 }
88438a58 1793
9ccdcd97 1794 $list_of_words_cp = trim($list_of_words_cp);
1795
1796 if ($list_of_words_cp) {
1797
1798 $list_of_words_cp = "(". $list_of_words_cp .")";
1799
1800 if (!$case){
1801 $haystack = eregi_replace("$list_of_words_cp", "$left_string"."\\1"."$right_string", $haystack);
1802 } else {
1803 $haystack = ereg_replace("$list_of_words_cp", "$left_string"."\\1"."$right_string", $haystack);
1804 }
88438a58 1805 }
1806 $haystack = str_replace(array_keys($final),$final,$haystack);
1807
f60e7cfe 1808 return $haystack;
88438a58 1809}
1810
d48b00b4 1811/**
1812 * This function will highlight instances of $needle in $haystack
1813 * It's faster that the above function and doesn't care about
1814 * HTML or anything.
1815 *
1816 * @param string $needle The string to search for
1817 * @param string $haystack The string to search for $needle in
1818 * @return string
1819 */
88438a58 1820function highlightfast($needle, $haystack) {
5af78ed2 1821
1822 $parts = explode(strtolower($needle), strtolower($haystack));
1823
1824 $pos = 0;
1825
1826 foreach ($parts as $key => $part) {
1827 $parts[$key] = substr($haystack, $pos, strlen($part));
1828 $pos += strlen($part);
1829
b0ccd3fb 1830 $parts[$key] .= '<span class="highlight">'.substr($haystack, $pos, strlen($needle)).'</span>';
5af78ed2 1831 $pos += strlen($needle);
ab9f24ad 1832 }
5af78ed2 1833
1834 return (join('', $parts));
1835}
1836
f9903ed0 1837
9fa49e22 1838/// STANDARD WEB PAGE PARTS ///////////////////////////////////////////////////
1839
d48b00b4 1840/**
1841 * Print a standard header
1842 *
89dcb99d 1843 * @uses $USER
1844 * @uses $CFG
89dcb99d 1845 * @uses $SESSION
1846 * @param string $title Appears at the top of the window
1847 * @param string $heading Appears at the top of the page
1848 * @param string $navigation Premade navigation string (for use as breadcrumbs links)
1849 * @param string $focus Indicates form element to get cursor focus on load eg inputform.password
1850 * @param string $meta Meta tags to be added to the header
1851 * @param boolean $cache Should this page be cacheable?
1852 * @param string $button HTML code for a button (usually for module editing)
1853 * @param string $menu HTML code for a popup menu
1854 * @param boolean $usexml use XML for this page
1855 * @param string $bodytags This text will be included verbatim in the <body> tag (useful for onload() etc)
d48b00b4 1856 */
b0ccd3fb 1857function print_header ($title='', $heading='', $navigation='', $focus='', $meta='',
1858 $cache=true, $button='&nbsp;', $menu='', $usexml=false, $bodytags='') {
63f3cbbd 1859
f78b1dad 1860 global $USER, $CFG, $THEME, $SESSION, $ME, $SITE, $HTTPSPAGEREQUIRED;
c06c8492 1861
32613b50 1862/// This makes sure that the header is never repeated twice on a page
1863 static $headerprinted = false;
1864
1865 if ($headerprinted) {
e575c059 1866 if ($CFG->debug > 7) {
1867 notify('print_header() was called more than once - this should not happen. Please check the code for this page closely, a common culprit is a call to error() after print_header().');
1868 }
32613b50 1869 return;
1870 } else {
1871 $headerprinted = true;
1872 }
1873
e89fb61e 1874/// This is an ugly hack to be replaced later by a proper global $COURSE
1875 global $course;
b3153e4b 1876 if (!empty($course->lang)) {
1877 $CFG->courselang = $course->lang;
1878 }
32e2b302 1879 if (!empty($course->theme)) {
1880 if (!empty($CFG->allowcoursethemes)) {
1881 $CFG->coursetheme = $course->theme;
1882 theme_setup();
1883 }
1884 }
b3153e4b 1885
f78b1dad 1886/// We have to change some URLs in styles if we are in a $HTTPSPAGEREQUIRED page
1887 if (!empty($HTTPSPAGEREQUIRED)) {
1888 $CFG->themewww = str_replace('http', 'https', $CFG->themewww);
1889 $CFG->pixpath = str_replace('http', 'https', $CFG->pixpath);
1890 $CFG->modpixpath = str_replace('http', 'https', $CFG->modpixpath);
1891 foreach ($CFG->stylesheets as $key => $stylesheet) {
1892 $CFG->stylesheets[$key] = str_replace('http', 'https', $stylesheet);
1893 }
1894 }
0d741155 1895
c3f55692 1896/// Add the required stylesheets
d74d4f20 1897 $stylesheetshtml = '';
1898 foreach ($CFG->stylesheets as $stylesheet) {
1899 $stylesheetshtml .= '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'" />'."\n";
c3f55692 1900 }
d74d4f20 1901 $meta = $stylesheetshtml.$meta;
e89fb61e 1902
9fa49e22 1903
b0ccd3fb 1904 if ($navigation == 'home') {
9fa49e22 1905 $home = true;
b0ccd3fb 1906 $navigation = '';
9d378732 1907 } else {
1908 $home = false;
9fa49e22 1909 }
1910
0d741155 1911/// This is another ugly hack to make navigation elements available to print_footer later
1912 $THEME->title = $title;
1913 $THEME->heading = $heading;
1914 $THEME->navigation = $navigation;
1915 $THEME->button = $button;
1916 $THEME->menu = $menu;
2507b2f5 1917 $navmenulist = isset($THEME->navmenulist) ? $THEME->navmenulist : '';
0d741155 1918
b0ccd3fb 1919 if ($button == '') {
1920 $button = '&nbsp;';
9fa49e22 1921 }
1922
1923 if (!$menu and $navigation) {
8a33e371 1924 if (empty($CFG->loginhttps)) {
1925 $wwwroot = $CFG->wwwroot;
1926 } else {
1927 $wwwroot = str_replace('http','https',$CFG->wwwroot);
1928 }
0e18f827 1929 if (isset($course->id)) {
009f39be 1930 $menu = user_login_string($course);
9fa49e22 1931 } else {
c44d5d42 1932 $menu = user_login_string($SITE);
9fa49e22 1933 }
1934 }
67ccec43 1935
b4bac9b6 1936 if (isset($SESSION->justloggedin)) {
1937 unset($SESSION->justloggedin);
1938 if (!empty($CFG->displayloginfailures)) {
1939 if (!empty($USER->username) and !isguest()) {
1940 if ($count = count_login_failures($CFG->displayloginfailures, $USER->username, $USER->lastlogin)) {
1941 $menu .= '&nbsp;<font size="1">';
1942 if (empty($count->accounts)) {
1943 $menu .= get_string('failedloginattempts', '', $count);
1944 } else {
1945 $menu .= get_string('failedloginattemptsall', '', $count);
1946 }
1947 if (isadmin()) {
52af9a35 1948 $menu .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php'.
839f2456 1949 '?chooselog=1&amp;id=1&amp;modid=site_errors">'.get_string('logs').'</a>)';
b4bac9b6 1950 }
1951 $menu .= '</font>';
1952 }
1953 }
1954 }
1955 }
9fa49e22 1956
47037513 1957
6aaa17c7 1958 $encoding = current_charset();
1959 if (!empty($CFG->courselang)) {
a2fa19d8 1960 moodle_setlocale();
9fa49e22 1961 }
6aaa17c7 1962
b0ccd3fb 1963 $meta = '<meta http-equiv="content-type" content="text/html; charset='. $encoding .'" />'. "\n". $meta ."\n";
03fe48e7 1964 if (!$usexml) {
1965 @header('Content-type: text/html; charset='.$encoding);
1966 }
9fa49e22 1967
b0ccd3fb 1968 if ( get_string('thisdirection') == 'rtl' ) {
1969 $direction = ' dir="rtl"';
9fa49e22 1970 } else {
b0ccd3fb 1971 $direction = ' dir="ltr"';
9fa49e22 1972 }
6575bfd4 1973 //Accessibility: added the 'lang' attribute to $direction, used in theme <html> tag.
1974 $language = str_replace('_utf8','',$CFG->lang);
1975 $direction .= ' lang="'.$language.'" xml:lang="'.$language.'"';
ab9f24ad 1976
5debee2d 1977 if ($cache) { // Allow caching on "back" (but not on normal clicks)
1978 @header('Cache-Control: private, pre-check=0, post-check=0, max-age=0');
1979 @header('Pragma: no-cache');
772e78be 1980 @header('Expires: ');
5debee2d 1981 } else { // Do everything we can to always prevent clients and proxies caching
03fe48e7 1982 @header('Cache-Control: no-store, no-cache, must-revalidate');
1983 @header('Cache-Control: post-check=0, pre-check=0', false);
1984 @header('Pragma: no-cache');
5debee2d 1985 @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT');
1986 @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
03fe48e7 1987
5debee2d 1988 $meta .= "\n<meta http-equiv=\"pragma\" content=\"no-cache\" />";
1989 $meta .= "\n<meta http-equiv=\"expires\" content=\"0\" />";
66a51452 1990 }
5debee2d 1991 @header('Accept-Ranges: none');
66a51452 1992
1993 if ($usexml) { // Added by Gustav Delius / Mad Alex for MathML output
8f0cd6ef 1994 // Modified by Julian Sedding
66a51452 1995 $currentlanguage = current_language();
8f0cd6ef 1996 $mathplayer = preg_match("/MathPlayer/i", $_SERVER['HTTP_USER_AGENT']);
1997 if(!$mathplayer) {
1998 header('Content-Type: application/xhtml+xml');
1999 }
b0ccd3fb 2000 echo '<?xml version="1.0" ?>'."\n";
66a51452 2001 if (!empty($CFG->xml_stylesheets)) {
b0ccd3fb 2002 $stylesheets = explode(';', $CFG->xml_stylesheets);
66a51452 2003 foreach ($stylesheets as $stylesheet) {
b0ccd3fb 2004 echo '<?xml-stylesheet type="text/xsl" href="'. $CFG->wwwroot .'/'. $stylesheet .'" ?>' . "\n";
66a51452 2005 }
2006 }
b0ccd3fb 2007 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1';
e4576482 2008 if (!empty($CFG->xml_doctype_extra)) {
b0ccd3fb 2009 echo ' plus '. $CFG->xml_doctype_extra;
e4576482 2010 }
b0ccd3fb 2011 echo '//' . strtoupper($currentlanguage) . '" "'. $CFG->xml_dtd .'">'."\n";
8f0cd6ef 2012 $direction = " xmlns=\"http://www.w3.org/1999/xhtml\"
2013 xmlns:math=\"http://www.w3.org/1998/Math/MathML\"
8f0cd6ef 2014 xmlns:xlink=\"http://www.w3.org/1999/xlink\"
2015 $direction";
2016 if($mathplayer) {
2017 $meta .= '<object id="mathplayer" classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987">' . "\n";
b0ccd3fb 2018 $meta .= '<!--comment required to prevent this becoming an empty tag-->'."\n";
2019 $meta .= '</object>'."\n";
8f0cd6ef 2020 $meta .= '<?import namespace="math" implementation="#mathplayer" ?>' . "\n";
2021 }
9fa49e22 2022 }
2023
7bb6d80f 2024 // Clean up the title
2025
2eea2cce 2026 $title = str_replace('"', '&quot;', $title);
1d9fc417 2027 $title = strip_tags($title);
2eea2cce 2028
7bb6d80f 2029 // Create class and id for this page
2030
68d5f00a 2031 page_id_and_class($pageid, $pageclass);
7bb6d80f 2032
d6c66e12 2033 if (isset($course->id)) {
2034 $pageclass .= ' course-'.$course->id;
c09e00ba 2035 } else {
2036 $pageclass .= ' course-'.SITEID;
d6c66e12 2037 }
2038
e299f862 2039 if (!empty($USER->editing)) {
2040 $pageclass .= ' editing';
2041 }
2042
7bb6d80f 2043 $bodytags .= ' class="'.$pageclass.'" id="'.$pageid.'"';
772e78be 2044
560811bb 2045 include ($CFG->themedir.current_theme().'/header.html');
e608dddd 2046
cdf39255 2047 if (!empty($CFG->messaging)) {
2048 echo message_popup_window();
2049 }
9fa49e22 2050}
2051
d48b00b4 2052/**
2053 * This version of print_header is simpler because the course name does not have to be
2054 * provided explicitly in the strings. It can be used on the site page as in courses
2055 * Eventually all print_header could be replaced by print_header_simple
2056 *
89dcb99d 2057 * @param string $title Appears at the top of the window
2058 * @param string $heading Appears at the top of the page
2059 * @param string $navigation Premade navigation string (for use as breadcrumbs links)
2060 * @param string $focus Indicates form element to get cursor focus on load eg inputform.password
2061 * @param string $meta Meta tags to be added to the header
2062 * @param boolean $cache Should this page be cacheable?
2063 * @param string $button HTML code for a button (usually for module editing)
2064 * @param string $menu HTML code for a popup menu
2065 * @param boolean $usexml use XML for this page
2066 * @param string $bodytags This text will be included verbatim in the <body> tag (useful for onload() etc)
d48b00b4 2067 */
b0ccd3fb 2068function print_header_simple($title='', $heading='', $navigation='', $focus='', $meta='',
2069 $cache=true, $button='&nbsp;', $menu='', $usexml=false, $bodytags='') {
90fcc576 2070
52d55cfc 2071 global $course,$CFG; // The same hack is used in print_header
90fcc576 2072
2073 $shortname ='';
2074 if ($course->category) {
52d55cfc 2075 $shortname = '<a href="'.$CFG->wwwroot.'/course/view.php?id='. $course->id .'">'. $course->shortname .'</a> ->';
90fcc576 2076 }
2077
b0ccd3fb 2078 print_header($course->shortname .': '. $title, $course->fullname .' '. $heading, $shortname .' '. $navigation, $focus, $meta,
90fcc576 2079 $cache, $button, $menu, $usexml, $bodytags);
2080}
629b5885 2081
2082
d48b00b4 2083/**
2084 * Can provide a course object to make the footer contain a link to
2085 * to the course home page, otherwise the link will go to the site home
2086 *
2087 * @uses $CFG
2088 * @uses $USER
89dcb99d 2089 * @param course $course {@link $COURSE} object containing course information
2090 * @param ? $usercourse ?
d48b00b4 2091 * @todo Finish documenting this function
2092 */
b3a2b9dd 2093function print_footer($course=NULL, $usercourse=NULL) {
0d741155 2094 global $USER, $CFG, $THEME;
9fa49e22 2095
9fa49e22 2096/// Course links
2097 if ($course) {
a789577b 2098 if (is_string($course) && $course == 'none') { // Don't print any links etc
b3a2b9dd 2099 $homelink = '';
2100 $loggedinas = '';
0d741155 2101 $home = false;
a789577b 2102 } else if (is_string($course) && $course == 'home') { // special case for site home page - please do not remove
b3a2b9dd 2103 $course = get_site();
a77ac3dc 2104 $homelink = '<div class="sitelink">'.
2105 '<a title="moodle '. $CFG->release .' ('. $CFG->version .')" href="http://moodle.org/" target="_blank">'.
2106 '<br /><img width="100" height="30" src="pix/moodlelogo.gif" border="0" alt="moodlelogo" /></a></div>';
0d741155 2107 $home = true;
9fa49e22 2108 } else {
a77ac3dc 2109 $homelink = '<div class="homelink"><a target="'.$CFG->framename.'" href="'.$CFG->wwwroot.
2110 '/course/view.php?id='.$course->id.'">'.$course->shortname.'</a></div>';
0d741155 2111 $home = false;
9fa49e22 2112 }
2113 } else {
b3a2b9dd 2114 $course = get_site(); // Set course as site course by default
a77ac3dc 2115 $homelink = '<div class="homelink"><a target="'.$CFG->framename.'" href="'.$CFG->wwwroot.'/">'.get_string('home').'</a></div>';
0d741155 2116 $home = false;
9fa49e22 2117 }
2118
0d741155 2119/// Set up some other navigation links (passed from print_header by ugly hack)
2507b2f5 2120 $menu = isset($THEME->menu) ? str_replace('navmenu', 'navmenufooter', $THEME->menu) : '';
2121 $title = isset($THEME->title) ? $THEME->title : '';
2122 $button = isset($THEME->button) ? $THEME->button : '';
2123 $heading = isset($THEME->heading) ? $THEME->heading : '';
2124 $navigation = isset($THEME->navigation) ? $THEME->navigation : '';
2125 $navmenulist = isset($THEME->navmenulist) ? $THEME->navmenulist : '';
0d741155 2126
f940ee41 2127
b3a2b9dd 2128/// Set the user link if necessary
2129 if (!$usercourse and is_object($course)) {
1f2eec7b 2130 $usercourse = $course;
2131 }
2132
b3a2b9dd 2133 if (!isset($loggedinas)) {
2134 $loggedinas = user_login_string($usercourse, $USER);
2135 }
2136
0d741155 2137 if ($loggedinas == $menu) {
9e0d1983 2138 $menu = '';
0d741155 2139 }
2140
b8cea9b2 2141/// Provide some performance info if required
c2fd9e95 2142 $performanceinfo = '';
4907efae 2143 if (defined('MDL_PERF') || $CFG->debug > 7 || $CFG->perfdebug > 7) {
c2fd9e95 2144 $perf = get_performance_info();
853df85e 2145 if (defined('MDL_PERFTOLOG')) {
2146 error_log("PERF: " . $perf['txt']);
2147 }
4907efae 2148 if (defined('MDL_PERFTOFOOT') || $CFG->debug > 7 || $CFG->perfdebug > 7) {
c2fd9e95 2149 $performanceinfo = $perf['html'];
2150 }
572fe9ab 2151 }
b8cea9b2 2152
0d741155 2153
b3a2b9dd 2154/// Include the actual footer file
a282d0ff 2155
560811bb 2156 include ($CFG->themedir.current_theme().'/footer.html');
a9a9bdba 2157
a282d0ff 2158}
2159
c3f55692 2160/**
2161 * Returns the name of the current theme
2162 *
2163 * @uses $CFG
2164 * @param $USER
2165 * @param $SESSION
2166 * @return string
2167 */
2168function current_theme() {
32e2b302 2169 global $CFG, $USER, $SESSION, $course;
c3f55692 2170
417375b7 2171 if (!empty($CFG->pagetheme)) { // Page theme is for special page-only themes set by code
2172 return $CFG->pagetheme;
c3f55692 2173
59552aab 2174 } else if (!empty($CFG->coursetheme) and !empty($CFG->allowcoursethemes)) { // Course themes override others
c3f55692 2175 return $CFG->coursetheme;
2176
2177 } else if (!empty($SESSION->theme)) { // Session theme can override other settings
2178 return $SESSION->theme;
2179
32e2b302 2180 } else if (!empty($USER->theme) and !empty($CFG->allowuserthemes)) { // User theme can override site theme
c3f55692 2181 return $USER->theme;
2182
2183 } else {
2184 return $CFG->theme;
2185 }
2186}
2187
2188
d48b00b4 2189/**
2190 * This function is called by stylesheets to set up the header
2191 * approriately as well as the current path
2192 *
2193 * @uses $CFG
89dcb99d 2194 * @param int $lastmodified ?
2195 * @param int $lifetime ?
2196 * @param string $thename ?
d48b00b4 2197 */
55b734fb 2198function style_sheet_setup($lastmodified=0, $lifetime=300, $themename='', $forceconfig='', $lang='') {
6535be85 2199
9c4e6e21 2200 global $CFG, $THEME;
ab9f24ad 2201
a2e2bf64 2202 // Fix for IE6 caching - we don't want the filemtime('styles.php'), instead use now.
2203 $lastmodified = time();
2204
b0ccd3fb 2205 header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $lastmodified) . ' GMT');
2206 header('Expires: ' . gmdate("D, d M Y H:i:s", time() + $lifetime) . ' GMT');
a2e2bf64 2207 header('Cache-Control: max-age='. $lifetime);
b0ccd3fb 2208 header('Pragma: ');
2209 header('Content-type: text/css'); // Correct MIME type
6535be85 2210
d45fd4dd 2211 $DEFAULT_SHEET_LIST = array('styles_layout', 'styles_fonts', 'styles_color');
9c4e6e21 2212
2213 if (empty($themename)) {
2214 $themename = current_theme(); // So we have something. Normally not needed.
ab25ce31 2215 } else {
2216 $themename = clean_param($themename, PARAM_SAFEDIR);
9c4e6e21 2217 }
2218
2219 if (!empty($forceconfig)) { // Page wants to use the config from this theme instead
2220 unset($THEME);
2d40fc05 2221 include($CFG->themedir.$forceconfig.'/'.'config.php');
9c4e6e21 2222 }
2223
2224/// If this is the standard theme calling us, then find out what sheets we need
2225
2226 if ($themename == 'standard') {
2227 if (!isset($THEME->standardsheets) or $THEME->standardsheets === true) { // Use all the sheets we have
2228 $THEME->sheets = $DEFAULT_SHEET_LIST;
2229 } else if (empty($THEME->standardsheets)) { // We can stop right now!
2230 echo "/***** Nothing required from this stylesheet by main theme *****/\n\n";
2231 exit;
2232 } else { // Use the provided subset only
2233 $THEME->sheets = $THEME->standardsheets;
2234 }
2235
2236/// If we are a parent theme, then check for parent definitions
2237
2238 } else if (!empty($THEME->parent) && $themename == $THEME->parent) {
2239 if (!isset($THEME->parentsheets) or $THEME->parentsheets === true) { // Use all the sheets we have
2240 $THEME->sheets = $DEFAULT_SHEET_LIST;
2241 } else if (empty($THEME->parentsheets)) { // We can stop right now!
2242 echo "/***** Nothing required from this stylesheet by main theme *****/\n\n";
2243 exit;
2244 } else { // Use the provided subset only
2245 $THEME->sheets = $THEME->parentsheets;
2246 }
2247 }
2248
2249/// Work out the last modified date for this theme
2250
2251 foreach ($THEME->sheets as $sheet) {
2d40fc05 2252 if (file_exists($CFG->themedir.$themename.'/'.$sheet.'.css')) {
2253 $sheetmodified = filemtime($CFG->themedir.$themename.'/'.$sheet.'.css');
9c4e6e21 2254 if ($sheetmodified > $lastmodified) {
2255 $lastmodified = $sheetmodified;
2256 }
2257 }
6535be85 2258 }
2259
6535be85 2260
6ba172fb 2261/// Get a list of all the files we want to include
2262 $files = array();
2263
2264 foreach ($THEME->sheets as $sheet) {
2265 $files[] = array($CFG->themedir, $themename.'/'.$sheet.'.css');
2266 }
2267
2268 if ($themename == 'standard') { // Add any standard styles included in any modules
2269 if (!empty($THEME->modsheets)) { // Search for styles.php within activity modules
2270 if ($mods = get_list_of_plugins('mod')) {
2271 foreach ($mods as $mod) {
2272 if (file_exists($CFG->dirroot.'/mod/'.$mod.'/styles.php')) {
2273 $files[] = array($CFG->dirroot, '/mod/'.$mod.'/styles.php');
2274 }
08396bb2 2275 }
2276 }
2277 }
a2b3f884 2278
6ba172fb 2279 if (!empty($THEME->blocksheets)) { // Search for styles.php within block modules
2280 if ($mods = get_list_of_plugins('blocks')) {
2281 foreach ($mods as $mod) {
2282 if (file_exists($CFG->dirroot.'/blocks/'.$mod.'/styles.php')) {
2283 $files[] = array($CFG->dirroot, '/blocks/'.$mod.'/styles.php');
2284 }
08396bb2 2285 }
2286 }
2287 }
a2b3f884 2288
6ba172fb 2289 if (!empty($THEME->langsheets)) { // Search for styles.php within the current language
6ba172fb 2290 if (file_exists($CFG->dirroot.'/lang/'.$lang.'/styles.php')) {
2291 $files[] = array($CFG->dirroot, '/lang/'.$lang.'/styles.php');
2292 }
2293 }
08396bb2 2294 }
2295
6ba172fb 2296
2297 if ($files) {
2298 /// Produce a list of all the files first
2299 echo '/**************************************'."\n";
2300 echo ' * THEME NAME: '.$themename."\n *\n";
2301 echo ' * Files included in this sheet:'."\n *\n";
2302 foreach ($files as $file) {
2303 echo ' * '.$file[1]."\n";
08396bb2 2304 }
6ba172fb 2305 echo ' **************************************/'."\n\n";
08396bb2 2306
6ba172fb 2307
2308 /// Actually output all the files in order.
2309 foreach ($files as $file) {
2310 echo '/***** '.$file[1].' start *****/'."\n\n";
2311 @include_once($file[0].$file[1]);
2312 echo '/***** '.$file[1].' end *****/'."\n\n";
2313 }
9c4e6e21 2314 }
2315
2d40fc05 2316 return $CFG->themewww.$themename; // Only to help old themes (1.4 and earlier)
6535be85 2317}
2318
9c4e6e21 2319
2320function theme_setup($theme = '', $params=NULL) {
d74d4f20 2321/// Sets up global variables related to themes
2322
56766f85 2323 global $CFG, $THEME, $SESSION, $USER;
d74d4f20 2324
2325 if (empty($theme)) {
2326 $theme = current_theme();
2327 }
9c4e6e21 2328
55b734fb 2329/// Load up the theme config
2330 $THEME = NULL; // Just to be sure
2331 include($CFG->themedir. $theme .'/config.php'); // Main config for current theme
2332
9c4e6e21 2333/// Put together the parameters
2334 if (!$params) {
2335 $params = array();
2336 }
56766f85 2337 if ($theme != $CFG->theme) {
2338 $params[] = 'forceconfig='.$theme;
9c4e6e21 2339 }
55b734fb 2340
2341/// Force language too if required
2342 if (!empty($THEME->langsheets)) {
2343 $params[] = 'lang='.current_language();
2344 }
2345
2346/// Convert params to string
9c4e6e21 2347 if ($params) {
55b734fb 2348 $paramstring = '?'.implode('&', $params);
d74d4f20 2349 } else {
9c4e6e21 2350 $paramstring = '';
d74d4f20 2351 }
2352
9c4e6e21 2353/// Set up image paths
25580407 2354 if (empty($THEME->custompix)) { // Could be set in the above file
d74d4f20 2355 $CFG->pixpath = $CFG->wwwroot .'/pix';
2356 $CFG->modpixpath = $CFG->wwwroot .'/mod';
2357 } else {
2d40fc05 2358 $CFG->pixpath = $CFG->themewww . $theme .'/pix';
2359 $CFG->modpixpath = $CFG->themewww . $theme .'/pix/mod';
d74d4f20 2360 }
2361
9c4e6e21 2362/// Header and footer paths
2d40fc05 2363 $CFG->header = $CFG->themedir . $theme .'/header.html';
2364 $CFG->footer = $CFG->themedir . $theme .'/footer.html';
d74d4f20 2365
9c4e6e21 2366/// Define stylesheet loading order
d74d4f20 2367 $CFG->stylesheets = array();
2368 if ($theme != 'standard') { /// The standard sheet is always loaded first
2d40fc05 2369 $CFG->stylesheets[] = $CFG->themewww.'standard/styles.php'.$paramstring;
d74d4f20 2370 }
2371 if (!empty($THEME->parent)) { /// Parent stylesheets are loaded next
2d40fc05 2372 $CFG->stylesheets[] = $CFG->themewww.$THEME->parent.'/styles.php'.$paramstring;
d74d4f20 2373 }
2d40fc05 2374 $CFG->stylesheets[] = $CFG->themewww.$theme.'/styles.php'.$paramstring;
d74d4f20 2375
2376}
2377
c3f55692 2378
d48b00b4 2379/**
2380 * Returns text to be displayed to the user which reflects their login status
2381 *
2382 * @uses $CFG
2383 * @uses $USER
89dcb99d 2384 * @param course $course {@link $COURSE} object containing course information
2385 * @param user $user {@link $USER} object containing user information
2386 * @return string
d48b00b4 2387 */
c44d5d42 2388function user_login_string($course=NULL, $user=NULL) {
2389 global $USER, $CFG, $SITE;
a282d0ff 2390
0e18f827 2391 if (empty($user) and isset($USER->id)) {
a282d0ff 2392 $user = $USER;
2393 }
2394
c44d5d42 2395 if (empty($course)) {
2396 $course = $SITE;
2397 }
2398
a282d0ff 2399 if (isset($user->realuser)) {
b0ccd3fb 2400 if ($realuser = get_record('user', 'id', $user->realuser)) {
2d71e8ee 2401 $fullname = fullname($realuser, true);
2402 $realuserinfo = " [<a target=\"{$CFG->framename}\"
01eb4f5f 2403 href=\"$CFG->wwwroot/course/loginas.php?id=$course->id&amp;return=1\">$fullname</a>] ";
9fa49e22 2404 }
9d378732 2405 } else {
b0ccd3fb 2406 $realuserinfo = '';
9fa49e22 2407 }
2408
87180677 2409 if (empty($CFG->loginhttps)) {
2410 $wwwroot = $CFG->wwwroot;
2411 } else {
2412 $wwwroot = str_replace('http','https',$CFG->wwwroot);
2413 }
2414
a282d0ff 2415 if (isset($user->id) and $user->id) {
2d71e8ee 2416 $fullname = fullname($user, true);
2417 $username = "<a target=\"{$CFG->framename}\" href=\"$CFG->wwwroot/user/view.php?id=$user->id&amp;course=$course->id\">$fullname</a>";
5c3706b2 2418 $instudentview = (!empty($USER->studentview)) ? get_string('instudentview') : '';
0ae7e6f4 2419 if (isguest($user->id)) {
158de846 2420 $loggedinas = $realuserinfo.get_string('loggedinasguest').
b0ccd3fb 2421 " (<a target=\"{$CFG->framename}\" href=\"$wwwroot/login/index.php\">".get_string('login').'</a>)';
0ae7e6f4 2422 } else {
5c3706b2 2423 $loggedinas = $realuserinfo.get_string('loggedinas', 'moodle', $username).' '.$instudentview.
b0ccd3fb 2424 " (<a target=\"{$CFG->framename}\" href=\"$CFG->wwwroot/login/logout.php\">".get_string('logout').'</a>)';
0ae7e6f4 2425 }
9fa49e22 2426 } else {
b0ccd3fb 2427 $loggedinas = get_string('loggedinnot', 'moodle').
2428 " (<a target=\"{$CFG->framename}\" href=\"$wwwroot/login/index.php\">".get_string('login').'</a>)';
9fa49e22 2429 }
d3593a67 2430 return '<div class="logininfo">'.$loggedinas.'</div>';
9fa49e22 2431}
2432
d48b00b4 2433/**
2434 * Prints breadcrumbs links
2435 *
2436 * @uses $CFG
89dcb99d 2437 * @param string $navigation The breadcrumbs string to be printed
d48b00b4 2438 */
9fa49e22 2439function print_navigation ($navigation) {
0d6b9d4f 2440 global $CFG, $USER;
9fa49e22 2441
2442 if ($navigation) {
9a477f90 2443 //Accessibility: breadcrumb links now in a list, &raquo; replaced with image.
2444 $nav_text = get_string('youarehere','access');
3034bd23 2445 echo '<span class="accesshide">'.$nav_text.':</span><ul>';
9fa49e22 2446 if (! $site = get_site()) {
f150292f 2447 $site->shortname = get_string('home');
9fa49e22 2448 }
40d34f9e 2449 $navigation = '<li title="'.$nav_text.'"><img src="'.$CFG->pixpath.'/a/r_breadcrumb.gif" class="resize" alt="" /> '
2450 .str_replace('->', '</li><li title="'.$nav_text.'"><img src="'.$CFG->pixpath.'/a/r_breadcrumb.gif" class="resize" alt="" /> ', $navigation)."</li>\n";
9a477f90 2451 echo '<li class="first"><a target="'. $CFG->framename .'" href="'. $CFG->wwwroot.((!isadmin() && !empty($USER->id) && !empty($CFG->mymoodleredirect) && !isguest())
2452 ? '/my' : '') .'/">'. $site->shortname ."</a></li>\n". $navigation;
2453 echo "</ul>\n";
9fa49e22 2454 }
2455}
2456
d48b00b4 2457/**
bfca0094 2458 * Prints a string in a specified size (retained for backward compatibility)
d48b00b4 2459 *
89dcb99d 2460 * @param string $text The text to be displayed
2461 * @param int $size The size to set the font for text display.
d48b00b4 2462 */
d4df9200 2463function print_headline($text, $size=2) {
bfca0094 2464 print_heading($text, 'left', $size);
d4df9200 2465}
2466
d48b00b4 2467/**
2468 * Prints text in a format for use in headings.
2469 *
89dcb99d 2470 * @param string $text The text to be displayed
2471 * @param string $align The alignment of the printed paragraph of text
2472 * @param int $size The size to set the font for text display.
d48b00b4 2473 */
4419aa80 2474function print_heading($text, $align='', $size=2, $class='main') {
bfca0094 2475 if ($align) {
2476 $align = ' align="'.$align.'"';
2477 }
4419aa80 2478 if ($class) {
2479 $class = ' class="'.$class.'"';
2480 }
2481 echo "<h$size $align $class>".stripslashes_safe($text)."</h$size>";
9fa49e22 2482}
2483
d48b00b4 2484/**
2485 * Centered heading with attached help button (same title text)
2486 * and optional icon attached
2487 *
89dcb99d 2488 * @param string $text The text to be displayed
2489 * @param string $helppage The help page to link to
2490 * @param string $module The module whose help should be linked to
2491 * @param string $icon Image to display if needed
d48b00b4 2492 */
b0ccd3fb 2493function print_heading_with_help($text, $helppage, $module='moodle', $icon='') {
4419aa80 2494 echo '<h2 class="main help">'.$icon.stripslashes_safe($text);
9fa49e22 2495 helpbutton($helppage, $text, $module);
26ecdc5b 2496 echo '</h2>';
9fa49e22 2497}
ab9f24ad 2498
6ee8277f 2499
2500function print_heading_block($heading, $class='') {
b6f30b18 2501 //Accessibility: 'headingblock' is now H1, see theme/standard/styles_*.css: ??
2502 echo '<h2 class="headingblock header '.$class.'">'.stripslashes($heading).'</h2>';
6ee8277f 2503}
2504
2505
d48b00b4 2506/**
2507 * Print a link to continue on to another page.
2508 *
2509 * @uses $CFG
2510 * @param string $link The url to create a link to.
2511 */
9fa49e22 2512function print_continue($link) {
9fa49e22 2513
51a96819 2514 global $CFG;
2515
9fa49e22 2516 if (!$link) {
b0ccd3fb 2517 $link = $_SERVER['HTTP_REFERER'];
9fa49e22 2518 }
2519
a8f68426 2520 echo '<div class="continuebutton">';
2521 print_single_button($link, NULL, get_string('continue'), 'post', $CFG->framename);
2522 echo '</div>'."\n";
9fa49e22 2523}
2524
d48b00b4 2525/**
2526 * Print a message in a standard themed box.
408b65dd 2527 * See, {@link print_simple_box_start}.
d48b00b4 2528 *
408b65dd 2529 * @param string $align string, alignment of the box, not the text (default center, left, right).
2530 * @param string $width string, width of the box, including units %, for example '100%'.
2531 * @param string $color string, background colour of the box, for example '#eee'.
2532 * @param int $padding integer, padding in pixels, specified without units.
2533 * @param string $class string, space-separated class names.
d48b00b4 2534 * @todo Finish documenting this function
2535 */
da17a899 2536function print_simple_box($message, $align='', $width='', $color='', $padding=5, $class='generalbox', $id='') {
2537 print_simple_box_start($align, $width, $color, $padding, $class, $id);
7d8f674d 2538 echo stripslashes_safe($message);
9fa49e22 2539 print_simple_box_end();
2540}
2541
d48b00b4 2542/**
30c9e694 2543 * Print the top portion of a standard themed box using a TABLE. Yes, we know.
2544 * See bug 4943 for details on some accessibility work regarding this that didn't make it into 1.6.
408b65dd 2545 *
2546 * @param string $align string, alignment of the box, not the text (default center, left, right).
2547 * @param string $width string, width of the box, including % units, for example '100%'.
97f76a1a 2548 * @param string $color string, background colour of the box, for example '#eee'.
2549 * @param int $padding integer, padding in pixels, specified without units.
2550 * @param string $class string, space-separated class names.
d48b00b4 2551 */
da17a899 2552function print_simple_box_start($align='', $width='', $color='', $padding=5, $class='generalbox', $id='') {
9fa49e22 2553
c147b8ab 2554 if ($color) {
30c9e694 2555 $color = 'bgcolor="'. $color .'"';
8ceb3e67 2556 }
30c9e694 2557 if ($align) {
2558 $align = 'align="'. $align .'"';
8ceb3e67 2559 }
9fa49e22 2560 if ($width) {
30c9e694 2561 $width = 'width="'. $width .'"';
9fa49e22 2562 }
da17a899 2563 if ($id) {
2564 $id = 'id="'. $id .'"';
30c9e694 2565 }
2566 echo "<table $align $width $id class=\"$class\" border=\"0\" cellpadding=\"$padding\" cellspacing=\"0\">".
2567 "<tr><td $color class=\"$class"."content\">";
9fa49e22 2568}
2569
d48b00b4 2570/**
2571 * Print the end portion of a standard themed box.
d48b00b4 2572 */
9fa49e22 2573function print_simple_box_end() {
30c9e694 2574 echo '</td></tr></table>';
9fa49e22 2575}
2576
30c9e694 2577
d48b00b4 2578/**
2579 * Print a self contained form with a single submit button.
2580 *
89dcb99d 2581 * @param string $link ?
2582 * @param array $options ?
2583 * @param string $label ?
2584 * @param string $method ?
d48b00b4 2585 * @todo Finish documenting this function
2586 */
4c6c0e01 2587function print_single_button($link, $options, $label='OK', $method='get', $target='_self') {
6ba172fb 2588 echo '<div class="singlebutton">';
4c6c0e01 2589 echo '<form action="'. $link .'" method="'. $method .'" target="'.$target.'">';
9fa49e22 2590 if ($options) {
2591 foreach ($options as $name => $value) {
b0ccd3fb 2592 echo '<input type="hidden" name="'. $name .'" value="'. $value .'" />';
9fa49e22 2593 }
2594 }
6ba172fb 2595 echo '<input type="submit" value="'. $label .'" /></form></div>';
9fa49e22 2596}
2597
d48b00b4 2598/**
2599 * Print a spacer image with the option of including a line break.
2600 *
89dcb99d 2601 * @param int $height ?
2602 * @param int $width ?
2603 * @param boolean $br ?
d48b00b4 2604 * @todo Finish documenting this function
2605 */
9fa49e22 2606function print_spacer($height=1, $width=1, $br=true) {
2607 global $CFG;
ed3136ff 2608 echo '<img class="spacer" height="'. $height .'" width="'. $width .'" src="'. $CFG->wwwroot .'/pix/spacer.gif" alt="" />';
9fa49e22 2609 if ($br) {
b0ccd3fb 2610 echo '<br />'."\n";
9fa49e22 2611 }
2612}
2613
d48b00b4 2614/**
2615 * Given the path to a picture file in a course, or a URL,
2616 * this function includes the picture in the page.
2617 *
89dcb99d 2618 * @param string $path ?
2619 * @param int $courseid ?
2620 * @param int $height ?
2621 * @param int $width ?
2622 * @param string $link ?
d48b00b4 2623 * @todo Finish documenting this function
2624 */
b0ccd3fb 2625function print_file_picture($path, $courseid=0, $height='', $width='', $link='') {
9fa49e22 2626 global $CFG;
2627
2628 if ($height) {
b0ccd3fb 2629 $height = 'height="'. $height .'"';
9fa49e22 2630 }
2631 if ($width) {
b0ccd3fb 2632 $width = 'width="'. $width .'"';
9fa49e22 2633 }
2634 if ($link) {
b0ccd3fb 2635 echo '<a href="'. $link .'">';
9fa49e22 2636 }
b0ccd3fb 2637 if (substr(strtolower($path), 0, 7) == 'http://') {
2638 echo '<img border="0" '.$height . $width .' src="'. $path .'" />';
9fa49e22 2639
2640 } else if ($courseid) {
b0ccd3fb 2641 echo '<img border="0" '. $height . $width .' src="';
9fa49e22 2642 if ($CFG->slasharguments) { // Use this method if possible for better caching
b0ccd3fb 2643 echo $CFG->wwwroot .'/file.php/'. $courseid .'/'. $path;
9fa49e22 2644 } else {
b0ccd3fb 2645 echo $CFG->wwwroot .'/file.php?file=/'. $courseid .'/'. $path;
9fa49e22 2646 }
b0ccd3fb 2647 echo '" />';
9fa49e22 2648 } else {
b0ccd3fb 2649 echo 'Error: must pass URL or course';
9fa49e22 2650 }
2651 if ($link) {
b0ccd3fb 2652 echo '</a>';
9fa49e22 2653 }
2654}
2655
d48b00b4 2656/**
2657 * Print the specified user's avatar.
2658 *
89dcb99d 2659 * @param int $userid ?
2660 * @param int $courseid ?
2661 * @param boolean $picture Print the user picture?
4c6c0e01 2662 * @param int $size Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatability
89dcb99d 2663 * @param boolean $returnstring If false print picture to current page, otherwise return the output as string
2664 * @param boolean $link Enclose printed image in a link to view specified course?
2665 * return string
d48b00b4 2666 * @todo Finish documenting this function
2667 */
f66e1977 2668function print_user_picture($userid, $courseid, $picture, $size=0, $returnstring=false, $link=true, $target='') {
f374fb10 2669 global $CFG;
9fa49e22 2670
2671 if ($link) {
f66e1977 2672 if ($target) {
2673 $target=' target="_blank"';
2674 }
2675 $output = '<a '.$target.' href="'. $CFG->wwwroot .'/user/view.php?id='. $userid .'&amp;course='. $courseid .'">';
9fa49e22 2676 } else {
b0ccd3fb 2677 $output = '';
9fa49e22 2678 }
4c6c0e01 2679 if (empty($size)) {
2680 $file = 'f2';
da7a785b 2681 $size = 35;
4c6c0e01 2682 } else if ($size === true or $size == 1) {
b0ccd3fb 2683 $file = 'f1';
9fa49e22 2684 $size = 100;
4c6c0e01 2685 } else if ($size >= 50) {
2686 $file = 'f1';
9fa49e22 2687 } else {
b0ccd3fb 2688 $file = 'f2';
9fa49e22 2689 }
113a79e2 2690 $class = "userpicture";
67a63a30 2691 if ($picture) { // Print custom user picture
9fa49e22 2692 if ($CFG->slasharguments) { // Use this method if possible for better caching
113a79e2 2693 $src = $CFG->wwwroot .'/user/pix.php/'. $userid .'/'. $file .'.jpg"';
9fa49e22 2694 } else {
113a79e2 2695 $src = $CFG->wwwroot .'/user/pix.php?file=/'. $userid .'/'. $file .'.jpg"';
9fa49e22 2696 }
67a63a30 2697 } else { // Print default user pictures (use theme version if available)
113a79e2 2698 $class .= " defaultuserpic";
2699 $src = "$CFG->pixpath/u/$file.png\"";
9fa49e22 2700 }
113a79e2 2701 $output .= "<img class=\"$class\" align=\"middle\" src=\"$src".
2702 " border=\"0\" width=\"$size\" height=\"$size\" alt=\"\" />";
9fa49e22 2703 if ($link) {
b0ccd3fb 2704 $output .= '</a>';
9fa49e22 2705 }
2706
2707 if ($returnstring) {
2708 return $output;
2709 } else {
2710 echo $output;
2711 }
2712}
2713
d48b00b4 2714/**
2715 * Prints a summary of a user in a nice little box.
2716 *
89dcb99d 2717 * @uses $CFG
2718 * @uses $USER
2719 * @param user $user A {@link $USER} object representing a user
2720 * @param course $course A {@link $COURSE} object representing a course
d48b00b4 2721 */
f19570d0 2722function print_user($user, $course, $messageselect=false) {
951b22a8 2723
89dcb99d 2724 global $CFG, $USER;
499795e8 2725
951b22a8 2726 static $string;
2727 static $datestring;
2728 static $countries;
2729 static $isteacher;
37d83d99 2730 static $isadmin;
951b22a8 2731
2732 if (empty($string)) { // Cache all the strings for the rest of the page
2733
b0ccd3fb 2734 $string->email = get_string('email');
2735 $string->location = get_string('location');
2736 $string->lastaccess = get_string('lastaccess');
2737 $string->activity = get_string('activity');
2738 $string->unenrol = get_string('unenrol');
2739 $string->loginas = get_string('loginas');
2740 $string->fullprofile = get_string('fullprofile');
2741 $string->role = get_string('role');
2742 $string->name = get_string('name');
2743 $string->never = get_string('never');
2744
2745 $datestring->day = get_string('day');
2746 $datestring->days = get_string('days');
2747 $datestring->hour = get_string('hour');
2748 $datestring->hours = get_string('hours');
2749 $datestring->min = get_string('min');
2750 $datestring->mins = get_string('mins');
2751 $datestring->sec = get_string('sec');
2752 $datestring->secs = get_string('secs');
951b22a8 2753
2754 $countries = get_list_of_countries();
2755
2756 $isteacher = isteacher($course->id);
37d83d99 2757 $isadmin = isadmin();
951b22a8 2758 }
2759
3468d58a 2760/// Get the hidden field list
2761 if ($isteacher || $isadmin) {
2762 $hiddenfields = array();
2763 } else {
2764 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
2765 }
2766
ed3136ff 2767 echo '<table class="userinfobox">';
951b22a8 2768 echo '<tr>';
ed3136ff 2769 echo '<td class="left side">';
951b22a8 2770 print_user_picture($user->id, $course->id, $user->picture, true);
2771 echo '</td>';
ed3136ff 2772 echo '<td class="content">';
2773 echo '<div class="username">'.fullname($user, $isteacher).'</div>';
2774 echo '<div class="info">';
951b22a8 2775 if (!empty($user->role) and ($user->role <> $course->teacher)) {
b0ccd3fb 2776 echo $string->role .': '. $user->role .'<br />';
951b22a8 2777 }
d0ec93fb 2778 if ($user->maildisplay == 1 or ($user->maildisplay == 2 and $course->category and !isguest()) or $isteacher) {
b0ccd3fb 2779 echo $string->email .': <a href="mailto:'. $user->email .'">'. $user->email .'</a><br />';
951b22a8 2780 }
3468d58a 2781 if (($user->city or $user->country) and (!isset($hiddenfields['city']) or !isset($hiddenfields['country']))) {
b0ccd3fb 2782 echo $string->location .': ';
3468d58a 2783 if ($user->city && !isset($hiddenfields['city'])) {
b40bc478 2784 echo $user->city;
2785 }
3468d58a 2786 if (!empty($countries[$user->country]) && !isset($hiddenfields['country'])) {
2787 if ($user->city && !isset($hiddenfields['city'])) {
b40bc478 2788 echo ', ';
2789 }
2790 echo $countries[$user->country];
2791 }
b0ccd3fb 2792 echo '<br />';
951b22a8 2793 }
ae8a5ff0 2794
3468d58a 2795 if (!isset($hiddenfields['lastaccess'])) {
2796 if ($user->lastaccess) {
2797 echo $string->lastaccess .': '. userdate($user->lastaccess);
2798 echo '&nbsp ('. format_time(time() - $user->lastaccess, $datestring) .')';
2799 } else {
2800 echo $string->lastaccess .': '. $string->never;
2801 }
951b22a8 2802 }
ed3136ff 2803 echo '</div></td><td class="links">';
ae8a5ff0 2804 //link to blogs
2805
2806 echo '<a href="'.$CFG->wwwroot.'/blog/index.php?userid='.$user->id.'">'.get_string('blogs','blog').'</a><br />';
951b22a8 2807 if ($isteacher) {
2808 $timemidnight = usergetmidnight(time());
b0ccd3fb 2809 echo '<a href="'. $CFG->wwwroot .'/course/user.php?id='. $course->id .'&amp;user='. $user->id .'">'. $string->activity .'</a><br />';
37d83d99 2810 if (!iscreator($user->id) or ($isadmin and !isadmin($user->id))) { // Includes admins
f29667f6 2811 if ($course->category and isteacheredit($course->id) and isstudent($course->id, $user->id)) { // Includes admins
b0ccd3fb 2812 echo '<a href="'. $CFG->wwwroot .'/course/unenrol.php?id='. $course->id .'&amp;user='. $user->id .'">'. $string->unenrol .'</a><br />';
4e3a6092 2813 }
2814 if ($USER->id != $user->id) {
b0ccd3fb 2815 echo '<a href="'. $CFG->wwwroot .'/course/loginas.php?id='. $course->id .'&amp;user='. $user->id .'">'. $string->loginas .'</a><br />';
4e3a6092 2816 }
951b22a8 2817 }
ab9f24ad 2818 }
b0ccd3fb 2819 echo '<a href="'. $CFG->wwwroot .'/user/view.php?id='. $user->id .'&amp;course='. $course->id .'">'. $string->fullprofile .'...</a>';
951b22a8 2820
f19570d0 2821 if (!empty($messageselect) && $isteacher) {
9a0f8502 2822 echo '<br /><input type="checkbox" name="';
2823 if (isteacher($course->id, $user->id)) {
2824 echo 'teacher';
2825 } else {
2826 echo 'user';
2827 }
2828 echo $user->id.'" /> ';
f19570d0 2829 }
2830
951b22a8 2831 echo '</td></tr></table>';
2832}
2833
d48b00b4 2834/**
2835 * Print a specified group's avatar.
2836 *
89dcb99d 2837 * @param group $group A {@link group} object representing a group
2838 * @param int $courseid ?
2839 * @param boolean $large ?
2840 * @param boolean $returnstring ?
2841 * @param boolean $link ?
2842 * @return string
d48b00b4 2843 * @todo Finish documenting this function
2844 */
f2c80965 2845function print_group_picture($group, $courseid, $large=false, $returnstring=false, $link=true) {
f374fb10 2846 global $CFG;
2847
97ea4833 2848 static $isteacheredit;
2849
2850 if (!isset($isteacheredit)) {
2851 $isteacheredit = isteacheredit($courseid);
2852 }
2853
2854 if ($group->hidepicture and !$isteacheredit) {
3c0561cf 2855 return '';
2856 }
c3cbfe7f 2857
97ea4833 2858 if ($link or $isteacheredit) {
a756cf1d 2859 $output = '<a href="'. $CFG->wwwroot .'/user/index.php?id='. $courseid .'&amp;group='. $group->id .'">';
3c0561cf 2860 } else {
2861 $output = '';
2862 }
2863 if ($large) {
b0ccd3fb 2864 $file = 'f1';
3c0561cf 2865 $size = 100;
2866 } else {
b0ccd3fb 2867 $file = 'f2';
3c0561cf 2868 $size = 35;
2869 }
2870 if ($group->picture) { // Print custom group picture
2871 if ($CFG->slasharguments) { // Use this method if possible for better caching
ed3136ff 2872 $output .= '<img class="grouppicture" align="middle" src="'.$CFG->wwwroot.'/user/pixgroup.php/'.$group->id.'/'.$file.'.jpg"'.
2873 ' border="0" width="'.$size.'" height="'.$size.'" alt="" title="'.s($group->name).'"/>';
f2c80965 2874 } else {
ed3136ff 2875 $output .= '<img class="grouppicture" align="middle" src="'.$CFG->wwwroot.'/user/pixgroup.php?file=/'.$group->id.'/'.$file.'.jpg"'.
2876 ' border="0" width="'.$size.'" height="'.$size.'" alt="" title="'.s($group->name).'"/>';
f2c80965 2877 }
f374fb10 2878 }
97ea4833 2879 if ($link or $isteacheredit) {
b0ccd3fb 2880 $output .= '</a>';
3c0561cf 2881 }
f374fb10 2882
2883 if ($returnstring) {
2884 return $output;
2885 } else {
2886 echo $output;
2887 }
2888}
2889
d48b00b4 2890/**
2891 * Print a png image.
2892 *
89dcb99d 2893 * @param string $url ?
2894 * @param int $sizex ?
2895 * @param int $sizey ?
2896 * @param boolean $returnstring ?
2897 * @param string $parameters ?
d48b00b4 2898 * @todo Finish documenting this function
2899 */
35067c43 2900function print_png($url, $sizex, $sizey, $returnstring, $parameters='alt=""') {
2901 global $CFG;
2902 static $recentIE;
2903
2904 if (!isset($recentIE)) {
2905 $recentIE = check_browser_version('MSIE', '5.0');
2906 }
2907
2908 if ($recentIE) { // work around the HORRIBLE bug IE has with alpha transparencies
89dcb99d 2909 $output .= '<img src="'. $CFG->pixpath .'/spacer.gif" width="'. $sizex .'" height="'. $sizey .'"'.
430c6392 2910 ' border="0" class="png" style="width: '. $sizex .'px; height: '. $sizey .'px; '.
89dcb99d 2911 ' filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='.
2912 "'$url', sizingMethod='scale') ".
2913 ' '. $parameters .' />';
35067c43 2914 } else {
89dcb99d 2915 $output .= '<img src="'. $url .'" border="0" width="'. $sizex .'" height="'. $sizey .'" '.
2916 ' '. $parameters .' />';
35067c43 2917 }
2918
2919 if ($returnstring) {
2920 return $output;
2921 } else {
2922 echo $output;
2923 }
2924}
2925
d48b00b4 2926/**
2927 * Print a nicely formatted table.
2928 *
89dcb99d 2929 * @param array $table is an object with several properties.
2930 * <ul<li>$table->head - An array of heading names.
2931 * <li>$table->align - An array of column alignments
2932 * <li>$table->size - An array of column sizes
2933 * <li>$table->wrap - An array of "nowrap"s or nothing
2934 * <li>$table->data[] - An array of arrays containing the data.
2935 * <li>$table->width - A percentage of the page
5889c1bb 2936 * <li>$table->tablealign - Align the whole table
89dcb99d 2937 * <li>$table->cellpadding - Padding on each cell
2938 * <li>$table->cellspacing - Spacing between cells
2939 * </ul>
2940 * @return boolean
d48b00b4 2941 * @todo Finish documenting this function
2942 */
9fa49e22 2943function print_table($table) {
9fa49e22 2944
2945 if (isset($table->align)) {
2946 foreach ($table->align as $key => $aa) {
2947 if ($aa) {
b0ccd3fb 2948 $align[$key] = ' align="'. $aa .'"';
9fa49e22 2949 } else {
b0ccd3fb 2950 $align[$key] = '';
9fa49e22 2951 }
2952 }
2953 }
2954 if (isset($table->size)) {
2955 foreach ($table->size as $key => $ss) {
2956 if ($ss) {
b0ccd3fb 2957 $size[$key] = ' width="'. $ss .'"';
9fa49e22 2958 } else {
b0ccd3fb 2959 $size[$key] = '';
9fa49e22 2960 }
2961 }
2962 }
5867bfb5 2963 if (isset($table->wrap)) {
2964 foreach ($table->wrap as $key => $ww) {
2965 if ($ww) {
b0ccd3fb 2966 $wrap[$key] = ' nowrap="nowrap" ';
5867bfb5 2967 } else {
b0ccd3fb 2968 $wrap[$key] = '';
5867bfb5 2969 }
2970 }
2971 }
9fa49e22 2972
9d378732 2973 if (empty($table->width)) {
b0ccd3fb 2974 $table->width = '80%';
9fa49e22 2975 }
2976
5889c1bb 2977 if (empty($table->tablealign)) {
2978 $table->tablealign = 'center';
2979 }
2980
9d378732 2981 if (empty($table->cellpadding)) {
b0ccd3fb 2982 $table->cellpadding = '5';
9fa49e22 2983 }
2984
9d378732 2985 if (empty($table->cellspacing)) {
b0ccd3fb 2986 $table->cellspacing = '1';
9fa49e22 2987 }
2988
da17a899 2989 if (empty($table->class)) {
2990 $table->class = 'generaltable';
2991 }
2992
2993 $tableid = empty($table->id) ? '' : 'id="'.$table->id.'"';
2994
5889c1bb 2995 echo '<table width="'.$table->width.'" border="0" align="'.$table->tablealign.'" ';
da17a899 2996 echo " cellpadding=\"$table->cellpadding\" cellspacing=\"$table->cellspacing\" class=\"$table->class\" $tableid>\n";
9fa49e22 2997
e21e20cf 2998 $countcols = 0;
2999
b79f41cd 3000 if (!empty($table->head)) {
f150292f 3001 $countcols = count($table->head);
b0ccd3fb 3002 echo '<tr>';
9fa49e22 3003 foreach ($table->head as $key => $heading) {
ab9f24ad 3004
9d378732 3005 if (!isset($size[$key])) {
b0ccd3fb 3006 $size[$key] = '';
ab9f24ad 3007 }
9d378732 3008 if (!isset($align[$key])) {
b0ccd3fb 3009 $align[$key] = '';
ab9f24ad 3010 }
591052a4 3011 echo '<th valign="top" '. $align[$key].$size[$key] .' nowrap="nowrap" class="header c'.$key.'">'. $heading .'</th>';
9fa49e22 3012 }
b0ccd3fb 3013 echo '</tr>'."\n";
9fa49e22 3014 }
3015
a1f8ff87 3016 if (!empty($table->data)) {
19505667 3017 $oddeven = 1;
3018 foreach ($table->data as $key => $row) {
3019 $oddeven = $oddeven ? 0 : 1;
3020 echo '<tr class="r'.$oddeven.'">'."\n";
b0ccd3fb 3021 if ($row == 'hr' and $countcols) {
3022 echo '<td colspan="'. $countcols .'"><div class="tabledivider"></div></td>';
e21e20cf 3023 } else { /// it's a normal row of data
3024 foreach ($row as $key => $item) {
3025 if (!isset($size[$key])) {
b0ccd3fb 3026 $size[$key] = '';
ab9f24ad 3027 }
e21e20cf 3028 if (!isset($align[$key])) {
b0ccd3fb 3029 $align[$key] = '';
ab9f24ad 3030 }
e21e20cf 3031 if (!isset($wrap[$key])) {
b0ccd3fb 3032 $wrap[$key] = '';
ab9f24ad 3033 }
591052a4 3034 echo '<td '. $align[$key].$size[$key].$wrap[$key] .' class="cell c'.$key.'">'. $item .'</td>';
e21e20cf 3035 }
a1f8ff87 3036 }
b0ccd3fb 3037 echo '</tr>'."\n";
9fa49e22 3038 }
9fa49e22 3039 }
b0ccd3fb 3040 echo '</table>'."\n";
9fa49e22 3041
3042 return true;
3043}
3044
d48b00b4 3045/**
3046 * Creates a nicely formatted table and returns it.
3047 *
89dcb99d 3048 * @param array $table is an object with several properties.
3049 * <ul<li>$table->head - An array of heading names.
3050 * <li>$table->align - An array of column alignments
3051 * <li>$table->size - An array of column sizes
3052 * <li>$table->wrap - An array of "nowrap"s or nothing
3053 * <li>$table->data[] - An array of arrays containing the data.
3054 * <li>$table->class - A css class name
3055 * <li>$table->fontsize - Is the size of all the text
3056 * <li>$table->tablealign - Align the whole table
3057 * <li>$table->width - A percentage of the page
3058 * <li>$table->cellpadding - Padding on each cell
3059 * <li>$table->cellspacing - Spacing between cells
3060 * </ul>
3061 * @return string
d48b00b4 3062 * @todo Finish documenting this function
3063 */
2f4d324b 3064function make_table($table) {
2f4d324b 3065
3066 if (isset($table->align)) {
3067 foreach ($table->align as $key => $aa) {
3068 if ($aa) {
b0ccd3fb 3069 $align[$key] = ' align="'. $aa .'"';
2f4d324b 3070 } else {
b0ccd3fb 3071 $align[$key] = '';
2f4d324b 3072 }
3073 }
3074 }
3075 if (isset($table->size)) {
3076 foreach ($table->size as $key => $ss) {
3077 if ($ss) {
b0ccd3fb 3078 $size[$key] = ' width="'. $ss .'"';
2f4d324b 3079 } else {
b0ccd3fb 3080 $size[$key] = '';
2f4d324b 3081 }
3082 }
3083 }
3084 if (isset($table->wrap)) {
3085 foreach ($table->wrap as $key => $ww) {
3086 if ($ww) {
b0ccd3fb 3087 $wrap[$key] = ' nowrap="nowrap" ';
2f4d324b 3088 } else {
b0ccd3fb 3089 $wrap[$key] = '';
2f4d324b 3090 }
3091 }
3092 }
3093
3094 if (empty($table->width)) {
b0ccd3fb 3095 $table->width = '80%';
2f4d324b 3096 }
3097
3098 if (empty($table->tablealign)) {
b0ccd3fb 3099 $table->tablealign = 'center';
2f4d324b 3100 }
3101
3102 if (empty($table->cellpadding)) {
b0ccd3fb 3103 $table->cellpadding = '5';
2f4d324b 3104 }
3105
3106 if (empty($table->cellspacing)) {
b0ccd3fb 3107 $table->cellspacing = '1';
2f4d324b 3108 }
3109
3110 if (empty($table->class)) {
b0ccd3fb 3111 $table->class = 'generaltable';
2f4d324b 3112 }
3113
3114 if (empty($table->fontsize)) {
b0ccd3fb 3115 $fontsize = '';
2f4d324b 3116 } else {
b0ccd3fb 3117 $fontsize = '<font size="'. $table->fontsize .'">';
2f4d324b 3118 }
3119
5aeaeb57 3120 $output = '<table width="'. $table->width .'" align="'. $table->tablealign .'" ';
b0ccd3fb 3121 $output .= ' cellpadding="'. $table->cellpadding .'" cellspacing="'. $table->cellspacing .'" class="'. $table->class .'">'."\n";
2f4d324b 3122
3123 if (!empty($table->head)) {
5aeaeb57 3124 $output .= '<tr valign="top">';
2f4d324b 3125 foreach ($table->head as $key => $heading) {
3126 if (!isset($size[$key])) {
b0ccd3fb 3127 $size[$key] = '';
ab9f24ad 3128 }
2f4d324b 3129 if (!isset($align[$key])) {
b0ccd3fb 3130 $align[$key] = '';
ab9f24ad 3131 }
b0ccd3fb 3132 $output .= '<th valign="top" '. $align[$key].$size[$key] .' nowrap="nowrap" class="'. $table->class .'header">'.$fontsize.$heading.'</th>';
2f4d324b 3133 }
b0ccd3fb 3134 $output .= '</tr>'."\n";
2f4d324b 3135 }
3136
3137 foreach ($table->data as $row) {
b0ccd3fb 3138 $output .= '<tr valign="top">';
2f4d324b 3139 foreach ($row as $key => $item) {
3140 if (!isset($size[$key])) {
b0ccd3fb 3141 $size[$key] = '';
ab9f24ad 3142 }
2f4d324b 3143 if (!isset($align[$key])) {
b0ccd3fb 3144 $align[$key] = '';
ab9f24ad 3145 }
2f4d324b 3146 if (!isset($wrap[$key])) {
b0ccd3fb 3147 $wrap[$key] = '';
ab9f24ad 3148 }
b0ccd3fb 3149 $output .= '<td '. $align[$key].$size[$key].$wrap[$key] .' class="'. $table->class .'cell">'. $fontsize . $item .'</td>';
2f4d324b 3150 }
b0ccd3fb 3151 $output .= '</tr>'."\n";
2f4d324b 3152 }
b0ccd3fb 3153 $output .= '</table>'."\n";
2f4d324b 3154
3155 return $output;
3156}
3157
8f7dc7f1 3158function print_recent_activity_note($time, $user, $isteacher, $text, $link) {
3159 static $strftimerecent;
3160
3161 if (empty($strftimerecent)) {
3162 $strftimerecent = get_string('strftimerecent');
3163 }
3164
3165 $date = userdate($time, $strftimerecent);
3166 $name = fullname($user, $isteacher);
3167
3168 echo '<div class="head">';
a169b5ee 3169 echo '<div class="date">'.$date.'</div> '.
3170 '<div class="name">'.fullname($user, $isteacher).'</div>';
8f7dc7f1 3171 echo '</div>';
188e4dd9 3172 echo '<div class="info"><a href="'.$link.'">'.format_string($text,true).'</a></div>';
8f7dc7f1 3173}
3174
3175
d48b00b4 3176/**
3177 * Prints a basic textarea field.
3178 *
89dcb99d 3179 * @uses $CFG
3180 * @param boolean $usehtmleditor ?
3181 * @param int $rows ?
3182 * @param int $cols ?
ed3136ff 3183 * @param null $width <b>Legacy field no longer used!</b> Set to zero to get control over mincols
3184 * @param null $height <b>Legacy field no longer used!</b> Set to zero to get control over minrows
89dcb99d 3185 * @param string $name ?
3186 * @param string $value ?
3187 * @param int $courseid ?
d48b00b4 3188 * @todo Finish documenting this function
3189 */
035d465c 3190function print_textarea($usehtmleditor, $rows, $cols, $width, $height, $name, $value='', $courseid=0, $return=false) {
bc01a2b8 3191/// $width and height are legacy fields and no longer used as pixels like they used to be.
3192/// However, you can set them to zero to override the mincols and minrows values below.
4c46c425 3193
47037513 3194 global $CFG, $course;
572fe9ab 3195 static $scriptcount; // For loading the htmlarea script only once.
50bdc74d 3196
bc01a2b8 3197 $mincols = 65;
3198 $minrows = 10;
a0fd7c1d 3199 $str = '';
3200
c06c8492 3201 if ( empty($CFG->editorsrc) ) { // for backward compatibility.
3202 if (empty($courseid)) {
3203 if (!empty($course->id)) { // search for it in global context
3204 $courseid = $course->id;
3205 }
50bdc74d 3206 }
9fa49e22 3207
c06c8492 3208 if (empty($scriptcount)) {
3209 $scriptcount = 0;
3210 }
572fe9ab 3211
c06c8492 3212 if ($usehtmleditor) {
d046ae55 3213
c06c8492 3214 if (!empty($courseid) and isteacher($courseid)) {
a0fd7c1d 3215 $str .= ($scriptcount < 1) ? '<script type="text/javascript" src="'.
c06c8492 3216 $CFG->wwwroot .'/lib/editor/htmlarea/htmlarea.php?id='. $courseid .'"></script>'."\n" : '';
3217 } else {
a0fd7c1d 3218 $str .= ($scriptcount < 1) ? '<script type="text/javascript" src="'.
c06c8492 3219 $CFG->wwwroot .'/lib/editor/htmlarea/htmlarea.php"></script>'."\n" : '';
3220 }
035d465c 3221 $str .= ($scriptcount < 1) ? '<script type="text/javascript" src="'.
c06c8492 3222 $CFG->wwwroot .'/lib/editor/htmlarea/lang/en.php"></script>'."\n" : '';
3223 $scriptcount++;
50bdc74d 3224