Automatic installer.php lang files by installer_builder (20070202)
[moodle.git] / lib / weblib.php
blob061c8934e15226e1bb60d4298fbc6a4b77871989
1 <?php // $Id$
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 ///////////////////////////////////////////////////////////////////////////
26 /**
27 * Library of functions for web output
29 * Library of all general-purpose Moodle PHP functions and constants
30 * that produce HTML output
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$
37 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
38 * @package moodlecore
41 /// We are going to uses filterlib functions here
42 require_once("$CFG->libdir/filterlib.php");
44 /// Constants
46 /// Define text formatting types ... eventually we can add Wiki, BBcode etc
48 /**
49 * Does all sorts of transformations and filtering
51 define('FORMAT_MOODLE', '0'); // Does all sorts of transformations and filtering
53 /**
54 * Plain HTML (with some tags stripped)
56 define('FORMAT_HTML', '1'); // Plain HTML (with some tags stripped)
58 /**
59 * Plain text (even tags are printed in full)
61 define('FORMAT_PLAIN', '2'); // Plain text (even tags are printed in full)
63 /**
64 * Wiki-formatted text
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)
68 define('FORMAT_WIKI', '3'); // Wiki-formatted text
70 /**
71 * Markdown-formatted text http://daringfireball.net/projects/markdown/
73 define('FORMAT_MARKDOWN', '4'); // Markdown-formatted text http://daringfireball.net/projects/markdown/
76 /**
77 * Allowed tags - string of html tags that can be tested against for safe html tags
78 * @global string $ALLOWED_TAGS
80 $ALLOWED_TAGS =
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>';
83 /**
84 * Allowed protocols - array of protocols that are safe to use in links and so on
85 * @global string $ALLOWED_PROTOCOLS
87 $ALLOWED_PROTOCOLS = array('http', 'https', 'ftp', 'news', 'mailto', 'rtsp', 'teamspeak', 'gopher', 'mms',
88 'color', 'callto', 'cursor', 'text-align', 'font-size', 'font-weight', 'font-style',
89 'border', 'margin', 'padding', 'background'); // CSS as well to get through kses
92 /// Functions
94 /**
95 * Add quotes to HTML characters
97 * Returns $var with HTML characters (like "<", ">", etc.) properly quoted.
98 * This function is very similar to {@link p()}
100 * @param string $var the string potentially containing HTML characters
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.
103 * @return string
105 function s($var, $strip=false) {
107 if ($var == '0') { // for integer 0, boolean false, string '0'
108 return '0';
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));
119 * Add quotes to HTML characters
121 * Prints $var with HTML characters (like "<", ">", etc.) properly quoted.
122 * This function is very similar to {@link s()}
124 * @param string $var the string potentially containing HTML characters
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.
127 * @return string
129 function p($var, $strip=false) {
130 echo s($var, $strip);
135 * Ensure that a variable is set
137 * Return $var if it is defined, otherwise return $default,
138 * This function is very similar to {@link optional_variable()}
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
144 function nvl(&$var, $default='') {
145 global $CFG;
147 if (!empty($CFG->disableglobalshack)) {
148 error( "The nvl() function is deprecated ($var, $default)." );
150 return isset($var) ? $var : $default;
154 * Remove query string from url
156 * Takes in a URL and returns it without the querystring portion
158 * @param string $url the url which may have a query string attached
159 * @return string
161 function strip_querystring($url) {
163 if ($commapos = strpos($url, '?')) {
164 return substr($url, 0, $commapos);
165 } else {
166 return $url;
171 * Returns the URL of the HTTP_REFERER, less the querystring portion
172 * @return string
174 function get_referer() {
176 return strip_querystring(nvl($_SERVER['HTTP_REFERER']));
181 * Returns the name of the current script, WITH the querystring portion.
182 * this function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
183 * return different things depending on a lot of things like your OS, Web
184 * server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.)
185 * <b>NOTE:</b> This function returns false if the global variables needed are not set.
187 * @return string
189 function me() {
191 if (!empty($_SERVER['REQUEST_URI'])) {
192 return $_SERVER['REQUEST_URI'];
194 } else if (!empty($_SERVER['PHP_SELF'])) {
195 if (!empty($_SERVER['QUERY_STRING'])) {
196 return $_SERVER['PHP_SELF'] .'?'. $_SERVER['QUERY_STRING'];
198 return $_SERVER['PHP_SELF'];
200 } else if (!empty($_SERVER['SCRIPT_NAME'])) {
201 if (!empty($_SERVER['QUERY_STRING'])) {
202 return $_SERVER['SCRIPT_NAME'] .'?'. $_SERVER['QUERY_STRING'];
204 return $_SERVER['SCRIPT_NAME'];
206 } else if (!empty($_SERVER['URL'])) { // May help IIS (not well tested)
207 if (!empty($_SERVER['QUERY_STRING'])) {
208 return $_SERVER['URL'] .'?'. $_SERVER['QUERY_STRING'];
210 return $_SERVER['URL'];
212 } else {
213 notify('Warning: Could not find any of these web server variables: $REQUEST_URI, $PHP_SELF, $SCRIPT_NAME or $URL');
214 return false;
219 * Like {@link me()} but returns a full URL
220 * @see me()
221 * @return string
223 function qualified_me() {
225 global $CFG;
227 if (!empty($CFG->wwwroot)) {
228 $url = parse_url($CFG->wwwroot);
231 if (!empty($url['host'])) {
232 $hostname = $url['host'];
233 } else if (!empty($_SERVER['SERVER_NAME'])) {
234 $hostname = $_SERVER['SERVER_NAME'];
235 } else if (!empty($_ENV['SERVER_NAME'])) {
236 $hostname = $_ENV['SERVER_NAME'];
237 } else if (!empty($_SERVER['HTTP_HOST'])) {
238 $hostname = $_SERVER['HTTP_HOST'];
239 } else if (!empty($_ENV['HTTP_HOST'])) {
240 $hostname = $_ENV['HTTP_HOST'];
241 } else {
242 notify('Warning: could not find the name of this server!');
243 return false;
246 if (!empty($url['port'])) {
247 $hostname .= ':'.$url['port'];
248 } else if (!empty($_SERVER['SERVER_PORT'])) {
249 if ($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
250 $hostname .= ':'.$_SERVER['SERVER_PORT'];
254 if (isset($_SERVER['HTTPS'])) {
255 $protocol = ($_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
256 } else if (isset($_SERVER['SERVER_PORT'])) { # Apache2 does not export $_SERVER['HTTPS']
257 $protocol = ($_SERVER['SERVER_PORT'] == '443') ? 'https://' : 'http://';
258 } else {
259 $protocol = 'http://';
262 $url_prefix = $protocol.$hostname;
263 return $url_prefix . me();
267 * Determine if a web referer is valid
269 * Returns true if the referer is the same as the goodreferer. If
270 * the referer to test is not specified, use {@link qualified_me()}.
271 * If the admin has not set secure forms ($CFG->secureforms) then
272 * this function returns true regardless of a match.
274 * @uses $CFG
275 * @param string $goodreferer the url to compare to referer
276 * @return boolean
278 function match_referer($goodreferer = '') {
279 global $CFG;
281 if (empty($CFG->secureforms)) { // Don't bother checking referer
282 return true;
285 if ($goodreferer == 'nomatch') { // Don't bother checking referer
286 return true;
289 if (empty($goodreferer)) {
290 $goodreferer = qualified_me();
291 // try to remove everything after ? because POST url may contain GET parameters (SID rewrite, etc.)
292 $pos = strpos($goodreferer, '?');
293 if ($pos !== FALSE) {
294 $goodreferer = substr($goodreferer, 0, $pos);
298 $referer = get_referer();
300 return (($referer == $goodreferer) or ($referer == $CFG->wwwroot .'/') or ($referer == $CFG->wwwroot .'/index.php'));
304 * Determine if there is data waiting to be processed from a form
306 * Used on most forms in Moodle to check for data
307 * Returns the data as an object, if it's found.
308 * This object can be used in foreach loops without
309 * casting because it's cast to (array) automatically
311 * Checks that submitted POST data exists, and also
312 * checks the referer against the given url (it uses
313 * the current page if none was specified.
315 * @uses $CFG
316 * @param string $url the url to compare to referer for secure forms
317 * @return boolean
319 function data_submitted($url='') {
322 global $CFG;
324 if (empty($_POST)) {
325 return false;
327 } else {
328 if (match_referer($url)) {
329 return (object)$_POST;
330 } else {
331 if ($CFG->debug > 10) {
332 notice('The form did not come from this page! (referer = '. get_referer() .')');
334 return false;
340 * Moodle replacement for php stripslashes() function,
341 * works also for objects and arrays.
343 * The standard php stripslashes() removes ALL backslashes
344 * even from strings - so C:\temp becomes C:temp - this isn't good.
345 * This function should work as a fairly safe replacement
346 * to be called on quoted AND unquoted strings (to be sure)
348 * @param mixed something to remove unsafe slashes from
349 * @return mixed
351 function stripslashes_safe($mixed) {
352 // there is no need to remove slashes from int, float and bool types
353 if (empty($mixed)) {
354 //nothing to do...
355 } else if (is_string($mixed)) {
356 $mixed = str_replace("\\'", "'", $mixed);
357 $mixed = str_replace('\\"', '"', $mixed);
358 $mixed = str_replace('\\\\', '\\', $mixed);
359 } else if (is_array($mixed)) {
360 foreach ($mixed as $key => $value) {
361 $mixed[$key] = stripslashes_safe($value);
363 } else if (is_object($mixed)) {
364 $vars = get_object_vars($mixed);
365 foreach ($vars as $key => $value) {
366 $mixed->$key = stripslashes_safe($value);
370 return $mixed;
374 * Recursive implementation of stripslashes()
376 * This function will allow you to strip the slashes from a variable.
377 * If the variable is an array or object, slashes will be stripped
378 * from the items (or properties) it contains, even if they are arrays
379 * or objects themselves.
381 * @param mixed the variable to remove slashes from
382 * @return mixed
384 function stripslashes_recursive($var) {
385 if(is_object($var)) {
386 $properties = get_object_vars($var);
387 foreach($properties as $property => $value) {
388 $var->$property = stripslashes_recursive($value);
391 else if(is_array($var)) {
392 foreach($var as $property => $value) {
393 $var[$property] = stripslashes_recursive($value);
396 else if(is_string($var)) {
397 $var = stripslashes($var);
399 return $var;
403 * Given some normal text this function will break up any
404 * long words to a given size by inserting the given character
406 * It's multibyte savvy and doesn't change anything inside html tags.
408 * @param string $string the string to be modified
409 * @param int $maxsize maximum length of the string to be returned
410 * @param string $cutchar the string used to represent word breaks
411 * @return string
413 function break_up_long_words($string, $maxsize=20, $cutchar=' ') {
415 /// Loading the textlib singleton instance. We are going to need it.
416 $textlib = textlib_get_instance();
418 /// First of all, save all the tags inside the text to skip them
419 $tags = array();
420 filter_save_tags($string,$tags);
422 /// Process the string adding the cut when necessary
423 $output = '';
424 $length = $textlib->strlen($string, current_charset());
425 $wordlength = 0;
427 for ($i=0; $i<$length; $i++) {
428 $char = $textlib->substr($string, $i, 1, current_charset());
429 if ($char == ' ' or $char == "\t" or $char == "\n" or $char == "\r" or $char == "<" or $char == ">") {
430 $wordlength = 0;
431 } else {
432 $wordlength++;
433 if ($wordlength > $maxsize) {
434 $output .= $cutchar;
435 $wordlength = 0;
438 $output .= $char;
441 /// Finally load the tags back again
442 if (!empty($tags)) {
443 $output = str_replace(array_keys($tags), $tags, $output);
446 return $output;
450 * This does a search and replace, ignoring case
451 * This function is only used for versions of PHP older than version 5
452 * which do not have a native version of this function.
453 * Taken from the PHP manual, by bradhuizenga @ softhome.net
455 * @param string $find the string to search for
456 * @param string $replace the string to replace $find with
457 * @param string $string the string to search through
458 * return string
460 if (!function_exists('str_ireplace')) { /// Only exists in PHP 5
461 function str_ireplace($find, $replace, $string) {
463 if (!is_array($find)) {
464 $find = array($find);
467 if(!is_array($replace)) {
468 if (!is_array($find)) {
469 $replace = array($replace);
470 } else {
471 // this will duplicate the string into an array the size of $find
472 $c = count($find);
473 $rString = $replace;
474 unset($replace);
475 for ($i = 0; $i < $c; $i++) {
476 $replace[$i] = $rString;
481 foreach ($find as $fKey => $fItem) {
482 $between = explode(strtolower($fItem),strtolower($string));
483 $pos = 0;
484 foreach($between as $bKey => $bItem) {
485 $between[$bKey] = substr($string,$pos,strlen($bItem));
486 $pos += strlen($bItem) + strlen($fItem);
488 $string = implode($replace[$fKey],$between);
490 return ($string);
495 * Locate the position of a string in another string
497 * This function is only used for versions of PHP older than version 5
498 * which do not have a native version of this function.
499 * Taken from the PHP manual, by dmarsh @ spscc.ctc.edu
501 * @param string $haystack The string to be searched
502 * @param string $needle The string to search for
503 * @param int $offset The position in $haystack where the search should begin.
505 if (!function_exists('stripos')) { /// Only exists in PHP 5
506 function stripos($haystack, $needle, $offset=0) {
508 return strpos(strtoupper($haystack), strtoupper($needle), $offset);
513 * Load a template from file
515 * Returns a (big) string containing the contents of a template file with all
516 * the variables interpolated. all the variables must be in the $var[] array or
517 * object (whatever you decide to use).
519 * <b>WARNING: do not use this on big files!!</b>
521 * @param string $filename Location on the server's filesystem where template can be found.
522 * @param mixed $var Passed in by reference. An array or object which will be loaded with data from the template file.
524 function read_template($filename, &$var) {
526 $temp = str_replace("\\", "\\\\", implode(file($filename), ''));
527 $temp = str_replace('"', '\"', $temp);
528 eval("\$template = \"$temp\";");
529 return $template;
533 * Set a variable's value depending on whether or not it already has a value.
535 * If variable is set, set it to the set_value otherwise set it to the
536 * unset_value. used to handle checkboxes when you are expecting them from
537 * a form
539 * @param mixed $var Passed in by reference. The variable to check.
540 * @param mixed $set_value The value to set $var to if $var already has a value.
541 * @param mixed $unset_value The value to set $var to if $var does not already have a value.
543 function checked(&$var, $set_value = 1, $unset_value = 0) {
545 if (empty($var)) {
546 $var = $unset_value;
547 } else {
548 $var = $set_value;
553 * Prints the word "checked" if a variable is true, otherwise prints nothing,
554 * used for printing the word "checked" in a checkbox form element.
556 * @param boolean $var Variable to be checked for true value
557 * @param string $true_value Value to be printed if $var is true
558 * @param string $false_value Value to be printed if $var is false
560 function frmchecked(&$var, $true_value = 'checked', $false_value = '') {
562 if ($var) {
563 echo $true_value;
564 } else {
565 echo $false_value;
570 * This function will create a HTML link that will work on both
571 * Javascript and non-javascript browsers.
572 * Relies on the Javascript function openpopup in javascript.php
574 * $url must be relative to home page eg /mod/survey/stuff.php
575 * @param string $url Web link relative to home page
576 * @param string $name Name to be assigned to the popup window
577 * @param string $linkname Text to be displayed as web link
578 * @param int $height Height to assign to popup window
579 * @param int $width Height to assign to popup window
580 * @param string $title Text to be displayed as popup page title
581 * @param string $options List of additional options for popup window
582 * @todo Add code examples and list of some options that might be used.
583 * @param boolean $return Should the link to the popup window be returned as a string (true) or printed immediately (false)?
584 * @return string
585 * @uses $CFG
587 function link_to_popup_window ($url, $name='popup', $linkname='click here',
588 $height=400, $width=500, $title='Popup window', $options='none', $return=false) {
590 global $CFG;
592 if ($options == 'none') {
593 $options = 'menubar=0,location=0,scrollbars,resizable,width='. $width .',height='. $height;
595 $fullscreen = 0;
597 if (!(strpos($url,$CFG->wwwroot) === false)) { // some log url entries contain _SERVER[HTTP_REFERRER] in which case wwwroot is already there.
598 $url = substr($url, strlen($CFG->wwwroot));
601 $link = '<a target="'. $name .'" title="'. $title .'" href="'. $CFG->wwwroot . $url .'" '.
602 "onclick=\"return openpopup('$url', '$name', '$options', $fullscreen);\">$linkname</a>";
603 if ($return) {
604 return $link;
605 } else {
606 echo $link;
611 * This function will print a button submit form element
612 * that will work on both Javascript and non-javascript browsers.
613 * Relies on the Javascript function openpopup in javascript.php
615 * $url must be relative to home page eg /mod/survey/stuff.php
616 * @param string $url Web link relative to home page
617 * @param string $name Name to be assigned to the popup window
618 * @param string $linkname Text to be displayed as web link
619 * @param int $height Height to assign to popup window
620 * @param int $width Height to assign to popup window
621 * @param string $title Text to be displayed as popup page title
622 * @param string $options List of additional options for popup window
623 * @param string $return If true, return as a string, otherwise print
624 * @return string
625 * @uses $CFG
627 function button_to_popup_window ($url, $name='popup', $linkname='click here',
628 $height=400, $width=500, $title='Popup window', $options='none', $return=false,
629 $id='', $class='') {
631 global $CFG;
633 if ($options == 'none') {
634 $options = 'menubar=0,location=0,scrollbars,resizable,width='. $width .',height='. $height;
637 if ($id) {
638 $id = ' id="'.$id.'" ';
640 if ($class) {
641 $class = ' class="'.$class.'" ';
643 $fullscreen = 0;
645 $button = '<input type="button" name="'.$name.'" title="'. $title .'" value="'. $linkname .' ..." '.$id.$class.
646 "onclick=\"return openpopup('$url', '$name', '$options', $fullscreen);\" />\n";
647 if ($return) {
648 return $button;
649 } else {
650 echo $button;
656 * Prints a simple button to close a window
658 function close_window_button($name='closewindow') {
660 echo '<center>' . "\n";
661 echo '<script type="text/javascript">' . "\n";
662 echo '<!--' . "\n";
663 echo "document.write('<form>');\n";
664 echo "document.write('<input type=\"button\" onclick=\"self.close();\" value=\"".get_string("closewindow")."\" />');\n";
665 echo "document.write('<\/form>');\n";
666 echo '-->' . "\n";
667 echo '</script>' . "\n";
668 echo '<noscript>' . "\n";
669 print_string($name);
670 echo '</noscript>' . "\n";
671 echo '</center>' . "\n";
675 * Try and close the current window immediately using Javascript
677 function close_window($delay=0) {
679 <script type="text/javascript">
680 <!--
681 function close_this_window() {
682 self.close();
684 setTimeout("close_this_window()", <?php echo $delay * 1000 ?>);
686 </script>
687 <noscript><center>
688 <?php print_string('pleaseclose') ?>
689 </center></noscript>
690 <?php
691 die;
696 * Given an array of value, creates a popup menu to be part of a form
697 * $options["value"]["label"]
699 * @param type description
700 * @todo Finish documenting this function
702 function choose_from_menu ($options, $name, $selected='', $nothing='choose', $script='',
703 $nothingvalue='0', $return=false, $disabled=false, $tabindex=0) {
705 if ($nothing == 'choose') {
706 $nothing = get_string('choose') .'...';
709 $attributes = ($script) ? 'onchange="'. $script .'"' : '';
710 if ($disabled) {
711 $attributes .= ' disabled="disabled"';
714 if ($tabindex) {
715 $attributes .= ' tabindex="'.$tabindex.'"';
718 $output = '<select id="menu'.$name.'" name="'. $name .'" '. $attributes .'>' . "\n";
719 if ($nothing) {
720 $output .= ' <option value="'. $nothingvalue .'"'. "\n";
721 if ($nothingvalue === $selected) {
722 $output .= ' selected="selected"';
724 $output .= '>'. $nothing .'</option>' . "\n";
726 if (!empty($options)) {
727 foreach ($options as $value => $label) {
728 $output .= ' <option value="'. $value .'"';
729 if ((string)$value == (string)$selected) {
730 $output .= ' selected="selected"';
732 if ($label === '') {
733 $output .= '>'. $value .'</option>' . "\n";
734 } else {
735 $output .= '>'. $label .'</option>' . "\n";
739 $output .= '</select>' . "\n";
741 if ($return) {
742 return $output;
743 } else {
744 echo $output;
749 * Just like choose_from_menu, but takes a nested array (2 levels) and makes a dropdown menu
750 * including option headings with the first level.
752 function choose_from_menu_nested($options,$name,$selected='',$nothing='choose',$script = '',
753 $nothingvalue=0,$return=false,$disabled=false,$tabindex=0) {
755 if ($nothing == 'choose') {
756 $nothing = get_string('choose') .'...';
759 $attributes = ($script) ? 'onchange="'. $script .'"' : '';
760 if ($disabled) {
761 $attributes .= ' disabled="disabled"';
764 if ($tabindex) {
765 $attributes .= ' tabindex="'.$tabindex.'"';
768 $output = '<select id="menu'.$name.'" name="'. $name .'" '. $attributes .'>' . "\n";
769 if ($nothing) {
770 $output .= ' <option value="'. $nothingvalue .'"'. "\n";
771 if ($nothingvalue === $selected) {
772 $output .= ' selected="selected"';
774 $output .= '>'. $nothing .'</option>' . "\n";
776 if (!empty($options)) {
777 foreach ($options as $section => $values) {
778 $output .= ' <optgroup label="'.$section.'">'."\n";
779 foreach ($values as $value => $label) {
780 $output .= ' <option value="'. $value .'"';
781 if ((string)$value == (string)$selected) {
782 $output .= ' selected="selected"';
784 if ($label === '') {
785 $output .= '>'. $value .'</option>' . "\n";
786 } else {
787 $output .= '>'. $label .'</option>' . "\n";
790 $output .= ' </optgroup>'."\n";
793 $output .= '</select>' . "\n";
795 if ($return) {
796 return $output;
797 } else {
798 echo $output;
804 * Given an array of values, creates a group of radio buttons to be part of a form
806 * @param array $options An array of value-label pairs for the radio group (values as keys)
807 * @param string $name Name of the radiogroup (unique in the form)
808 * @param string $checked The value that is already checked
810 function choose_from_radio ($options, $name, $checked='') {
812 static $idcounter = 0;
814 if (!$name) {
815 $name = 'unnamed';
818 $output = '<span class="radiogroup '.$name."\">\n";
820 if (!empty($options)) {
821 $currentradio = 0;
822 foreach ($options as $value => $label) {
823 $htmlid = 'auto-rb'.sprintf('%04d', ++$idcounter);
824 $output .= ' <span class="radioelement '.$name.' rb'.$currentradio."\">";
825 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="radio" value="'.$value.'"';
826 if ($value == $checked) {
827 $output .= ' checked="checked"';
829 if ($label === '') {
830 $output .= ' /> <label for="'.$htmlid.'">'. $value .'</label></span>' . "\n";
831 } else {
832 $output .= ' /> <label for="'.$htmlid.'">'. $label .'</label></span>' . "\n";
834 $currentradio = ($currentradio + 1) % 2;
838 $output .= '</span>' . "\n";
840 echo $output;
843 /** Display an standard html checkbox with an optional label
845 * @param string $name The name of the checkbox
846 * @param string $value The valus that the checkbox will pass when checked
847 * @param boolean $checked The flag to tell the checkbox initial state
848 * @param string $label The label to be showed near the checkbox
849 * @param string $alt The info to be inserted in the alt tag
851 function print_checkbox ($name, $value, $checked = true, $label = '', $alt = '', $script='',$return=false) {
853 static $idcounter = 0;
855 if (!$name) {
856 $name = 'unnamed';
859 if (!$alt) {
860 $alt = 'checkbox';
863 if ($checked) {
864 $strchecked = ' checked="checked"';
865 } else {
866 $strchecked = '';
869 $htmlid = 'auto-cb'.sprintf('%04d', ++$idcounter);
870 $output = '<span class="checkbox '.$name."\">";
871 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="checkbox" value="'.$value.'" alt="'.$alt.'"'.$strchecked.' '.((!empty($script)) ? ' onClick="'.$script.'" ' : '').' />';
872 if(!empty($label)) {
873 $output .= ' <label for="'.$htmlid.'">'.$label.'</label>';
875 $output .= '</span>'."\n";
877 if (empty($return)) {
878 echo $output;
879 } else {
880 return $output;
885 /** Display an standard html text field with an optional label
887 * @param string $name The name of the text field
888 * @param string $value The value of the text field
889 * @param string $label The label to be showed near the text field
890 * @param string $alt The info to be inserted in the alt tag
892 function print_textfield ($name, $value, $alt = '',$size=50,$maxlength= 0,$return=false) {
894 static $idcounter = 0;
896 if (empty($name)) {
897 $name = 'unnamed';
900 if (empty($alt)) {
901 $alt = 'textfield';
904 if (!empty($maxlength)) {
905 $maxlength = ' maxlength="'.$maxlength.'" ';
908 $htmlid = 'auto-tf'.sprintf('%04d', ++$idcounter);
909 $output = '<span class="textfield '.$name."\">";
910 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="text" value="'.$value.'" size="'.$size.'" '.$maxlength.' alt="'.$alt.'" />';
912 $output .= '</span>'."\n";
914 if (empty($return)) {
915 echo $output;
916 } else {
917 return $output;
924 * Implements a complete little popup form
926 * @uses $CFG
927 * @param string $common The URL up to the point of the variable that changes
928 * @param array $options Alist of value-label pairs for the popup list
929 * @param string $formname Name must be unique on the page
930 * @param string $selected The option that is already selected
931 * @param string $nothing The label for the "no choice" option
932 * @param string $help The name of a help page if help is required
933 * @param string $helptext The name of the label for the help button
934 * @param boolean $return Indicates whether the function should return the text
935 * as a string or echo it directly to the page being rendered
936 * @param string $targetwindow The name of the target page to open the linked page in.
937 * @return string If $return is true then the entire form is returned as a string.
938 * @todo Finish documenting this function<br>
940 function popup_form($common, $options, $formname, $selected='', $nothing='choose', $help='', $helptext='', $return=false, $targetwindow='self') {
942 global $CFG;
943 static $go, $choose; /// Locally cached, in case there's lots on a page
945 if (empty($options)) {
946 return '';
949 if (!isset($go)) {
950 $go = get_string('go');
953 if ($nothing == 'choose') {
954 if (!isset($choose)) {
955 $choose = get_string('choose');
957 $nothing = $choose.'...';
960 $startoutput = '<form action="'.$CFG->wwwroot.'/course/jumpto.php"'.
961 ' method="get"'.
962 ' target="'.$CFG->framename.'"'.
963 ' name="'.$formname.'"'.
964 ' class="popupform">';
966 $output = '<select name="jump" onchange="'.$targetwindow.'.location=document.'.$formname.
967 '.jump.options[document.'.$formname.'.jump.selectedIndex].value;">'."\n";
969 if ($nothing != '') {
970 $output .= " <option value=\"javascript:void(0)\">$nothing</option>\n";
973 $inoptgroup = false;
974 foreach ($options as $value => $label) {
976 if (substr($label,0,2) == '--') { /// we are starting a new optgroup
978 /// Check to see if we already have a valid open optgroup
979 /// XHTML demands that there be at least 1 option within an optgroup
980 if ($inoptgroup and (count($optgr) > 1) ) {
981 $output .= implode('', $optgr);
982 $output .= ' </optgroup>';
985 unset($optgr);
986 $optgr = array();
988 $optgr[] = ' <optgroup label="'. substr($label,2) .'">'; // Plain labels
990 $inoptgroup = true; /// everything following will be in an optgroup
991 continue;
993 } else {
994 if (!empty($CFG->usesid) && !isset($_COOKIE[session_name()]))
996 $url=sid_process_url( $common . $value );
997 } else
999 $url=$common . $value;
1001 $optstr = ' <option value="' . $url . '"';
1003 if ($value == $selected) {
1004 $optstr .= ' selected="selected"';
1007 if ($label) {
1008 $optstr .= '>'. $label .'</option>' . "\n";
1009 } else {
1010 $optstr .= '>'. $value .'</option>' . "\n";
1013 if ($inoptgroup) {
1014 $optgr[] = $optstr;
1015 } else {
1016 $output .= $optstr;
1022 /// catch the final group if not closed
1023 if ($inoptgroup and count($optgr) > 1) {
1024 $output .= implode('', $optgr);
1025 $output .= ' </optgroup>';
1028 $output .= '</select>';
1029 $output .= '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
1030 $output .= '<noscript id="noscript'.$formname.'" style="display: inline;">';
1031 $output .= '<input type="submit" value="'.$go.'" /></noscript>';
1032 $output .= '<script type="text/javascript">'.
1033 "\n<!--\n".
1034 'document.getElementById("noscript'.$formname.'").style.display = "none";'.
1035 "\n-->\n".'</script>';
1036 $output .= '</form>' . "\n";
1038 if ($help) {
1039 $button = helpbutton($help, $helptext, 'moodle', true, false, '', true);
1040 } else {
1041 $button = '';
1044 if ($return) {
1045 return $startoutput.$button.$output;
1046 } else {
1047 echo $startoutput.$button.$output;
1053 * Prints some red text
1055 * @param string $error The text to be displayed in red
1057 function formerr($error) {
1059 if (!empty($error)) {
1060 echo '<font color="#ff0000">'. $error .'</font>';
1065 * Validates an email to make sure it makes sense.
1067 * @param string $address The email address to validate.
1068 * @return boolean
1070 function validate_email($address) {
1072 return (ereg('^[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+'.
1073 '(\.[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+)*'.
1074 '@'.
1075 '[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.
1076 '[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$',
1077 $address));
1081 * Extracts file argument either from file parameter or PATH_INFO
1083 * @param string $scriptname name of the calling script
1084 * @return string file path (only safe characters)
1086 function get_file_argument($scriptname) {
1087 global $_SERVER;
1089 $relativepath = FALSE;
1091 // first try normal parameter (compatible method == no relative links!)
1092 $relativepath = optional_param('file', FALSE, PARAM_PATH);
1093 if ($relativepath === '/testslasharguments') {
1094 echo 'test -1 : Incorrect use - try "file.php/testslasharguments" instead'; //indicate fopen/fread works for health center
1095 die;
1098 // then try extract file from PATH_INFO (slasharguments method)
1099 if (!$relativepath and !empty($_SERVER['PATH_INFO'])) {
1100 $path_info = $_SERVER['PATH_INFO'];
1101 // check that PATH_INFO works == must not contain the script name
1102 if (!strpos($path_info, $scriptname)) {
1103 $relativepath = clean_param(rawurldecode($path_info), PARAM_PATH);
1104 if ($relativepath === '/testslasharguments') {
1105 echo 'test 1 : Slasharguments test passed. Server confguration is compatible with file.php/1/pic.jpg slashargument setting.'; //indicate ok for health center
1106 die;
1111 // now if both fail try the old way
1112 // (for compatibility with misconfigured or older buggy php implementations)
1113 if (!$relativepath) {
1114 $arr = explode($scriptname, me());
1115 if (!empty($arr[1])) {
1116 $path_info = strip_querystring($arr[1]);
1117 $relativepath = clean_param(rawurldecode($path_info), PARAM_PATH);
1118 if ($relativepath === '/testslasharguments') {
1119 echo 'test 2 : Slasharguments test passed (compatibility hack). Server confguration may be compatible with file.php/1/pic.jpg slashargument setting'; //indicate ok for health center
1120 die;
1125 return $relativepath;
1129 * Check for bad characters ?
1131 * @param string $string ?
1132 * @param int $allowdots ?
1133 * @todo Finish documenting this function - more detail needed in description as well as details on arguments
1135 function detect_munged_arguments($string, $allowdots=1) {
1136 if (substr_count($string, '..') > $allowdots) { // Sometimes we allow dots in references
1137 return true;
1139 if (ereg('[\|\`]', $string)) { // check for other bad characters
1140 return true;
1142 if (empty($string) or $string == '/') {
1143 return true;
1146 return false;
1150 * Searches the current environment variables for some slash arguments
1152 * @param string $file ?
1153 * @todo Finish documenting this function
1155 function get_slash_arguments($file='file.php') {
1157 if (!$string = me()) {
1158 return false;
1161 $pathinfo = explode($file, $string);
1163 if (!empty($pathinfo[1])) {
1164 return addslashes($pathinfo[1]);
1165 } else {
1166 return false;
1171 * Extracts arguments from "/foo/bar/something"
1172 * eg http://mysite.com/script.php/foo/bar/something
1174 * @param string $string ?
1175 * @param int $i ?
1176 * @return array|string
1177 * @todo Finish documenting this function
1179 function parse_slash_arguments($string, $i=0) {
1181 if (detect_munged_arguments($string)) {
1182 return false;
1184 $args = explode('/', $string);
1186 if ($i) { // return just the required argument
1187 return $args[$i];
1189 } else { // return the whole array
1190 array_shift($args); // get rid of the empty first one
1191 return $args;
1196 * Just returns an array of text formats suitable for a popup menu
1198 * @uses FORMAT_MOODLE
1199 * @uses FORMAT_HTML
1200 * @uses FORMAT_PLAIN
1201 * @uses FORMAT_MARKDOWN
1202 * @return array
1204 function format_text_menu() {
1206 return array (FORMAT_MOODLE => get_string('formattext'),
1207 FORMAT_HTML => get_string('formathtml'),
1208 FORMAT_PLAIN => get_string('formatplain'),
1209 FORMAT_MARKDOWN => get_string('formatmarkdown'));
1213 * Given text in a variety of format codings, this function returns
1214 * the text as safe HTML.
1216 * @uses $CFG
1217 * @uses FORMAT_MOODLE
1218 * @uses FORMAT_HTML
1219 * @uses FORMAT_PLAIN
1220 * @uses FORMAT_WIKI
1221 * @uses FORMAT_MARKDOWN
1222 * @param string $text The text to be formatted. This is raw text originally from user input.
1223 * @param int $format Identifier of the text format to be used
1224 * (FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN)
1225 * @param array $options ?
1226 * @param int $courseid ?
1227 * @return string
1228 * @todo Finish documenting this function
1230 function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL ) {
1232 global $CFG, $course;
1234 if (!isset($options->noclean)) {
1235 $options->noclean=false;
1237 if (!isset($options->smiley)) {
1238 $options->smiley=true;
1240 if (!isset($options->filter)) {
1241 $options->filter=true;
1243 if (!isset($options->para)) {
1244 $options->para=true;
1246 if (!isset($options->newlines)) {
1247 $options->newlines=true;
1250 if (empty($courseid)) {
1251 if (!empty($course->id)) { // An ugly hack for better compatibility
1252 $courseid = $course->id;
1256 if (!empty($CFG->cachetext)) {
1257 $time = time() - $CFG->cachetext;
1258 $md5key = md5($text.'-'.$courseid.$options->noclean.$options->smiley.$options->filter.$options->para.$options->newlines.$format.current_language().$courseid);
1259 if ($oldcacheitem = get_record_sql('SELECT * FROM '.$CFG->prefix.'cache_text WHERE md5key = \''.$md5key.'\'', true)) {
1260 if ($oldcacheitem->timemodified >= $time) {
1261 return $oldcacheitem->formattedtext;
1266 $CFG->currenttextiscacheable = true; // Default status - can be changed by any filter
1268 switch ($format) {
1269 case FORMAT_HTML:
1270 if (!empty($options->smiley)) {
1271 replace_smilies($text);
1273 if (empty($options->noclean)) {
1274 $text = clean_text($text, $format);
1276 if (!empty($options->filter)) {
1277 $text = filter_text($text, $courseid);
1279 break;
1281 case FORMAT_PLAIN:
1282 $text = s($text);
1283 $text = rebuildnolinktag($text);
1284 $text = str_replace(' ', '&nbsp; ', $text);
1285 $text = nl2br($text);
1286 break;
1288 case FORMAT_WIKI:
1289 // this format is deprecated
1290 $text = '<p>NOTICE: Wiki-like formatting has been removed from Moodle. You should not be seeing
1291 this message as all texts should have been converted to Markdown format instead.
1292 Please post a bug report to http://moodle.org/bugs with information about where you
1293 saw this message.</p>'.s($text);
1294 break;
1296 case FORMAT_MARKDOWN:
1297 $text = markdown_to_html($text);
1298 if (!empty($options->smiley)) {
1299 replace_smilies($text);
1301 if (empty($options->noclean)) {
1302 $text = clean_text($text, $format);
1305 if (!empty($options->filter)) {
1306 $text = filter_text($text, $courseid);
1308 break;
1310 default: // FORMAT_MOODLE or anything else
1311 $text = text_to_html($text, $options->smiley, $options->para, $options->newlines);
1312 if (empty($options->noclean)) {
1313 $text = clean_text($text, $format);
1316 if (!empty($options->filter)) {
1317 $text = filter_text($text, $courseid);
1319 break;
1322 if (!empty($CFG->cachetext) and $CFG->currenttextiscacheable) {
1323 $newcacheitem->md5key = $md5key;
1324 $newcacheitem->formattedtext = addslashes($text);
1325 $newcacheitem->timemodified = time();
1326 if ($oldcacheitem) { // See bug 4677 for discussion
1327 $newcacheitem->id = $oldcacheitem->id;
1328 @update_record('cache_text', $newcacheitem); // Update existing record in the cache table
1329 // It's unlikely that the cron cache cleaner could have
1330 // deleted this entry in the meantime, as it allows
1331 // some extra time to cover these cases.
1332 } else {
1333 @insert_record('cache_text', $newcacheitem); // Insert a new record in the cache table
1334 // Again, it's possible that another user has caused this
1335 // record to be created already in the time that it took
1336 // to traverse this function. That's OK too, as the
1337 // call above handles duplicate entries, and eventually
1338 // the cron cleaner will delete them.
1342 return $text;
1345 /** Converts the text format from the value to the 'internal'
1346 * name or vice versa. $key can either be the value or the name
1347 * and you get the other back.
1349 * @param mixed int 0-4 or string one of 'moodle','html','plain','markdown'
1350 * @return mixed as above but the other way around!
1352 function text_format_name( $key ) {
1353 $lookup = array();
1354 $lookup[FORMAT_MOODLE] = 'moodle';
1355 $lookup[FORMAT_HTML] = 'html';
1356 $lookup[FORMAT_PLAIN] = 'plain';
1357 $lookup[FORMAT_MARKDOWN] = 'markdown';
1358 $value = "error";
1359 if (!is_numeric($key)) {
1360 $key = strtolower( $key );
1361 $value = array_search( $key, $lookup );
1363 else {
1364 if (isset( $lookup[$key] )) {
1365 $value = $lookup[ $key ];
1368 return $value;
1371 /** Given a simple string, this function returns the string
1372 * processed by enabled filters if $CFG->filterall is enabled
1374 * @param string $string The string to be filtered.
1375 * @param boolean $striplinks To strip any link in the result text.
1376 * @param int $courseid Current course as filters can, potentially, use it
1377 * @return string
1379 function format_string ($string, $striplinks = false, $courseid=NULL ) {
1381 global $CFG, $course;
1383 //We'll use a in-memory cache here to speed up repeated strings
1384 static $strcache;
1386 //Calculate md5
1387 $md5 = md5($string.'<+>'.$striplinks);
1389 //Fetch from cache if possible
1390 if(isset($strcache[$md5])) {
1391 return $strcache[$md5];
1394 if (empty($courseid)) {
1395 if (!empty($course->id)) { // An ugly hack for better compatibility
1396 $courseid = $course->id; // (copied from format_text)
1400 if (!empty($CFG->filterall)) {
1401 $string = filter_text($string, $courseid);
1404 if ($striplinks) { //strip links in string
1405 $string = preg_replace('/(<a[^>]+?>)(.+?)(<\/a>)/is','$2',$string);
1408 //Store to cache
1409 $strcache[$md5] = $string;
1411 return $string;
1415 * Given text in a variety of format codings, this function returns
1416 * the text as plain text suitable for plain email.
1418 * @uses FORMAT_MOODLE
1419 * @uses FORMAT_HTML
1420 * @uses FORMAT_PLAIN
1421 * @uses FORMAT_WIKI
1422 * @uses FORMAT_MARKDOWN
1423 * @param string $text The text to be formatted. This is raw text originally from user input.
1424 * @param int $format Identifier of the text format to be used
1425 * (FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN)
1426 * @return string
1428 function format_text_email($text, $format) {
1430 switch ($format) {
1432 case FORMAT_PLAIN:
1433 return $text;
1434 break;
1436 case FORMAT_WIKI:
1437 $text = wiki_to_html($text);
1438 /// This expression turns links into something nice in a text format. (Russell Jungwirth)
1439 /// From: http://php.net/manual/en/function.eregi-replace.php and simplified
1440 $text = eregi_replace('(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)','\\3 [ \\2 ]', $text);
1441 return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
1442 break;
1444 case FORMAT_HTML:
1445 return html_to_text($text);
1446 break;
1448 case FORMAT_MOODLE:
1449 case FORMAT_MARKDOWN:
1450 default:
1451 $text = eregi_replace('(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)','\\3 [ \\2 ]', $text);
1452 return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES)));
1453 break;
1458 * Given some text in HTML format, this function will pass it
1459 * through any filters that have been defined in $CFG->textfilterx
1460 * The variable defines a filepath to a file containing the
1461 * filter function. The file must contain a variable called
1462 * $textfilter_function which contains the name of the function
1463 * with $courseid and $text parameters
1465 * @param string $text The text to be passed through format filters
1466 * @param int $courseid ?
1467 * @return string
1468 * @todo Finish documenting this function
1470 function filter_text($text, $courseid=NULL) {
1472 global $CFG;
1474 require_once($CFG->libdir.'/filterlib.php');
1475 if (!empty($CFG->textfilters)) {
1476 $textfilters = explode(',', $CFG->textfilters);
1477 foreach ($textfilters as $textfilter) {
1478 if (is_readable($CFG->dirroot .'/'. $textfilter .'/filter.php')) {
1479 include_once($CFG->dirroot .'/'. $textfilter .'/filter.php');
1480 $functionname = basename($textfilter).'_filter';
1481 if (function_exists($functionname)) {
1482 $text = $functionname($courseid, $text);
1488 /// <nolink> tags removed for XHTML compatibility
1489 $text = str_replace('<nolink>', '', $text);
1490 $text = str_replace('</nolink>', '', $text);
1492 return $text;
1496 * Given raw text (eg typed in by a user), this function cleans it up
1497 * and removes any nasty tags that could mess up Moodle pages.
1499 * @uses FORMAT_MOODLE
1500 * @uses FORMAT_PLAIN
1501 * @uses ALLOWED_TAGS
1502 * @param string $text The text to be cleaned
1503 * @param int $format Identifier of the text format to be used
1504 * (FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN)
1505 * @return string The cleaned up text
1507 function clean_text($text, $format=FORMAT_MOODLE) {
1509 global $ALLOWED_TAGS;
1511 switch ($format) {
1512 case FORMAT_PLAIN:
1513 return $text;
1515 default:
1517 /// Fix non standard entity notations
1518 $text = preg_replace('/(&#[0-9]+)(;?)/', "\\1;", $text);
1519 $text = preg_replace('/(&#x[0-9a-fA-F]+)(;?)/', "\\1;", $text);
1521 /// Remove tags that are not allowed
1522 $text = strip_tags($text, $ALLOWED_TAGS);
1524 /// Clean up embedded scripts and , using kses
1525 $text = cleanAttributes($text);
1527 /// Remove script events
1528 $text = eregi_replace("([^a-z])language([[:space:]]*)=", "\\1Xlanguage=", $text);
1529 $text = eregi_replace("([^a-z])on([a-z]+)([[:space:]]*)=", "\\1Xon\\2=", $text);
1531 return $text;
1536 * This function takes a string and examines it for HTML tags.
1537 * If tags are detected it passes the string to a helper function {@link cleanAttributes2()}
1538 * which checks for attributes and filters them for malicious content
1539 * 17/08/2004 :: Eamon DOT Costello AT dcu DOT ie
1541 * @param string $str The string to be examined for html tags
1542 * @return string
1544 function cleanAttributes($str){
1545 $result = preg_replace_callback(
1546 '%(<[^>]*(>|$)|>)%m', #search for html tags
1547 "cleanAttributes2",
1548 $str
1550 return $result;
1554 * This function takes a string with an html tag and strips out any unallowed
1555 * protocols e.g. javascript:
1556 * It calls ancillary functions in kses which are prefixed by kses
1557 * 17/08/2004 :: Eamon DOT Costello AT dcu DOT ie
1559 * @param array $htmlArray An array from {@link cleanAttributes()}, containing in its 1st
1560 * element the html to be cleared
1561 * @return string
1563 function cleanAttributes2($htmlArray){
1565 global $CFG, $ALLOWED_PROTOCOLS;
1566 require_once($CFG->libdir .'/kses.php');
1568 $htmlTag = $htmlArray[1];
1569 if (substr($htmlTag, 0, 1) != '<') {
1570 return '&gt;'; //a single character ">" detected
1572 if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $htmlTag, $matches)) {
1573 return ''; // It's seriously malformed
1575 $slash = trim($matches[1]); //trailing xhtml slash
1576 $elem = $matches[2]; //the element name
1577 $attrlist = $matches[3]; // the list of attributes as a string
1579 $attrArray = kses_hair($attrlist, $ALLOWED_PROTOCOLS);
1581 $attStr = '';
1582 foreach ($attrArray as $arreach) {
1583 $arreach['name'] = strtolower($arreach['name']);
1584 if ($arreach['name'] == 'style') {
1585 $value = $arreach['value'];
1586 while (true) {
1587 $prevvalue = $value;
1588 $value = kses_no_null($value);
1589 $value = preg_replace("/\/\*.*\*\//Us", '', $value);
1590 $value = kses_decode_entities($value);
1591 $value = preg_replace('/(&#[0-9]+)(;?)/', "\\1;", $value);
1592 $value = preg_replace('/(&#x[0-9a-fA-F]+)(;?)/', "\\1;", $value);
1593 if ($value === $prevvalue) {
1594 $arreach['value'] = $value;
1595 break;
1598 $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']);
1599 $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']);
1600 } else if ($arreach['name'] == 'href') {
1601 //Adobe Acrobat Reader XSS protection
1602 $arreach['value'] = preg_replace('/(\.(pdf|fdf|xfdf|xdp|xfd))[^a-z0-9_\.\-].*$/i', '$1', $arreach['value']);
1604 $attStr .= ' '.$arreach['name'].'="'.$arreach['value'].'" ';
1607 // Remove last space from attribute list
1608 $attStr = rtrim($attStr);
1610 $xhtml_slash = '';
1611 if (preg_match('%/\s*$%', $attrlist)) {
1612 $xhtml_slash = ' /';
1614 return '<'. $slash . $elem . $attStr . $xhtml_slash .'>';
1618 * Replaces all known smileys in the text with image equivalents
1620 * @uses $CFG
1621 * @param string $text Passed by reference. The string to search for smily strings.
1622 * @return string
1624 function replace_smilies(&$text) {
1626 global $CFG;
1628 /// this builds the mapping array only once
1629 static $runonce = false;
1630 static $e = array();
1631 static $img = array();
1632 static $emoticons = array(
1633 ':-)' => 'smiley',
1634 ':)' => 'smiley',
1635 ':-D' => 'biggrin',
1636 ';-)' => 'wink',
1637 ':-/' => 'mixed',
1638 'V-.' => 'thoughtful',
1639 ':-P' => 'tongueout',
1640 'B-)' => 'cool',
1641 '^-)' => 'approve',
1642 '8-)' => 'wideeyes',
1643 ':o)' => 'clown',
1644 ':-(' => 'sad',
1645 ':(' => 'sad',
1646 '8-.' => 'shy',
1647 ':-I' => 'blush',
1648 ':-X' => 'kiss',
1649 '8-o' => 'surprise',
1650 'P-|' => 'blackeye',
1651 '8-[' => 'angry',
1652 'xx-P' => 'dead',
1653 '|-.' => 'sleepy',
1654 '}-]' => 'evil',
1657 if ($runonce == false) { /// After the first time this is not run again
1658 foreach ($emoticons as $emoticon => $image){
1659 $alttext = get_string($image, 'pix');
1661 $e[] = $emoticon;
1662 $img[] = '<img alt="'. $alttext .'" width="15" height="15" src="'. $CFG->pixpath .'/s/'. $image .'.gif" />';
1664 $runonce = true;
1667 // Exclude from transformations all the code inside <script> tags
1668 // Needed to solve Bug 1185. Thanks to jouse 2001 detecting it. :-)
1669 // Based on code from glossary fiter by Williams Castillo.
1670 // - Eloy
1672 // Detect all the <script> zones to take out
1673 $excludes = array();
1674 preg_match_all('/<script language(.+?)<\/script>/is',$text,$list_of_excludes);
1676 // Take out all the <script> zones from text
1677 foreach (array_unique($list_of_excludes[0]) as $key=>$value) {
1678 $excludes['<+'.$key.'+>'] = $value;
1680 if ($excludes) {
1681 $text = str_replace($excludes,array_keys($excludes),$text);
1684 /// this is the meat of the code - this is run every time
1685 $text = str_replace($e, $img, $text);
1687 // Recover all the <script> zones to text
1688 if ($excludes) {
1689 $text = str_replace(array_keys($excludes),$excludes,$text);
1694 * Given plain text, makes it into HTML as nicely as possible.
1695 * May contain HTML tags already
1697 * @uses $CFG
1698 * @param string $text The string to convert.
1699 * @param boolean $smiley Convert any smiley characters to smiley images?
1700 * @param boolean $para If true then the returned string will be wrapped in paragraph tags
1701 * @param boolean $newlines If true then lines newline breaks will be converted to HTML newline breaks.
1702 * @return string
1705 function text_to_html($text, $smiley=true, $para=true, $newlines=true) {
1708 global $CFG;
1710 /// Remove any whitespace that may be between HTML tags
1711 $text = eregi_replace(">([[:space:]]+)<", "><", $text);
1713 /// Remove any returns that precede or follow HTML tags
1714 $text = eregi_replace("([\n\r])<", " <", $text);
1715 $text = eregi_replace(">([\n\r])", "> ", $text);
1717 convert_urls_into_links($text);
1719 /// Make returns into HTML newlines.
1720 if ($newlines) {
1721 $text = nl2br($text);
1724 /// Turn smileys into images.
1725 if ($smiley) {
1726 replace_smilies($text);
1729 /// Wrap the whole thing in a paragraph tag if required
1730 if ($para) {
1731 return '<p>'.$text.'</p>';
1732 } else {
1733 return $text;
1738 * Given Markdown formatted text, make it into XHTML using external function
1740 * @uses $CFG
1741 * @param string $text The markdown formatted text to be converted.
1742 * @return string Converted text
1744 function markdown_to_html($text) {
1745 global $CFG;
1747 require_once($CFG->libdir .'/markdown.php');
1749 return Markdown($text);
1753 * Given HTML text, make it into plain text using external function
1755 * @uses $CFG
1756 * @param string $html The text to be converted.
1757 * @return string
1759 function html_to_text($html) {
1761 global $CFG;
1763 require_once($CFG->libdir .'/html2text.php');
1765 return html2text($html);
1769 * Given some text this function converts any URLs it finds into HTML links
1771 * @param string $text Passed in by reference. The string to be searched for urls.
1773 function convert_urls_into_links(&$text) {
1774 /// Make lone URLs into links. eg http://moodle.com/
1775 $text = eregi_replace("([[:space:]]|^|\(|\[)([[:alnum:]]+)://([^[:space:]]*)([[:alnum:]#?/&=])",
1776 "\\1<a href=\"\\2://\\3\\4\" target=\"_blank\">\\2://\\3\\4</a>", $text);
1778 /// eg www.moodle.com
1779 $text = eregi_replace("([[:space:]]|^|\(|\[)www\.([^[:space:]]*)([[:alnum:]#?/&=])",
1780 "\\1<a href=\"http://www.\\2\\3\" target=\"_blank\">www.\\2\\3</a>", $text);
1784 * This function will highlight search words in a given string
1785 * It cares about HTML and will not ruin links. It's best to use
1786 * this function after performing any conversions to HTML.
1787 * Function found here: http://forums.devshed.com/t67822/scdaa2d1c3d4bacb4671d075ad41f0854.html
1789 * @param string $needle The string to search for
1790 * @param string $haystack The string to search for $needle in
1791 * @param int $case ?
1792 * @return string
1793 * @todo Finish documenting this function
1795 function highlight($needle, $haystack, $case=0,
1796 $left_string='<span class="highlight">', $right_string='</span>') {
1797 if (empty($needle)) {
1798 return $haystack;
1801 //$list_of_words = eregi_replace("[^-a-zA-Z0-9&.']", " ", $needle); // bug 3101
1802 $list_of_words = $needle;
1803 $list_array = explode(' ', $list_of_words);
1804 for ($i=0; $i<sizeof($list_array); $i++) {
1805 if (strlen($list_array[$i]) == 1) {
1806 $list_array[$i] = '';
1809 $list_of_words = implode(' ', $list_array);
1810 $list_of_words_cp = $list_of_words;
1811 $final = array();
1812 preg_match_all('/<(.+?)>/is',$haystack,$list_of_words);
1814 foreach (array_unique($list_of_words[0]) as $key=>$value) {
1815 $final['<|'.$key.'|>'] = $value;
1818 $haystack = str_replace($final,array_keys($final),$haystack);
1819 $list_of_words_cp = eregi_replace(' +', '|', $list_of_words_cp);
1821 if ($list_of_words_cp{0}=='|') {
1822 $list_of_words_cp{0} = '';
1824 if ($list_of_words_cp{strlen($list_of_words_cp)-1}=='|') {
1825 $list_of_words_cp{strlen($list_of_words_cp)-1}='';
1828 $list_of_words_cp = trim($list_of_words_cp);
1830 if ($list_of_words_cp) {
1832 $list_of_words_cp = "(". $list_of_words_cp .")";
1834 if (!$case){
1835 $haystack = eregi_replace("$list_of_words_cp", "$left_string"."\\1"."$right_string", $haystack);
1836 } else {
1837 $haystack = ereg_replace("$list_of_words_cp", "$left_string"."\\1"."$right_string", $haystack);
1840 $haystack = str_replace(array_keys($final),$final,$haystack);
1842 return $haystack;
1846 * This function will highlight instances of $needle in $haystack
1847 * It's faster that the above function and doesn't care about
1848 * HTML or anything.
1850 * @param string $needle The string to search for
1851 * @param string $haystack The string to search for $needle in
1852 * @return string
1854 function highlightfast($needle, $haystack) {
1856 $parts = explode(strtolower($needle), strtolower($haystack));
1858 $pos = 0;
1860 foreach ($parts as $key => $part) {
1861 $parts[$key] = substr($haystack, $pos, strlen($part));
1862 $pos += strlen($part);
1864 $parts[$key] .= '<span class="highlight">'.substr($haystack, $pos, strlen($needle)).'</span>';
1865 $pos += strlen($needle);
1868 return (join('', $parts));
1872 /// STANDARD WEB PAGE PARTS ///////////////////////////////////////////////////
1875 * Print a standard header
1877 * @uses $USER
1878 * @uses $CFG
1879 * @uses $SESSION
1880 * @param string $title Appears at the top of the window
1881 * @param string $heading Appears at the top of the page
1882 * @param string $navigation Premade navigation string (for use as breadcrumbs links)
1883 * @param string $focus Indicates form element to get cursor focus on load eg inputform.password
1884 * @param string $meta Meta tags to be added to the header
1885 * @param boolean $cache Should this page be cacheable?
1886 * @param string $button HTML code for a button (usually for module editing)
1887 * @param string $menu HTML code for a popup menu
1888 * @param boolean $usexml use XML for this page
1889 * @param string $bodytags This text will be included verbatim in the <body> tag (useful for onload() etc)
1891 function print_header ($title='', $heading='', $navigation='', $focus='', $meta='',
1892 $cache=true, $button='&nbsp;', $menu='', $usexml=false, $bodytags='') {
1894 global $USER, $CFG, $THEME, $SESSION, $ME, $SITE, $HTTPSPAGEREQUIRED;
1896 /// This makes sure that the header is never repeated twice on a page
1897 if (defined('HEADER_PRINTED')) {
1898 if ($CFG->debug > 7) {
1899 notify('print_header() was called more than once - this should not happen. Please check the code for this page closely. Note: error() and redirect() are now safe to call after print_header().');
1901 return;
1903 define('HEADER_PRINTED', 'true');
1906 global $course, $COURSE;
1907 if (!empty($COURSE->lang)) {
1908 $CFG->courselang = $COURSE->lang;
1909 moodle_setlocale();
1910 } else if (!empty($course->lang)) { // ugly backwards compatibility hack
1911 $CFG->courselang = $course->lang;
1912 moodle_setlocale();
1914 if (!empty($COURSE->theme)) {
1915 if (!empty($CFG->allowcoursethemes)) {
1916 $CFG->coursetheme = $COURSE->theme;
1917 theme_setup();
1919 } else if (!empty($course->theme)) { // ugly backwards compatibility hack
1920 if (!empty($CFG->allowcoursethemes)) {
1921 $CFG->coursetheme = $course->theme;
1922 theme_setup();
1926 /// We have to change some URLs in styles if we are in a $HTTPSPAGEREQUIRED page
1927 if (!empty($HTTPSPAGEREQUIRED)) {
1928 $CFG->themewww = str_replace('http:', 'https:', $CFG->themewww);
1929 $CFG->pixpath = str_replace('http:', 'https:', $CFG->pixpath);
1930 $CFG->modpixpath = str_replace('http:', 'https:', $CFG->modpixpath);
1931 foreach ($CFG->stylesheets as $key => $stylesheet) {
1932 $CFG->stylesheets[$key] = str_replace('http:', 'https:', $stylesheet);
1936 /// Add the required stylesheets
1937 $stylesheetshtml = '';
1938 foreach ($CFG->stylesheets as $stylesheet) {
1939 $stylesheetshtml .= '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'" />'."\n";
1941 $meta = $stylesheetshtml.$meta;
1944 if ($navigation == 'home') {
1945 $home = true;
1946 $navigation = '';
1947 } else {
1948 $home = false;
1951 /// This is another ugly hack to make navigation elements available to print_footer later
1952 $THEME->title = $title;
1953 $THEME->heading = $heading;
1954 $THEME->navigation = $navigation;
1955 $THEME->button = $button;
1956 $THEME->menu = $menu;
1957 $navmenulist = isset($THEME->navmenulist) ? $THEME->navmenulist : '';
1959 if ($button == '') {
1960 $button = '&nbsp;';
1963 if (!$menu and $navigation) {
1964 if (empty($CFG->loginhttps)) {
1965 $wwwroot = $CFG->wwwroot;
1966 } else {
1967 $wwwroot = str_replace('http:','https:',$CFG->wwwroot);
1969 if (isset($course->id)) {
1970 $menu = user_login_string($course);
1971 } else {
1972 $menu = user_login_string($SITE);
1976 if (isset($SESSION->justloggedin)) {
1977 unset($SESSION->justloggedin);
1978 if (!empty($CFG->displayloginfailures)) {
1979 if (!empty($USER->username) and !isguest()) {
1980 if ($count = count_login_failures($CFG->displayloginfailures, $USER->username, $USER->lastlogin)) {
1981 $menu .= '&nbsp;<font size="1">';
1982 if (empty($count->accounts)) {
1983 $menu .= get_string('failedloginattempts', '', $count);
1984 } else {
1985 $menu .= get_string('failedloginattemptsall', '', $count);
1987 if (isadmin()) {
1988 $menu .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php'.
1989 '?chooselog=1&amp;id=1&amp;modid=site_errors">'.get_string('logs').'</a>)';
1991 $menu .= '</font>';
1998 $encoding = current_charset();
2000 $meta = '<meta http-equiv="content-type" content="text/html; charset='. $encoding .'" />'. "\n". $meta ."\n";
2001 if (!$usexml) {
2002 @header('Content-type: text/html; charset='.$encoding);
2005 if ( get_string('thisdirection') == 'rtl' ) {
2006 $direction = ' dir="rtl"';
2007 } else {
2008 $direction = ' dir="ltr"';
2010 //Accessibility: added the 'lang' attribute to $direction, used in theme <html> tag.
2011 $language = str_replace('_utf8','',$CFG->lang);
2012 $direction .= ' lang="'.$language.'" xml:lang="'.$language.'"';
2014 if ($cache) { // Allow caching on "back" (but not on normal clicks)
2015 @header('Cache-Control: private, pre-check=0, post-check=0, max-age=0');
2016 @header('Pragma: no-cache');
2017 @header('Expires: ');
2018 } else { // Do everything we can to always prevent clients and proxies caching
2019 @header('Cache-Control: no-store, no-cache, must-revalidate');
2020 @header('Cache-Control: post-check=0, pre-check=0', false);
2021 @header('Pragma: no-cache');
2022 @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT');
2023 @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
2025 $meta .= "\n<meta http-equiv=\"pragma\" content=\"no-cache\" />";
2026 $meta .= "\n<meta http-equiv=\"expires\" content=\"0\" />";
2028 @header('Accept-Ranges: none');
2030 if ($usexml) { // Added by Gustav Delius / Mad Alex for MathML output
2031 // Modified by Julian Sedding
2032 $currentlanguage = current_language();
2033 $mathplayer = preg_match("/MathPlayer/i", $_SERVER['HTTP_USER_AGENT']);
2034 if(!$mathplayer) {
2035 header('Content-Type: application/xhtml+xml');
2037 echo '<?xml version="1.0" ?>'."\n";
2038 if (!empty($CFG->xml_stylesheets)) {
2039 $stylesheets = explode(';', $CFG->xml_stylesheets);
2040 foreach ($stylesheets as $stylesheet) {
2041 echo '<?xml-stylesheet type="text/xsl" href="'. $CFG->wwwroot .'/'. $stylesheet .'" ?>' . "\n";
2044 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1';
2045 if (!empty($CFG->xml_doctype_extra)) {
2046 echo ' plus '. $CFG->xml_doctype_extra;
2048 echo '//' . strtoupper($currentlanguage) . '" "'. $CFG->xml_dtd .'">'."\n";
2049 $direction = " xmlns=\"http://www.w3.org/1999/xhtml\"
2050 xmlns:math=\"http://www.w3.org/1998/Math/MathML\"
2051 xmlns:xlink=\"http://www.w3.org/1999/xlink\"
2052 $direction";
2053 if($mathplayer) {
2054 $meta .= '<object id="mathplayer" classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987">' . "\n";
2055 $meta .= '<!--comment required to prevent this becoming an empty tag-->'."\n";
2056 $meta .= '</object>'."\n";
2057 $meta .= '<?import namespace="math" implementation="#mathplayer" ?>' . "\n";
2061 // Clean up the title
2063 $title = str_replace('"', '&quot;', $title);
2064 $title = strip_tags($title);
2066 // Create class and id for this page
2068 page_id_and_class($pageid, $pageclass);
2070 if (isset($course->id)) {
2071 $pageclass .= ' course-'.$course->id;
2072 } else {
2073 $pageclass .= ' course-'.SITEID;
2076 if (!empty($USER->editing)) {
2077 $pageclass .= ' editing';
2080 $bodytags .= ' class="'.$pageclass.'" id="'.$pageid.'"';
2082 include ($CFG->themedir.current_theme().'/header.html');
2084 if (!empty($CFG->messaging)) {
2085 echo message_popup_window();
2090 * This version of print_header is simpler because the course name does not have to be
2091 * provided explicitly in the strings. It can be used on the site page as in courses
2092 * Eventually all print_header could be replaced by print_header_simple
2094 * @param string $title Appears at the top of the window
2095 * @param string $heading Appears at the top of the page
2096 * @param string $navigation Premade navigation string (for use as breadcrumbs links)
2097 * @param string $focus Indicates form element to get cursor focus on load eg inputform.password
2098 * @param string $meta Meta tags to be added to the header
2099 * @param boolean $cache Should this page be cacheable?
2100 * @param string $button HTML code for a button (usually for module editing)
2101 * @param string $menu HTML code for a popup menu
2102 * @param boolean $usexml use XML for this page
2103 * @param string $bodytags This text will be included verbatim in the <body> tag (useful for onload() etc)
2105 function print_header_simple($title='', $heading='', $navigation='', $focus='', $meta='',
2106 $cache=true, $button='&nbsp;', $menu='', $usexml=false, $bodytags='') {
2108 global $course,$CFG; // The same hack is used in print_header
2110 $shortname ='';
2111 if ($course->category) {
2112 $shortname = '<a href="'.$CFG->wwwroot.'/course/view.php?id='. $course->id .'">'. $course->shortname .'</a> ->';
2115 print_header($course->shortname .': '. $title, $course->fullname .' '. $heading, $shortname .' '. $navigation, $focus, $meta,
2116 $cache, $button, $menu, $usexml, $bodytags);
2121 * Can provide a course object to make the footer contain a link to
2122 * to the course home page, otherwise the link will go to the site home
2124 * @uses $CFG
2125 * @uses $USER
2126 * @param course $course {@link $COURSE} object containing course information
2127 * @param ? $usercourse ?
2128 * @todo Finish documenting this function
2130 function print_footer($course=NULL, $usercourse=NULL) {
2131 global $USER, $CFG, $THEME;
2133 /// Course links
2134 if ($course) {
2135 if (is_string($course) && $course == 'none') { // Don't print any links etc
2136 $homelink = '';
2137 $loggedinas = '';
2138 $home = false;
2139 } else if (is_string($course) && $course == 'home') { // special case for site home page - please do not remove
2140 $course = get_site();
2141 $homelink = '<div class="sitelink">'.
2142 '<a title="moodle '. $CFG->release .' ('. $CFG->version .')" href="http://moodle.org/" target="_blank">'.
2143 '<br /><img width="100" height="30" src="pix/moodlelogo.gif" border="0" alt="moodlelogo" /></a></div>';
2144 $home = true;
2145 } else {
2146 $homelink = '<div class="homelink"><a target="'.$CFG->framename.'" href="'.$CFG->wwwroot.
2147 '/course/view.php?id='.$course->id.'">'.$course->shortname.'</a></div>';
2148 $home = false;
2150 } else {
2151 $course = get_site(); // Set course as site course by default
2152 $homelink = '<div class="homelink"><a target="'.$CFG->framename.'" href="'.$CFG->wwwroot.'/">'.get_string('home').'</a></div>';
2153 $home = false;
2156 /// Set up some other navigation links (passed from print_header by ugly hack)
2157 $menu = isset($THEME->menu) ? str_replace('navmenu', 'navmenufooter', $THEME->menu) : '';
2158 $title = isset($THEME->title) ? $THEME->title : '';
2159 $button = isset($THEME->button) ? $THEME->button : '';
2160 $heading = isset($THEME->heading) ? $THEME->heading : '';
2161 $navigation = isset($THEME->navigation) ? $THEME->navigation : '';
2162 $navmenulist = isset($THEME->navmenulist) ? $THEME->navmenulist : '';
2165 /// Set the user link if necessary
2166 if (!$usercourse and is_object($course)) {
2167 $usercourse = $course;
2170 if (!isset($loggedinas)) {
2171 $loggedinas = user_login_string($usercourse, $USER);
2174 if ($loggedinas == $menu) {
2175 $menu = '';
2178 /// Provide some performance info if required
2179 $performanceinfo = '';
2180 if (defined('MDL_PERF') || $CFG->perfdebug > 7) {
2181 $perf = get_performance_info();
2182 if (defined('MDL_PERFTOLOG')) {
2183 error_log("PERF: " . $perf['txt']);
2185 if (defined('MDL_PERFTOFOOT') || $CFG->debug > 7 || $CFG->perfdebug > 7) {
2186 $performanceinfo = $perf['html'];
2191 /// Include the actual footer file
2193 include ($CFG->themedir.current_theme().'/footer.html');
2198 * Returns the name of the current theme
2200 * @uses $CFG
2201 * @param $USER
2202 * @param $SESSION
2203 * @return string
2205 function current_theme() {
2206 global $CFG, $USER, $SESSION, $course;
2208 if (!empty($CFG->pagetheme)) { // Page theme is for special page-only themes set by code
2209 return $CFG->pagetheme;
2211 } else if (!empty($CFG->coursetheme) and !empty($CFG->allowcoursethemes)) { // Course themes override others
2212 return $CFG->coursetheme;
2214 } else if (!empty($SESSION->theme)) { // Session theme can override other settings
2215 return $SESSION->theme;
2217 } else if (!empty($USER->theme) and !empty($CFG->allowuserthemes)) { // User theme can override site theme
2218 return $USER->theme;
2220 } else {
2221 return $CFG->theme;
2227 * This function is called by stylesheets to set up the header
2228 * approriately as well as the current path
2230 * @uses $CFG
2231 * @param int $lastmodified ?
2232 * @param int $lifetime ?
2233 * @param string $thename ?
2235 function style_sheet_setup($lastmodified=0, $lifetime=300, $themename='', $forceconfig='', $lang='') {
2237 global $CFG, $THEME;
2239 // Fix for IE6 caching - we don't want the filemtime('styles.php'), instead use now.
2240 $lastmodified = time();
2242 header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $lastmodified) . ' GMT');
2243 header('Expires: ' . gmdate("D, d M Y H:i:s", time() + $lifetime) . ' GMT');
2244 header('Cache-Control: max-age='. $lifetime);
2245 header('Pragma: ');
2246 header('Content-type: text/css'); // Correct MIME type
2248 $DEFAULT_SHEET_LIST = array('styles_layout', 'styles_fonts', 'styles_color');
2250 if (empty($themename)) {
2251 $themename = current_theme(); // So we have something. Normally not needed.
2252 } else {
2253 $themename = clean_param($themename, PARAM_SAFEDIR);
2256 if (!empty($forceconfig)) { // Page wants to use the config from this theme instead
2257 unset($THEME);
2258 include($CFG->themedir.$forceconfig.'/'.'config.php');
2261 /// If this is the standard theme calling us, then find out what sheets we need
2263 if ($themename == 'standard') {
2264 if (!isset($THEME->standardsheets) or $THEME->standardsheets === true) { // Use all the sheets we have
2265 $THEME->sheets = $DEFAULT_SHEET_LIST;
2266 } else if (empty($THEME->standardsheets)) { // We can stop right now!
2267 echo "/***** Nothing required from this stylesheet by main theme *****/\n\n";
2268 exit;
2269 } else { // Use the provided subset only
2270 $THEME->sheets = $THEME->standardsheets;
2273 /// If we are a parent theme, then check for parent definitions
2275 } else if (!empty($THEME->parent) && $themename == $THEME->parent) {
2276 if (!isset($THEME->parentsheets) or $THEME->parentsheets === true) { // Use all the sheets we have
2277 $THEME->sheets = $DEFAULT_SHEET_LIST;
2278 } else if (empty($THEME->parentsheets)) { // We can stop right now!
2279 echo "/***** Nothing required from this stylesheet by main theme *****/\n\n";
2280 exit;
2281 } else { // Use the provided subset only
2282 $THEME->sheets = $THEME->parentsheets;
2286 /// Work out the last modified date for this theme
2288 foreach ($THEME->sheets as $sheet) {
2289 if (file_exists($CFG->themedir.$themename.'/'.$sheet.'.css')) {
2290 $sheetmodified = filemtime($CFG->themedir.$themename.'/'.$sheet.'.css');
2291 if ($sheetmodified > $lastmodified) {
2292 $lastmodified = $sheetmodified;
2298 /// Get a list of all the files we want to include
2299 $files = array();
2301 foreach ($THEME->sheets as $sheet) {
2302 $files[] = array($CFG->themedir, $themename.'/'.$sheet.'.css');
2305 if ($themename == 'standard') { // Add any standard styles included in any modules
2306 if (!empty($THEME->modsheets)) { // Search for styles.php within activity modules
2307 if ($mods = get_list_of_plugins('mod')) {
2308 foreach ($mods as $mod) {
2309 if (file_exists($CFG->dirroot.'/mod/'.$mod.'/styles.php')) {
2310 $files[] = array($CFG->dirroot, '/mod/'.$mod.'/styles.php');
2316 if (!empty($THEME->blocksheets)) { // Search for styles.php within block modules
2317 if ($mods = get_list_of_plugins('blocks')) {
2318 foreach ($mods as $mod) {
2319 if (file_exists($CFG->dirroot.'/blocks/'.$mod.'/styles.php')) {
2320 $files[] = array($CFG->dirroot, '/blocks/'.$mod.'/styles.php');
2326 if (!empty($THEME->langsheets)) { // Search for styles.php within the current language
2327 if (file_exists($CFG->dirroot.'/lang/'.$lang.'/styles.php')) {
2328 $files[] = array($CFG->dirroot, '/lang/'.$lang.'/styles.php');
2334 if ($files) {
2335 /// Produce a list of all the files first
2336 echo '/**************************************'."\n";
2337 echo ' * THEME NAME: '.$themename."\n *\n";
2338 echo ' * Files included in this sheet:'."\n *\n";
2339 foreach ($files as $file) {
2340 echo ' * '.$file[1]."\n";
2342 echo ' **************************************/'."\n\n";
2345 /// Actually output all the files in order.
2346 foreach ($files as $file) {
2347 echo '/***** '.$file[1].' start *****/'."\n\n";
2348 @include_once($file[0].$file[1]);
2349 echo '/***** '.$file[1].' end *****/'."\n\n";
2353 return $CFG->themewww.$themename; // Only to help old themes (1.4 and earlier)
2357 function theme_setup($theme = '', $params=NULL) {
2358 /// Sets up global variables related to themes
2360 global $CFG, $THEME, $SESSION, $USER;
2362 if (empty($theme)) {
2363 $theme = current_theme();
2366 /// If the theme doesn't exist for some reason then revert to standardwhite
2367 if (!file_exists($CFG->themedir. $theme .'/config.php')) {
2368 $CFG->theme = $theme = 'standardwhite';
2371 /// Load up the theme config
2372 $THEME = NULL; // Just to be sure
2373 include($CFG->themedir. $theme .'/config.php'); // Main config for current theme
2375 /// Put together the parameters
2376 if (!$params) {
2377 $params = array();
2379 if ($theme != $CFG->theme) {
2380 $params[] = 'forceconfig='.$theme;
2383 /// Force language too if required
2384 if (!empty($THEME->langsheets)) {
2385 $params[] = 'lang='.current_language();
2388 /// Convert params to string
2389 if ($params) {
2390 $paramstring = '?'.implode('&', $params);
2391 } else {
2392 $paramstring = '';
2395 /// Set up image paths
2396 if (empty($THEME->custompix)) { // Could be set in the above file
2397 $CFG->pixpath = $CFG->wwwroot .'/pix';
2398 $CFG->modpixpath = $CFG->wwwroot .'/mod';
2399 } else {
2400 $CFG->pixpath = $CFG->themewww . $theme .'/pix';
2401 $CFG->modpixpath = $CFG->themewww . $theme .'/pix/mod';
2404 /// Header and footer paths
2405 $CFG->header = $CFG->themedir . $theme .'/header.html';
2406 $CFG->footer = $CFG->themedir . $theme .'/footer.html';
2408 /// Define stylesheet loading order
2409 $CFG->stylesheets = array();
2410 if ($theme != 'standard') { /// The standard sheet is always loaded first
2411 $CFG->stylesheets[] = $CFG->themewww.'standard/styles.php'.$paramstring;
2413 if (!empty($THEME->parent)) { /// Parent stylesheets are loaded next
2414 $CFG->stylesheets[] = $CFG->themewww.$THEME->parent.'/styles.php'.$paramstring;
2416 $CFG->stylesheets[] = $CFG->themewww.$theme.'/styles.php'.$paramstring;
2422 * Returns text to be displayed to the user which reflects their login status
2424 * @uses $CFG
2425 * @uses $USER
2426 * @param course $course {@link $COURSE} object containing course information
2427 * @param user $user {@link $USER} object containing user information
2428 * @return string
2430 function user_login_string($course=NULL, $user=NULL) {
2431 global $USER, $CFG, $SITE;
2433 if (empty($user) and isset($USER->id)) {
2434 $user = $USER;
2437 if (empty($course)) {
2438 $course = $SITE;
2441 if (isset($user->realuser)) {
2442 if ($realuser = get_record('user', 'id', $user->realuser)) {
2443 $fullname = fullname($realuser, true);
2444 $realuserinfo = " [<a target=\"{$CFG->framename}\"
2445 href=\"$CFG->wwwroot/course/loginas.php?id=$course->id&amp;return=1\">$fullname</a>] ";
2447 } else {
2448 $realuserinfo = '';
2451 if (empty($CFG->loginhttps)) {
2452 $wwwroot = $CFG->wwwroot;
2453 } else {
2454 $wwwroot = str_replace('http:','https:',$CFG->wwwroot);
2457 if (isset($user->id) and $user->id) {
2458 $fullname = fullname($user, true);
2459 $username = "<a target=\"{$CFG->framename}\" href=\"$CFG->wwwroot/user/view.php?id=$user->id&amp;course=$course->id\">$fullname</a>";
2460 $instudentview = (!empty($USER->studentview)) ? get_string('instudentview') : '';
2461 if (isguest($user->id)) {
2462 $loggedinas = $realuserinfo.get_string('loggedinasguest').
2463 " (<a target=\"{$CFG->framename}\" href=\"$wwwroot/login/index.php\">".get_string('login').'</a>)';
2464 } else {
2465 $loggedinas = $realuserinfo.get_string('loggedinas', 'moodle', $username).' '.$instudentview.
2466 " (<a target=\"{$CFG->framename}\" href=\"$CFG->wwwroot/login/logout.php\">".get_string('logout').'</a>)';
2468 } else {
2469 $loggedinas = get_string('loggedinnot', 'moodle').
2470 " (<a target=\"{$CFG->framename}\" href=\"$wwwroot/login/index.php\">".get_string('login').'</a>)';
2472 return '<div class="logininfo">'.$loggedinas.'</div>';
2476 * Prints breadcrumbs links
2478 * @uses $CFG
2479 * @param string $navigation The breadcrumbs string to be printed
2481 function print_navigation ($navigation) {
2482 global $CFG, $USER;
2484 if ($navigation) {
2485 //Accessibility: breadcrumb links now in a list, &raquo; replaced with image.
2486 $nav_text = get_string('youarehere','access');
2487 echo '<h2 class="accesshide">'.$nav_text.",</h2><ul>\n";
2488 if (! $site = get_site()) {
2489 $site->shortname = get_string('home');
2491 $navigation = '<li title="'.$nav_text.'"><img src="'.$CFG->pixpath.'/a/r_breadcrumb.gif" class="resize" alt="" /> '
2492 .str_replace('->', '</li><li title="'.$nav_text.'"><img src="'.$CFG->pixpath.'/a/r_breadcrumb.gif" class="resize" alt="" /> ', $navigation)."</li>\n";
2493 echo '<li class="first"><a target="'. $CFG->framename .'" href="'. $CFG->wwwroot.((!isadmin() && !empty($USER->id) && !empty($CFG->mymoodleredirect) && !isguest())
2494 ? '/my' : '') .'/">'. $site->shortname ."</a></li>\n". $navigation;
2495 echo "</ul>\n";
2500 * Prints a string in a specified size (retained for backward compatibility)
2502 * @param string $text The text to be displayed
2503 * @param int $size The size to set the font for text display.
2505 function print_headline($text, $size=2) {
2506 print_heading($text, 'left', $size);
2510 * Prints text in a format for use in headings.
2512 * @param string $text The text to be displayed
2513 * @param string $align The alignment of the printed paragraph of text
2514 * @param int $size The size to set the font for text display.
2516 function print_heading($text, $align='', $size=2, $class='main') {
2517 if ($align) {
2518 $align = ' align="'.$align.'"';
2520 if ($class) {
2521 $class = ' class="'.$class.'"';
2523 echo "<h$size $align $class>".stripslashes_safe($text)."</h$size>";
2527 * Centered heading with attached help button (same title text)
2528 * and optional icon attached
2530 * @param string $text The text to be displayed
2531 * @param string $helppage The help page to link to
2532 * @param string $module The module whose help should be linked to
2533 * @param string $icon Image to display if needed
2535 function print_heading_with_help($text, $helppage, $module='moodle', $icon='') {
2536 echo '<h2 class="main help">'.$icon.stripslashes_safe($text);
2537 helpbutton($helppage, $text, $module);
2538 echo '</h2>';
2542 function print_heading_block($heading, $class='') {
2543 //Accessibility: 'headingblock' is now H1, see theme/standard/styles_*.css: ??
2544 echo '<h2 class="headingblock header '.$class.'">'.stripslashes($heading).'</h2>';
2549 * Print a link to continue on to another page.
2551 * @uses $CFG
2552 * @param string $link The url to create a link to.
2554 function print_continue($link) {
2556 global $CFG;
2558 if (!$link) {
2559 $link = $_SERVER['HTTP_REFERER'];
2562 echo '<div class="continuebutton">';
2563 print_single_button($link, NULL, get_string('continue'), 'post', $CFG->framename);
2564 echo '</div>'."\n";
2568 * Print a message in a standard themed box.
2569 * See, {@link print_simple_box_start}.
2571 * @param string $align string, alignment of the box, not the text (default center, left, right).
2572 * @param string $width string, width of the box, including units %, for example '100%'.
2573 * @param string $color string, background colour of the box, for example '#eee'.
2574 * @param int $padding integer, padding in pixels, specified without units.
2575 * @param string $class string, space-separated class names.
2576 * @todo Finish documenting this function
2578 function print_simple_box($message, $align='', $width='', $color='', $padding=5, $class='generalbox', $id='') {
2579 print_simple_box_start($align, $width, $color, $padding, $class, $id);
2580 echo stripslashes_safe($message);
2581 print_simple_box_end();
2585 * Print the top portion of a standard themed box using a TABLE. Yes, we know.
2586 * See bug 4943 for details on some accessibility work regarding this that didn't make it into 1.6.
2588 * @param string $align string, alignment of the box, not the text (default center, left, right).
2589 * @param string $width string, width of the box, including % units, for example '100%'.
2590 * @param string $color string, background colour of the box, for example '#eee'.
2591 * @param int $padding integer, padding in pixels, specified without units.
2592 * @param string $class string, space-separated class names.
2594 function print_simple_box_start($align='', $width='', $color='', $padding=5, $class='generalbox', $id='') {
2596 if ($color) {
2597 $color = 'bgcolor="'. $color .'"';
2599 if ($align) {
2600 $align = 'align="'. $align .'"';
2602 if ($width) {
2603 $width = 'width="'. $width .'"';
2605 if ($id) {
2606 $id = 'id="'. $id .'"';
2608 echo "<table $align $width $id class=\"$class\" border=\"0\" cellpadding=\"$padding\" cellspacing=\"0\">".
2609 "<tr><td $color class=\"$class"."content\">";
2613 * Print the end portion of a standard themed box.
2615 function print_simple_box_end() {
2616 echo '</td></tr></table>';
2621 * Print a self contained form with a single submit button.
2623 * @param string $link ?
2624 * @param array $options ?
2625 * @param string $label ?
2626 * @param string $method ?
2627 * @todo Finish documenting this function
2629 function print_single_button($link, $options, $label='OK', $method='get', $target='_self') {
2630 echo '<div class="singlebutton">';
2631 echo '<form action="'. $link .'" method="'. $method .'" target="'.$target.'">';
2632 if ($options) {
2633 foreach ($options as $name => $value) {
2634 echo '<input type="hidden" name="'. $name .'" value="'. $value .'" />';
2637 echo '<input type="submit" value="'. $label .'" /></form></div>';
2641 * Print a spacer image with the option of including a line break.
2643 * @param int $height ?
2644 * @param int $width ?
2645 * @param boolean $br ?
2646 * @todo Finish documenting this function
2648 function print_spacer($height=1, $width=1, $br=true) {
2649 global $CFG;
2650 echo '<img class="spacer" height="'. $height .'" width="'. $width .'" src="'. $CFG->wwwroot .'/pix/spacer.gif" alt="" />';
2651 if ($br) {
2652 echo '<br />'."\n";
2657 * Given the path to a picture file in a course, or a URL,
2658 * this function includes the picture in the page.
2660 * @param string $path ?
2661 * @param int $courseid ?
2662 * @param int $height ?
2663 * @param int $width ?
2664 * @param string $link ?
2665 * @todo Finish documenting this function
2667 function print_file_picture($path, $courseid=0, $height='', $width='', $link='') {
2668 global $CFG;
2670 if ($height) {
2671 $height = 'height="'. $height .'"';
2673 if ($width) {
2674 $width = 'width="'. $width .'"';
2676 if ($link) {
2677 echo '<a href="'. $link .'">';
2679 if (substr(strtolower($path), 0, 7) == 'http://') {
2680 echo '<img border="0" '.$height . $width .' src="'. $path .'" />';
2682 } else if ($courseid) {
2683 echo '<img border="0" '. $height . $width .' src="';
2684 if ($CFG->slasharguments) { // Use this method if possible for better caching
2685 echo $CFG->wwwroot .'/file.php/'. $courseid .'/'. $path;
2686 } else {
2687 echo $CFG->wwwroot .'/file.php?file=/'. $courseid .'/'. $path;
2689 echo '" />';
2690 } else {
2691 echo 'Error: must pass URL or course';
2693 if ($link) {
2694 echo '</a>';
2699 * Print the specified user's avatar.
2701 * @param int $userid ?
2702 * @param int $courseid ?
2703 * @param boolean $picture Print the user picture?
2704 * @param int $size Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatability
2705 * @param boolean $returnstring If false print picture to current page, otherwise return the output as string
2706 * @param boolean $link Enclose printed image in a link to view specified course?
2707 * return string
2708 * @todo Finish documenting this function
2710 function print_user_picture($userid, $courseid, $picture, $size=0, $returnstring=false, $link=true, $target='') {
2711 global $CFG;
2713 if ($link) {
2714 if ($target) {
2715 $target=' target="_blank"';
2717 $output = '<a '.$target.' href="'. $CFG->wwwroot .'/user/view.php?id='. $userid .'&amp;course='. $courseid .'">';
2718 } else {
2719 $output = '';
2721 if (empty($size)) {
2722 $file = 'f2';
2723 $size = 35;
2724 } else if ($size === true or $size == 1) {
2725 $file = 'f1';
2726 $size = 100;
2727 } else if ($size >= 50) {
2728 $file = 'f1';
2729 } else {
2730 $file = 'f2';
2732 $class = "userpicture";
2733 if ($picture) { // Print custom user picture
2734 if ($CFG->slasharguments) { // Use this method if possible for better caching
2735 $src = $CFG->wwwroot .'/user/pix.php/'. $userid .'/'. $file .'.jpg"';
2736 } else {
2737 $src = $CFG->wwwroot .'/user/pix.php?file=/'. $userid .'/'. $file .'.jpg"';
2739 } else { // Print default user pictures (use theme version if available)
2740 $class .= " defaultuserpic";
2741 $src = "$CFG->pixpath/u/$file.png\"";
2743 $output .= "<img class=\"$class\" align=\"middle\" src=\"$src".
2744 " border=\"0\" width=\"$size\" height=\"$size\" alt=\"\" />";
2745 if ($link) {
2746 $output .= '</a>';
2749 if ($returnstring) {
2750 return $output;
2751 } else {
2752 echo $output;
2757 * Prints a summary of a user in a nice little box.
2759 * @uses $CFG
2760 * @uses $USER
2761 * @param user $user A {@link $USER} object representing a user
2762 * @param course $course A {@link $COURSE} object representing a course
2764 function print_user($user, $course, $messageselect=false) {
2766 global $CFG, $USER;
2768 static $string;
2769 static $datestring;
2770 static $countries;
2771 static $isteacher;
2772 static $isadmin;
2774 if (empty($string)) { // Cache all the strings for the rest of the page
2776 $string->email = get_string('email');
2777 $string->location = get_string('location');
2778 $string->lastaccess = get_string('lastaccess');
2779 $string->activity = get_string('activity');
2780 $string->unenrol = get_string('unenrol');
2781 $string->loginas = get_string('loginas');
2782 $string->fullprofile = get_string('fullprofile');
2783 $string->role = get_string('role');
2784 $string->name = get_string('name');
2785 $string->never = get_string('never');
2787 $datestring->day = get_string('day');
2788 $datestring->days = get_string('days');
2789 $datestring->hour = get_string('hour');
2790 $datestring->hours = get_string('hours');
2791 $datestring->min = get_string('min');
2792 $datestring->mins = get_string('mins');
2793 $datestring->sec = get_string('sec');
2794 $datestring->secs = get_string('secs');
2796 $countries = get_list_of_countries();
2798 $isteacher = isteacher($course->id);
2799 $isadmin = isadmin();
2802 /// Get the hidden field list
2803 if ($isteacher || $isadmin) {
2804 $hiddenfields = array();
2805 } else {
2806 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
2809 echo '<table class="userinfobox">';
2810 echo '<tr>';
2811 echo '<td class="left side">';
2812 print_user_picture($user->id, $course->id, $user->picture, true);
2813 echo '</td>';
2814 echo '<td class="content">';
2815 echo '<div class="username">'.fullname($user, $isteacher).'</div>';
2816 echo '<div class="info">';
2817 if (!empty($user->role) and ($user->role <> $course->teacher)) {
2818 echo $string->role .': '. $user->role .'<br />';
2820 if ($user->maildisplay == 1 or ($user->maildisplay == 2 and $course->category and !isguest()) or $isteacher) {
2821 echo $string->email .': <a href="mailto:'. $user->email .'">'. $user->email .'</a><br />';
2823 if (($user->city or $user->country) and (!isset($hiddenfields['city']) or !isset($hiddenfields['country']))) {
2824 echo $string->location .': ';
2825 if ($user->city && !isset($hiddenfields['city'])) {
2826 echo $user->city;
2828 if (!empty($countries[$user->country]) && !isset($hiddenfields['country'])) {
2829 if ($user->city && !isset($hiddenfields['city'])) {
2830 echo ', ';
2832 echo $countries[$user->country];
2834 echo '<br />';
2837 if (!isset($hiddenfields['lastaccess'])) {
2838 if ($user->lastaccess) {
2839 echo $string->lastaccess .': '. userdate($user->lastaccess);
2840 echo '&nbsp ('. format_time(time() - $user->lastaccess, $datestring) .')';
2841 } else {
2842 echo $string->lastaccess .': '. $string->never;
2845 echo '</div></td><td class="links">';
2846 //link to blogs
2847 if ($CFG->bloglevel > 0) {
2848 echo '<a href="'.$CFG->wwwroot.'/blog/index.php?userid='.$user->id.'">'.get_string('blogs','blog').'</a><br />';
2851 if ($isteacher) {
2852 $timemidnight = usergetmidnight(time());
2853 echo '<a href="'. $CFG->wwwroot .'/course/user.php?id='. $course->id .'&amp;user='. $user->id .'">'. $string->activity .'</a><br />';
2854 if (!iscreator($user->id) or ($isadmin and !isadmin($user->id))) { // Includes admins
2855 if ($course->category and isteacheredit($course->id) and isstudent($course->id, $user->id)) { // Includes admins
2856 echo '<a href="'. $CFG->wwwroot .'/course/unenrol.php?id='. $course->id .'&amp;user='. $user->id .'">'. $string->unenrol .'</a><br />';
2858 if ($USER->id != $user->id) {
2859 echo '<a href="'. $CFG->wwwroot .'/course/loginas.php?id='. $course->id .'&amp;user='. $user->id .'">'. $string->loginas .'</a><br />';
2863 echo '<a href="'. $CFG->wwwroot .'/user/view.php?id='. $user->id .'&amp;course='. $course->id .'">'. $string->fullprofile .'...</a>';
2865 if (!empty($messageselect) && $isteacher) {
2866 echo '<br /><input type="checkbox" name="';
2867 if (isteacher($course->id, $user->id)) {
2868 echo 'teacher';
2869 } else {
2870 echo 'user';
2872 echo $user->id.'" /> ';
2875 echo '</td></tr></table>';
2879 * Print a specified group's avatar.
2881 * @param group $group A {@link group} object representing a group or array of groups
2882 * @param int $courseid ?
2883 * @param boolean $large ?
2884 * @param boolean $returnstring ?
2885 * @param boolean $link ?
2886 * @return string
2887 * @todo Finish documenting this function
2889 function print_group_picture($group, $courseid, $large=false, $returnstring=false, $link=true) {
2890 global $CFG;
2892 if (is_array($group)) {
2893 $output = '';
2894 foreach($group as $g) {
2895 $output .= print_group_picture($g, $courseid, $large, true, $link);
2897 if ($returnstring) {
2898 return $output;
2899 } else {
2900 echo $output;
2901 return;
2905 static $isteacheredit;
2907 if (!isset($isteacheredit)) {
2908 $isteacheredit = isteacheredit($courseid);
2911 if ($group->hidepicture and !$isteacheredit) {
2912 return '';
2915 if ($link or $isteacheredit) {
2916 $output = '<a href="'. $CFG->wwwroot .'/user/index.php?id='. $courseid .'&amp;group='. $group->id .'">';
2917 } else {
2918 $output = '';
2920 if ($large) {
2921 $file = 'f1';
2922 $size = 100;
2923 } else {
2924 $file = 'f2';
2925 $size = 35;
2927 if ($group->picture) { // Print custom group picture
2928 if ($CFG->slasharguments) { // Use this method if possible for better caching
2929 $output .= '<img class="grouppicture" align="middle" src="'.$CFG->wwwroot.'/user/pixgroup.php/'.$group->id.'/'.$file.'.jpg"'.
2930 ' border="0" width="'.$size.'" height="'.$size.'" alt="" title="'.s($group->name).'"/>';
2931 } else {
2932 $output .= '<img class="grouppicture" align="middle" src="'.$CFG->wwwroot.'/user/pixgroup.php?file=/'.$group->id.'/'.$file.'.jpg"'.
2933 ' border="0" width="'.$size.'" height="'.$size.'" alt="" title="'.s($group->name).'"/>';
2936 if ($link or $isteacheredit) {
2937 $output .= '</a>';
2940 if ($returnstring) {
2941 return $output;
2942 } else {
2943 echo $output;
2948 * Print a png image.
2950 * @param string $url ?
2951 * @param int $sizex ?
2952 * @param int $sizey ?
2953 * @param boolean $returnstring ?
2954 * @param string $parameters ?
2955 * @todo Finish documenting this function
2957 function print_png($url, $sizex, $sizey, $returnstring, $parameters='alt=""') {
2958 global $CFG;
2959 static $recentIE;
2961 if (!isset($recentIE)) {
2962 $recentIE = check_browser_version('MSIE', '5.0');
2965 if ($recentIE) { // work around the HORRIBLE bug IE has with alpha transparencies
2966 $output .= '<img src="'. $CFG->pixpath .'/spacer.gif" width="'. $sizex .'" height="'. $sizey .'"'.
2967 ' border="0" class="png" style="width: '. $sizex .'px; height: '. $sizey .'px; '.
2968 ' filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='.
2969 "'$url', sizingMethod='scale') ".
2970 ' '. $parameters .' />';
2971 } else {
2972 $output .= '<img src="'. $url .'" border="0" width="'. $sizex .'" height="'. $sizey .'" '.
2973 ' '. $parameters .' />';
2976 if ($returnstring) {
2977 return $output;
2978 } else {
2979 echo $output;
2984 * Print a nicely formatted table.
2986 * @param array $table is an object with several properties.
2987 * <ul<li>$table->head - An array of heading names.
2988 * <li>$table->align - An array of column alignments
2989 * <li>$table->size - An array of column sizes
2990 * <li>$table->wrap - An array of "nowrap"s or nothing
2991 * <li>$table->data[] - An array of arrays containing the data.
2992 * <li>$table->width - A percentage of the page
2993 * <li>$table->tablealign - Align the whole table
2994 * <li>$table->cellpadding - Padding on each cell
2995 * <li>$table->cellspacing - Spacing between cells
2996 * </ul>
2997 * @return boolean
2998 * @todo Finish documenting this function
3000 function print_table($table) {
3002 if (isset($table->align)) {
3003 foreach ($table->align as $key => $aa) {
3004 if ($aa) {
3005 $align[$key] = ' align="'. $aa .'"';
3006 } else {
3007 $align[$key] = '';
3011 if (isset($table->size)) {
3012 foreach ($table->size as $key => $ss) {
3013 if ($ss) {
3014 $size[$key] = ' width="'. $ss .'"';
3015 } else {
3016 $size[$key] = '';
3020 if (isset($table->wrap)) {
3021 foreach ($table->wrap as $key => $ww) {
3022 if ($ww) {
3023 $wrap[$key] = ' nowrap="nowrap" ';
3024 } else {
3025 $wrap[$key] = '';
3030 if (empty($table->width)) {
3031 $table->width = '80%';
3034 if (empty($table->tablealign)) {
3035 $table->tablealign = 'center';
3038 if (empty($table->cellpadding)) {
3039 $table->cellpadding = '5';
3042 if (empty($table->cellspacing)) {
3043 $table->cellspacing = '1';
3046 if (empty($table->class)) {
3047 $table->class = 'generaltable';
3050 $tableid = empty($table->id) ? '' : 'id="'.$table->id.'"';
3052 echo '<table width="'.$table->width.'" border="0" align="'.$table->tablealign.'" ';
3053 echo " cellpadding=\"$table->cellpadding\" cellspacing=\"$table->cellspacing\" class=\"$table->class\" $tableid>\n";
3055 $countcols = 0;
3057 if (!empty($table->head)) {
3058 $countcols = count($table->head);
3059 echo '<tr>';
3060 foreach ($table->head as $key => $heading) {
3062 if (!isset($size[$key])) {
3063 $size[$key] = '';
3065 if (!isset($align[$key])) {
3066 $align[$key] = '';
3068 echo '<th valign="top" '. $align[$key].$size[$key] .' nowrap="nowrap" class="header c'.$key.'">'. $heading .'</th>';
3070 echo '</tr>'."\n";
3073 if (!empty($table->data)) {
3074 $oddeven = 1;
3075 foreach ($table->data as $key => $row) {
3076 $oddeven = $oddeven ? 0 : 1;
3077 echo '<tr class="r'.$oddeven.'">'."\n";
3078 if ($row == 'hr' and $countcols) {
3079 echo '<td colspan="'. $countcols .'"><div class="tabledivider"></div></td>';
3080 } else { /// it's a normal row of data
3081 foreach ($row as $key => $item) {
3082 if (!isset($size[$key])) {
3083 $size[$key] = '';
3085 if (!isset($align[$key])) {
3086 $align[$key] = '';
3088 if (!isset($wrap[$key])) {
3089 $wrap[$key] = '';
3091 echo '<td '. $align[$key].$size[$key].$wrap[$key] .' class="cell c'.$key.'">'. $item .'</td>';
3094 echo '</tr>'."\n";
3097 echo '</table>'."\n";
3099 return true;
3103 * Creates a nicely formatted table and returns it.
3105 * @param array $table is an object with several properties.
3106 * <ul<li>$table->head - An array of heading names.
3107 * <li>$table->align - An array of column alignments
3108 * <li>$table->size - An array of column sizes
3109 * <li>$table->wrap - An array of "nowrap"s or nothing
3110 * <li>$table->data[] - An array of arrays containing the data.
3111 * <li>$table->class - A css class name
3112 * <li>$table->fontsize - Is the size of all the text
3113 * <li>$table->tablealign - Align the whole table
3114 * <li>$table->width - A percentage of the page
3115 * <li>$table->cellpadding - Padding on each cell
3116 * <li>$table->cellspacing - Spacing between cells
3117 * </ul>
3118 * @return string
3119 * @todo Finish documenting this function
3121 function make_table($table) {
3123 if (isset($table->align)) {
3124 foreach ($table->align as $key => $aa) {
3125 if ($aa) {
3126 $align[$key] = ' align="'. $aa .'"';
3127 } else {
3128 $align[$key] = '';
3132 if (isset($table->size)) {
3133 foreach ($table->size as $key => $ss) {
3134 if ($ss) {
3135 $size[$key] = ' width="'. $ss .'"';
3136 } else {
3137 $size[$key] = '';
3141 if (isset($table->wrap)) {
3142 foreach ($table->wrap as $key => $ww) {
3143 if ($ww) {
3144 $wrap[$key] = ' nowrap="nowrap" ';
3145 } else {
3146 $wrap[$key] = '';
3151 if (empty($table->width)) {
3152 $table->width = '80%';
3155 if (empty($table->tablealign)) {
3156 $table->tablealign = 'center';
3159 if (empty($table->cellpadding)) {
3160 $table->cellpadding = '5';
3163 if (empty($table->cellspacing)) {
3164 $table->cellspacing = '1';
3167 if (empty($table->class)) {
3168 $table->class = 'generaltable';
3171 if (empty($table->fontsize)) {
3172 $fontsize = '';
3173 } else {
3174 $fontsize = '<font size="'. $table->fontsize .'">';
3177 $output = '<table width="'. $table->width .'" align="'. $table->tablealign .'" ';
3178 $output .= ' cellpadding="'. $table->cellpadding .'" cellspacing="'. $table->cellspacing .'" class="'. $table->class .'">'."\n";
3180 if (!empty($table->head)) {
3181 $output .= '<tr valign="top">';
3182 foreach ($table->head as $key => $heading) {
3183 if (!isset($size[$key])) {
3184 $size[$key] = '';
3186 if (!isset($align[$key])) {
3187 $align[$key] = '';
3189 $output .= '<th valign="top" '. $align[$key].$size[$key] .' nowrap="nowrap" class="'. $table->class .'header">'.$fontsize.$heading.'</th>';
3191 $output .= '</tr>'."\n";
3194 foreach ($table->data as $row) {
3195 $output .= '<tr valign="top">';
3196 foreach ($row as $key => $item) {
3197 if (!isset($size[$key])) {
3198 $size[$key] = '';
3200 if (!isset($align[$key])) {
3201 $align[$key] = '';
3203 if (!isset($wrap[$key])) {
3204 $wrap[$key] = '';
3206 $output .= '<td '. $align[$key].$size[$key].$wrap[$key] .' class="'. $table->class .'cell">'. $fontsize . $item .'</td>';
3208 $output .= '</tr>'."\n";
3210 $output .= '</table>'."\n";
3212 return $output;
3215 function print_recent_activity_note($time, $user, $isteacher, $text, $link) {
3216 static $strftimerecent;
3218 if (empty($strftimerecent)) {
3219 $strftimerecent = get_string('strftimerecent');
3222 $date = userdate($time, $strftimerecent);
3223 $name = fullname($user, $isteacher);
3225 echo '<div class="head">';
3226 echo '<div class="date">'.$date.'</div> '.
3227 '<div class="name">'.fullname($user, $isteacher).'</div>';
3228 echo '</div>';
3229 echo '<div class="info"><a href="'.$link.'">'.format_string($text,true).'</a></div>';
3234 * Prints a basic textarea field.
3236 * @uses $CFG
3237 * @param boolean $usehtmleditor ?
3238 * @param int $rows ?
3239 * @param int $cols ?
3240 * @param null $width <b>Legacy field no longer used!</b> Set to zero to get control over mincols
3241 * @param null $height <b>Legacy field no longer used!</b> Set to zero to get control over minrows
3242 * @param string $name ?
3243 * @param string $value ?
3244 * @param int $courseid ?
3245 * @todo Finish documenting this function
3247 function print_textarea($usehtmleditor, $rows, $cols, $width, $height, $name, $value='', $courseid=0, $return=false) {
3248 /// $width and height are legacy fields and no longer used as pixels like they used to be.
3249 /// However, you can set them to zero to override the mincols and minrows values below.
3251 global $CFG, $course;
3252 static $scriptcount; // For loading the htmlarea script only once.
3254 $mincols = 65;
3255 $minrows = 10;
3256 $str = '';
3258 if ( empty($CFG->editorsrc) ) { // for backward compatibility.
3259 if (empty($courseid)) {
3260 if (!empty($course->id)) { // search for it in global context
3261 $courseid = $course->id;
3265 if (empty($scriptcount)) {
3266 $scriptcount = 0;
3269 if ($usehtmleditor) {
3271 if (!empty($courseid) and isteacher($courseid)) {
3272 $str .= ($scriptcount < 1) ? '<script type="text/javascript" src="'.
3273 $CFG->wwwroot .'/lib/editor/htmlarea/htmlarea.php?id='. $courseid .'"></script>'."\n" : '';
3274 } else {
3275 $str .= ($scriptcount < 1) ? '<script type="text/javascript" src="'.
3276 $CFG->wwwroot .'/lib/editor/htmlarea/htmlarea.php"></script>'."\n" : '';
3278 $str .= ($scriptcount < 1) ? '<script type="text/javascript" src="'.
3279 $CFG->wwwroot .'/lib/editor/htmlarea/lang/en.php"></script>'."\n" : '';
3280 $scriptcount++;
3282 if ($height) { // Usually with legacy calls
3283 if ($rows < $minrows) {
3284 $rows = $minrows;
3287 if ($width) { // Usually with legacy calls
3288 if ($cols < $mincols) {
3289 $cols = $mincols;
3294 $str .= '<textarea id="edit-'. $name .'" name="'. $name .'" rows="'. $rows .'" cols="'. $cols .'">';
3295 if ($usehtmleditor) {
3296 $str .= htmlspecialchars($value); // needed for editing of cleaned text!
3297 } else {
3298 $str .= s($value);
3300 $str .= '</textarea>'."\n";
3302 if ($return) {
3303 return $str;
3305 echo $str;
3309 * Legacy function, provided for backward compatability.
3310 * This method now simply calls {@link use_html_editor()}
3312 * @deprecated Use {@link use_html_editor()} instead.
3313 * @param string $name Form element to replace with HTMl editor by name
3314 * @todo Finish documenting this function
3316 function print_richedit_javascript($form, $name, $source='no') {
3317 use_html_editor($name);
3321 * Sets up the HTML editor on textareas in the current page.
3322 * If a field name is provided, then it will only be
3323 * applied to that field - otherwise it will be used
3324 * on every textarea in the page.
3326 * In most cases no arguments need to be supplied
3328 * @param string $name Form element to replace with HTMl editor by name
3330 function use_html_editor($name='', $editorhidebuttons='') {
3331 $editor = 'editor_'.md5($name); //name might contain illegal characters
3332 echo '<script language="javascript" type="text/javascript" defer="defer">'."\n";
3333 echo "$editor = new HTMLArea('edit-$name');\n";
3334 echo "var config = $editor.config;\n";
3336 echo print_editor_config($editorhidebuttons);
3338 if (empty($name)) {
3339 echo "\nHTMLArea.replaceAll($editor.config);\n";
3340 } else {
3341 echo "\n$editor.generate();\n";
3343 echo '</script>'."\n";
3346 function print_editor_config($editorhidebuttons='', $return=false) {
3347 global $CFG;
3349 $str = "config.pageStyle = \"body {";
3351 if (!(empty($CFG->editorbackgroundcolor))) {
3352 $str .= " background-color: $CFG->editorbackgroundcolor;";
3355 if (!(empty($CFG->editorfontfamily))) {
3356 $str .= " font-family: $CFG->editorfontfamily;";
3359 if (!(empty($CFG->editorfontsize))) {
3360 $str .= " font-size: $CFG->editorfontsize;";
3363 $str .= " }\";\n";
3364 $str .= "config.killWordOnPaste = ";
3365 $str .= (empty($CFG->editorkillword)) ? "false":"true";
3366 $str .= ';'."\n";
3367 $str .= 'config.fontname = {'."\n";
3369 $fontlist = isset($CFG->editorfontlist) ? explode(';', $CFG->editorfontlist) : array();
3370 $i = 1; // Counter is used to get rid of the last comma.
3372 foreach ($fontlist as $fontline) {
3373 if (!empty($fontline)) {
3374 if ($i > 1) {
3375 $str .= ','."\n";
3377 list($fontkey, $fontvalue) = split(':', $fontline);
3378 $str .= '"'. $fontkey ."\":\t'". $fontvalue ."'";
3380 $i++;
3383 $str .= '};';
3385 if (!empty($editorhidebuttons)) {
3386 $str .= "\nconfig.hideSomeButtons(\" ". $editorhidebuttons ." \");\n";
3387 } else if (!empty($CFG->editorhidebuttons)) {
3388 $str .= "\nconfig.hideSomeButtons(\" ". $CFG->editorhidebuttons ." \");\n";
3391 if (!empty($CFG->editorspelling) && !empty($CFG->aspellpath)) {
3392 $str .= print_speller_code($usehtmleditor=true, true);
3395 if ($return) {
3396 return $str;
3398 echo $str;
3402 * Returns a turn edit on/off button for course in a self contained form.
3403 * Used to be an icon, but it's now a simple form button
3405 * @uses $CFG
3406 * @uses $USER
3407 * @param int $courseid The course to update by id as found in 'course' table
3408 * @return string
3410 function update_course_icon($courseid) {
3412 global $CFG, $USER;
3414 if (isteacheredit($courseid)) {
3415 if (!empty($USER->editing)) {
3416 $string = get_string('turneditingoff');
3417 $edit = '0';
3418 } else {
3419 $string = get_string('turneditingon');
3420 $edit = '1';
3422 return "<form target=\"$CFG->framename\" method=\"get\" action=\"$CFG->wwwroot/course/view.php\">".
3423 "<input type=\"hidden\" name=\"id\" value=\"$courseid\" />".
3424 "<input type=\"hidden\" name=\"edit\" value=\"$edit\" />".
3425 "<input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />".
3426 "<input type=\"submit\" value=\"$string\" /></form>";
3431 * Returns a turn student view on/off button for course in a self contained form.
3433 * @uses $CFG
3434 * @uses $USER
3435 * @param int $courseid The course to update by id as found in 'course' table
3436 * @return string
3438 function update_studentview_button($courseid) {
3440 global $CFG, $USER;
3442 if (isteacheredit($courseid,0,true)) {
3443 if (!empty($USER->studentview)) {
3444 $svstring = get_string('studentviewoff');
3445 $svedit = 'off';
3446 } else {
3447 $svstring = get_string('studentviewon');
3448 $svedit = 'on';
3450 $button = "<form target=\"$CFG->framename\" method=\"get\" action=\"$CFG->wwwroot/course/view.php\">".
3451 "<input type=\"hidden\" name=\"id\" value=\"$courseid\" />".
3452 "<input type=\"hidden\" name=\"studentview\" value=\"$svedit\" />".
3453 "<input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />".
3454 "<input type=\"submit\" value=\"$svstring\" /></form>";
3455 return $button;
3460 * Returns a turn edit on/off button for course in a self contained form.
3461 * Used to be an icon, but it's now a simple form button
3463 * @uses $CFG
3464 * @uses $USER
3465 * @param int $courseid The course to update by id as found in 'course' table
3466 * @return string
3468 function update_mymoodle_icon() {
3470 global $CFG, $USER;
3472 if (!empty($USER->editing)) {
3473 $string = get_string('updatemymoodleoff');
3474 $edit = '0';
3475 } else {
3476 $string = get_string('updatemymoodleon');
3477 $edit = '1';
3479 return "<form target=\"$CFG->framename\" method=\"get\" action=\"$CFG->wwwroot/my/index.php\">".
3480 "<input type=\"hidden\" name=\"edit\" value=\"$edit\" />".
3481 "<input type=\"submit\" value=\"$string\" /></form>";
3485 * Prints the editing button on a module "view" page
3487 * @uses $CFG
3488 * @param type description
3489 * @todo Finish documenting this function
3491 function update_module_button($moduleid, $courseid, $string) {
3492 global $CFG, $USER;
3494 // do not display if studentview is on
3495 if (!empty($USER->studentview)) {
3496 return '';
3499 if (isteacheredit($courseid)) {
3500 $string = get_string('updatethis', '', $string);
3501 return "<form target=\"$CFG->framename\" method=\"get\" action=\"$CFG->wwwroot/course/mod.php\">".
3502 "<input type=\"hidden\" name=\"update\" value=\"$moduleid\" />".
3503 "<input type=\"hidden\" name=\"return\" value=\"true\" />".
3504 "<input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />".
3505 "<input type=\"submit\" value=\"$string\" /></form>";
3506 } else {
3507 return '';
3512 * Prints the editing button on a category page
3514 * @uses $CFG
3515 * @uses $USER
3516 * @param int $categoryid ?
3517 * @return string
3518 * @todo Finish documenting this function
3520 function update_category_button($categoryid) {
3521 global $CFG, $USER;
3523 if (iscreator()) {
3524 if (!empty($USER->categoryediting)) {
3525 $string = get_string('turneditingoff');
3526 $edit = 'off';
3527 } else {
3528 $string = get_string('turneditingon');
3529 $edit = 'on';
3531 return "<form target=\"$CFG->framename\" method=\"get\" action=\"$CFG->wwwroot/course/category.php\">".
3532 "<input type=\"hidden\" name=\"id\" value=\"$categoryid\" />".
3533 "<input type=\"hidden\" name=\"edit\" value=\"$edit\" />".
3534 "<input type=\"hidden\" name=\"sesskey\" value=\"$USER->sesskey\" />".
3535 "<input type=\"submit\" value=\"$string\" /></form>";
3540 * Prints the editing button on categories listing
3542 * @uses $CFG
3543 * @uses $USER
3544 * @return string
3546 function update_categories_button() {
3547 global $CFG, $USER;
3549 if (isadmin()) {
3550 if (!empty($USER->categoryediting)) {
3551 $string = get_string('turneditingoff');
3552 $edit = 'off';
3553 } else {
3554 $string = get_string('turneditingon');
3555 $edit = 'on';
3557 return "<form target=\"$CFG->framename\" method=\"get\" action=\"$CFG->wwwroot/course/index.php\">".
3558 '<input type="hidden" name="edit" value="'. $edit .'" />'.
3559 '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />'.
3560 '<input type="submit" value="'. $string .'" /></form>';
3565 * Prints the editing button on search results listing
3566 * For bulk move courses to another category
3569 function update_categories_search_button($search,$page,$perpage) {
3570 global $CFG, $USER;
3572 if (isadmin()) {
3573 if (!empty($USER->categoryediting)) {
3574 $string = get_string("turneditingoff");
3575 $edit = "off";
3576 $perpage = 30;
3577 } else {
3578 $string = get_string("turneditingon");
3579 $edit = "on";
3581 return "<form target=\"$CFG->framename\" method=\"get\" action=\"$CFG->wwwroot/course/search.php\">".
3582 "<input type=\"hidden\" name=\"edit\" value=\"$edit\" />".
3583 "<input type=\"hidden\" name=\"sesskey\" value=\"$USER->sesskey\" />".
3584 "<input type=\"hidden\" name=\"search\" value=\"".s($search, true)."\" />".
3585 "<input type=\"hidden\" name=\"page\" value=\"$page\" />".
3586 "<input type=\"hidden\" name=\"perpage\" value=\"$perpage\" />".
3587 "<input type=\"submit\" value=\"".s($string)."\" /></form>";
3592 * Prints the editing button on group page
3594 * @uses $CFG
3595 * @uses $USER
3596 * @param int $courseid The course group is associated with
3597 * @param int $groupid The group to update
3598 * @return string
3600 function update_group_button($courseid, $groupid) {
3601 global $CFG, $USER;
3603 if (isteacheredit($courseid)) {
3604 $string = get_string('editgroupprofile');
3605 return "<form target=\"$CFG->framename\" method=\"get\" action=\"$CFG->wwwroot/course/group.php\">".
3606 '<input type="hidden" name="id" value="'. $courseid .'" />'.
3607 '<input type="hidden" name="group" value="'. $groupid .'" />'.
3608 '<input type="hidden" name="edit" value="on" />'.
3609 '<input type="submit" value="'. $string .'" /></form>';
3614 * Prints the editing button on groups page
3616 * @uses $CFG
3617 * @uses $USER
3618 * @param int $courseid The id of the course to be edited
3619 * @return string
3620 * @todo Finish documenting this function
3622 function update_groups_button($courseid) {
3623 global $CFG, $USER;
3625 if (isteacheredit($courseid)) {
3626 if (!empty($USER->groupsediting)) {
3627 $string = get_string('turneditingoff');
3628 $edit = 'off';
3629 } else {
3630 $string = get_string('turneditingon');
3631 $edit = 'on';
3633 return "<form target=\"$CFG->framename\" method=\"get\" action=\"$CFG->wwwroot/course/groups.php\">".
3634 "<input type=\"hidden\" name=\"id\" value=\"$courseid\" />".
3635 "<input type=\"hidden\" name=\"edit\" value=\"$edit\" />".
3636 "<input type=\"submit\" value=\"$string\" /></form>";
3641 * Prints an appropriate group selection menu
3643 * @uses VISIBLEGROUPS
3644 * @param array $groups ?
3645 * @param int $groupmode ?
3646 * @param string $currentgroup ?
3647 * @param string $urlroot ?
3648 * @param boolean $showall: if set to 0, it is a student in separate groups, do not display all participants
3649 * @todo Finish documenting this function
3651 function print_group_menu($groups, $groupmode, $currentgroup, $urlroot, $showall=1) {
3653 /// Add an "All groups" to the start of the menu
3654 if ($showall){
3655 $groupsmenu[0] = get_string('allparticipants');
3657 foreach ($groups as $key => $groupname) {
3658 $groupsmenu[$key] = $groupname;
3661 echo '<table><tr><td align="right">';
3662 if ($groupmode == VISIBLEGROUPS) {
3663 print_string('groupsvisible');
3664 } else {
3665 print_string('groupsseparate');
3667 echo ':';
3668 echo '</td><td nowrap="nowrap" align="left">';
3669 popup_form($urlroot.'&amp;group=', $groupsmenu, 'selectgroup', $currentgroup, '', '', '', false, 'self');
3670 echo '</td></tr></table>';
3675 * Given a course and a (current) coursemodule
3676 * This function returns a small popup menu with all the
3677 * course activity modules in it, as a navigation menu
3678 * The data is taken from the serialised array stored in
3679 * the course record
3681 * @param course $course A {@link $COURSE} object.
3682 * @param course $cm A {@link $COURSE} object.
3683 * @param string $targetwindow ?
3684 * @return string
3685 * @todo Finish documenting this function
3687 function navmenu($course, $cm=NULL, $targetwindow='self') {
3689 global $CFG, $THEME;
3691 if (empty($THEME->navmenuwidth)) {
3692 $width = 50;
3693 } else {
3694 $width = $THEME->navmenuwidth;
3697 if ($cm) {
3698 $cm = $cm->id;
3701 if ($course->format == 'weeks') {
3702 $strsection = get_string('week');
3703 } else {
3704 $strsection = get_string('topic');
3706 $strjumpto = get_string('jumpto');
3708 if (!$modinfo = unserialize($course->modinfo)) {
3709 return '';
3711 $isteacher = isteacher($course->id);
3712 $section = -1;
3713 $selected = '';
3714 $url = '';
3715 $previousmod = NULL;
3716 $backmod = NULL;
3717 $nextmod = NULL;
3718 $selectmod = NULL;
3719 $logslink = NULL;
3720 $flag = false;
3721 $menu = array();
3723 $sections = get_records('course_sections','course',$course->id,'section','section,visible,summary');
3725 if (!empty($THEME->makenavmenulist)) { /// A hack to produce an XHTML navmenu list for use in themes
3726 $THEME->navmenulist = navmenulist($course, $sections, $modinfo,
3727 $isteacher, $strsection, $strjumpto, $width, $cm);
3730 foreach ($modinfo as $mod) {
3731 if ($mod->mod == 'label') {
3732 continue;
3735 if ($mod->section > $course->numsections) { /// Don't show excess hidden sections
3736 break;
3739 if ($mod->section > 0 and $section <> $mod->section) {
3740 $thissection = $sections[$mod->section];
3742 if ($thissection->visible or !$course->hiddensections or $isteacher) {
3743 $thissection->summary = strip_tags(format_string($thissection->summary,true));
3744 if ($course->format == 'weeks' or empty($thissection->summary)) {
3745 $menu[] = '-------------- '. $strsection ." ". $mod->section .' --------------';
3746 } else {
3747 if (strlen($thissection->summary) < ($width-3)) {
3748 $menu[] = '-- '.$thissection->summary;
3749 } else {
3750 $menu[] = '-- '.substr($thissection->summary, 0, $width).'...';
3756 $section = $mod->section;
3758 //Only add visible or teacher mods to jumpmenu
3759 if ($mod->visible or $isteacher) {
3760 $url = $mod->mod .'/view.php?id='. $mod->cm;
3761 if ($flag) { // the current mod is the "next" mod
3762 $nextmod = $mod;
3763 $flag = false;
3765 if ($cm == $mod->cm) {
3766 $selected = $url;
3767 $selectmod = $mod;
3768 $backmod = $previousmod;
3769 $flag = true; // set flag so we know to use next mod for "next"
3770 $mod->name = $strjumpto;
3771 $strjumpto = '';
3772 } else {
3773 $mod->name = strip_tags(format_string(urldecode($mod->name),true));
3774 if (strlen($mod->name) > ($width+5)) {
3775 $mod->name = substr($mod->name, 0, $width).'...';
3777 if (!$mod->visible) {
3778 $mod->name = '('.$mod->name.')';
3781 $menu[$url] = $mod->name;
3782 $previousmod = $mod;
3785 if ($selectmod and $isteacher) {
3786 $logslink = "<td><a target=\"$CFG->framename\" href=".
3787 "\"$CFG->wwwroot/course/report/log/index.php?chooselog=1&amp;user=0&amp;date=0&amp;id=$course->id&amp;modid=$selectmod->cm\">".
3788 "<img border=\"0\" height=\"16\" width=\"16\" src=\"$CFG->pixpath/i/log.gif\" alt=\"\" /></a></td>";
3791 if ($backmod) {
3792 $backmod = "<form action=\"$CFG->wwwroot/mod/$backmod->mod/view.php\" target=\"$CFG->framename\">".
3793 "<input type=\"hidden\" name=\"id\" value=\"$backmod->cm\" />".
3794 "<input type=\"submit\" value=\"&lt;\" /></form>";
3796 if ($nextmod) {
3797 $nextmod = "<form action=\"$CFG->wwwroot/mod/$nextmod->mod/view.php\" target=\"$CFG->framename\">".
3798 "<input type=\"hidden\" name=\"id\" value=\"$nextmod->cm\" />".
3799 "<input type=\"submit\" value=\"&gt;\" /></form>";
3802 return '<table><tr>'.$logslink .'<td>'. $backmod .'</td><td>' .
3803 popup_form($CFG->wwwroot .'/mod/', $menu, 'navmenu', $selected, $strjumpto,
3804 '', '', true, $targetwindow).
3805 '</td><td>'. $nextmod .'</td></tr></table>';
3809 * Given a course
3810 * This function returns a small popup menu with all the
3811 * course activity modules in it, as a navigation menu
3812 * outputs a simple list structure in XHTML
3813 * The data is taken from the serialised array stored in
3814 * the course record
3816 * @param course $course A {@link $COURSE} object.
3817 * @return string
3818 * @todo Finish documenting this function
3820 function navmenulist($course, $sections, $modinfo, $isteacher, $strsection, $strjumpto, $width=50, $cmid=0) {
3822 global $CFG;
3824 $section = -1;
3825 $selected = '';
3826 $url = '';
3827 $previousmod = NULL;
3828 $backmod = NULL;
3829 $nextmod = NULL;
3830 $selectmod = NULL;
3831 $logslink = NULL;
3832 $flag = false;
3833 $menu = array();
3835 $menu[] = '<ul class="navmenulist"><li class="jumpto section"><span>'.$strjumpto.'</span><ul>';
3836 foreach ($modinfo as $mod) {
3837 if ($mod->mod == 'label') {
3838 continue;
3841 if ($mod->section > $course->numsections) { /// Don't show excess hidden sections
3842 break;
3845 if ($mod->section >= 0 and $section <> $mod->section) {
3846 $thissection = $sections[$mod->section];
3848 if ($thissection->visible or !$course->hiddensections or $isteacher) {
3849 $thissection->summary = strip_tags(format_string($thissection->summary,true));
3850 if (!empty($doneheading)) {
3851 $menu[] = '</ul></li>';
3853 if ($course->format == 'weeks' or empty($thissection->summary)) {
3854 $item = $strsection ." ". $mod->section;
3855 } else {
3856 if (strlen($thissection->summary) < ($width-3)) {
3857 $item = $thissection->summary;
3858 } else {
3859 $item = substr($thissection->summary, 0, $width).'...';
3862 $menu[] = '<li class="section"><span>'.$item.'</span>';
3863 $menu[] = '<ul>';
3864 $doneheading = true;
3868 $section = $mod->section;
3870 //Only add visible or teacher mods to jumpmenu
3871 if ($mod->visible or $isteacher) {
3872 $url = $mod->mod .'/view.php?id='. $mod->cm;
3873 if ($flag) { // the current mod is the "next" mod
3874 $nextmod = $mod;
3875 $flag = false;
3877 $mod->name = strip_tags(format_string(urldecode($mod->name),true));
3878 if (strlen($mod->name) > ($width+5)) {
3879 $mod->name = substr($mod->name, 0, $width).'...';
3881 if (!$mod->visible) {
3882 $mod->name = '('.$mod->name.')';
3884 $class = 'activity '.$mod->mod;
3885 $class .= ($cmid == $mod->cm) ? ' selected' : '';
3886 $menu[] = '<li class="'.$class.'">'.
3887 '<img src="'.$CFG->modpixpath.'/'.$mod->mod.'/icon.gif" border="0" />'.
3888 '<a href="'.$CFG->wwwroot.'/mod/'.$url.'">'.$mod->name.'</a></li>';
3889 $previousmod = $mod;
3892 if ($doneheading) {
3893 $menu[] = '</ul></li>';
3895 $menu[] = '</ul></li></ul>';
3897 return implode("\n", $menu);
3901 * Prints form items with the names $day, $month and $year
3903 * @param string $day fieldname
3904 * @param string $month fieldname
3905 * @param string $year fieldname
3906 * @param int $currenttime A default timestamp in GMT
3907 * @param boolean $return
3909 function print_date_selector($day, $month, $year, $currenttime=0, $return=false) {
3911 if (!$currenttime) {
3912 $currenttime = time();
3914 $currentdate = usergetdate($currenttime);
3916 for ($i=1; $i<=31; $i++) {
3917 $days[$i] = $i;
3919 for ($i=1; $i<=12; $i++) {
3920 $months[$i] = userdate(gmmktime(12,0,0,$i,1,2000), "%B");
3922 for ($i=1970; $i<=2020; $i++) {
3923 $years[$i] = $i;
3925 return choose_from_menu($days, $day, $currentdate['mday'], '', '', '0', $return)
3926 .choose_from_menu($months, $month, $currentdate['mon'], '', '', '0', $return)
3927 .choose_from_menu($years, $year, $currentdate['year'], '', '', '0', $return);
3932 *Prints form items with the names $hour and $minute
3934 * @param string $hour fieldname
3935 * @param string ? $minute fieldname
3936 * @param $currenttime A default timestamp in GMT
3937 * @param int $step minute spacing
3938 * @param boolean $return
3940 function print_time_selector($hour, $minute, $currenttime=0, $step=5, $return=false) {
3942 if (!$currenttime) {
3943 $currenttime = time();
3945 $currentdate = usergetdate($currenttime);
3946 if ($step != 1) {
3947 $currentdate['minutes'] = ceil($currentdate['minutes']/$step)*$step;
3949 for ($i=0; $i<=23; $i++) {
3950 $hours[$i] = sprintf("%02d",$i);
3952 for ($i=0; $i<=59; $i+=$step) {
3953 $minutes[$i] = sprintf("%02d",$i);
3956 return choose_from_menu($hours, $hour, $currentdate['hours'], '','','0',$return)
3957 .choose_from_menu($minutes, $minute, $currentdate['minutes'], '','','0',$return);
3961 * Prints time limit value selector
3963 * @uses $CFG
3964 * @param int $timelimit default
3965 * @param string $unit
3966 * @param string $name
3967 * @param boolean $return
3969 function print_timer_selector($timelimit = 0, $unit = '', $name = 'timelimit', $return=false) {
3971 global $CFG;
3973 if ($unit) {
3974 $unit = ' '.$unit;
3977 // Max timelimit is sessiontimeout - 10 minutes.
3978 $maxvalue = ($CFG->sessiontimeout / 60) - 10;
3980 for ($i=1; $i<=$maxvalue; $i++) {
3981 $minutes[$i] = $i.$unit;
3983 return choose_from_menu($minutes, $name, $timelimit, get_string('none'), '','','0',$return);
3987 * Prints a grade menu (as part of an existing form) with help
3988 * Showing all possible numerical grades and scales
3990 * @uses $CFG
3991 * @param int $courseid ?
3992 * @param string $name ?
3993 * @param string $current ?
3994 * @param boolean $includenograde ?
3995 * @todo Finish documenting this function
3997 function print_grade_menu($courseid, $name, $current, $includenograde=true) {
3999 global $CFG;
4001 $strscale = get_string('scale');
4002 $strscales = get_string('scales');
4004 $scales = get_scales_menu($courseid);
4005 foreach ($scales as $i => $scalename) {
4006 $grades[-$i] = $strscale .': '. $scalename;
4008 if ($includenograde) {
4009 $grades[0] = get_string('nograde');
4011 for ($i=100; $i>=1; $i--) {
4012 $grades[$i] = $i;
4014 choose_from_menu($grades, $name, $current, '');
4016 $linkobject = '<span class="helplink"><img height="17" width="17" alt="'.$strscales.'" src="'.$CFG->pixpath .'/help.gif" /></span>';
4017 link_to_popup_window ('/course/scales.php?id='. $courseid .'&amp;list=true', 'ratingscales',
4018 $linkobject, 400, 500, $strscales);
4022 * Prints a scale menu (as part of an existing form) including help button
4023 * Just like {@link print_grade_menu()} but without the numeric grades
4025 * @param int $courseid ?
4026 * @param string $name ?
4027 * @param string $current ?
4028 * @todo Finish documenting this function
4030 function print_scale_menu($courseid, $name, $current) {
4032 global $CFG;
4034 $strscales = get_string('scales');
4035 choose_from_menu(get_scales_menu($courseid), $name, $current, '');
4037 $linkobject = '<span class="helplink"><img height="17" width="17" alt="'.$strscales.'" src="'.$CFG->pixpath .'/help.gif" /></span>';
4038 link_to_popup_window ('/course/scales.php?id='. $courseid .'&amp;list=true', 'ratingscales',
4039 $linkobject, 400, 500, $strscales);
4043 * Prints a help button about a scale
4045 * @uses $CFG
4046 * @param id $courseid ?
4047 * @param object $scale ?
4048 * @todo Finish documenting this function
4050 function print_scale_menu_helpbutton($courseid, $scale) {
4052 global $CFG;
4054 $strscales = get_string('scales');
4056 $linkobject = '<span class="helplink"><img height="17" width="17" alt="'.$scale->name.'" src="'.$CFG->pixpath .'/help.gif" /></span>';
4057 link_to_popup_window ('/course/scales.php?id='. $courseid .'&amp;list=true&amp;scaleid='. $scale->id, 'ratingscale',
4058 $linkobject, 400, 500, $scale->name);
4062 * Print an error page displaying an error message.
4063 * Old method, don't call directly in new code - use print_error instead.
4066 * @uses $SESSION
4067 * @uses $CFG
4068 * @param string $message The message to display to the user about the error.
4069 * @param string $link The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page.
4071 function error ($message, $link='') {
4072 global $CFG, $SESSION;
4074 if (! defined('HEADER_PRINTED')) {
4075 //header not yet printed
4076 @header('HTTP/1.0 404 Not Found');
4077 print_header(get_string('error'));
4080 echo '<br />';
4082 $message = clean_text($message); // In case nasties are in here
4084 print_simple_box($message, '', '', '', '', 'errorbox');
4086 if (!$link) {
4087 if ( !empty($SESSION->fromurl) ) {
4088 $link = $SESSION->fromurl;
4089 unset($SESSION->fromurl);
4090 } else {
4091 $link = $CFG->wwwroot .'/';
4094 print_continue($link);
4095 print_footer();
4096 for ($i=0;$i<512;$i++) { // Padding to help IE work with 404
4097 echo ' ';
4099 die;
4103 * Print an error page displaying an error message. New method - use this for new code.
4105 * @uses $SESSION
4106 * @uses $CFG
4107 * @param string $errorcode The name of the string from error.php to print
4108 * @param string $link The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page.
4109 * @param object $a Extra words and phrases that might be required in the error string
4111 function print_error ($errorcode, $module='', $link='', $a=NULL) {
4113 global $CFG;
4115 if (empty($module) || $module == 'moodle' || $module == 'core') {
4116 $module = 'error';
4117 $modulelink = 'moodle';
4118 } else {
4119 $modulelink = $module;
4122 if (!empty($CFG->errordocroot)) {
4123 $errordocroot = $CFG->errordocroot;
4124 } else if (!empty($CFG->docroot)) {
4125 $errordocroot = $CFG->docroot;
4126 } else {
4127 $errordocroot = 'http://docs.moodle.org';
4130 $message = '<p class="errormessage">'.get_string($errorcode, $module, $a).'</p>'.
4131 '<p class="errorcode">'.
4132 '<a href="'.$errordocroot.'/en/error/'.$modulelink.'/'.$errorcode.'">'.
4133 get_string('moreinformation').'</a></p>';
4134 error($message, $link);
4139 * Print a help button.
4141 * @uses $CFG
4142 * @param string $page The keyword that defines a help page
4143 * @param string $title The title of links, rollover tips, alt tags etc
4144 * 'Help with' (or the language equivalent) will be prefixed and '...' will be stripped.
4145 * @param string $module Which module is the page defined in
4146 * @param mixed $image Use a help image for the link? (true/false/"both")
4147 * @param string $text If defined then this text is used in the page, and
4148 * the $page variable is ignored.
4149 * @param boolean $return If true then the output is returned as a string, if false it is printed to the current page.
4150 * @param string $imagetext The full text for the helpbutton icon. If empty use default help.gif
4151 * @return string
4152 * @todo Finish documenting this function
4154 function helpbutton ($page, $title='', $module='moodle', $image=true, $linktext=false, $text='', $return=false,
4155 $imagetext='') {
4156 global $CFG;
4158 if ($module == '') {
4159 $module = 'moodle';
4163 //Accessibility: prefix the alt text/title with 'Help with', strip distracting dots '...'
4164 // PLEASE DO NOT CHANGE. ('...' is VERY distracting for non-visual users)
4165 $tooltip = get_string('helpprefix', '', trim($title, ". \t"));
4167 $linkobject = '';
4169 if ($image) {
4170 if ($imagetext == '') {
4171 $imagetext = '<img alt="'.$tooltip.'" src="'.
4172 $CFG->pixpath .'/help.gif" />';
4174 if ($linktext) {
4175 $linkobject .= $title.'&nbsp;';
4178 $linkobject .= $imagetext;
4180 } else {
4181 $linkobject .= $tooltip;
4184 if ($text) {
4185 $url = '/help.php?module='. $module .'&amp;text='. s(urlencode($text));
4186 } else {
4187 $url = '/help.php?module='. $module .'&amp;file='. $page .'.html';
4190 $link = '<span class="helplink">'.
4191 link_to_popup_window ($url, 'popup', $linkobject, 400, 500, $tooltip, 'none', true).
4192 '</span>';
4194 if ($return) {
4195 return $link;
4196 } else {
4197 echo $link;
4202 * Print a help button.
4204 * Prints a special help button that is a link to the "live" emoticon popup
4205 * @uses $CFG
4206 * @uses $SESSION
4207 * @param string $form ?
4208 * @param string $field ?
4209 * @todo Finish documenting this function
4211 function emoticonhelpbutton($form, $field) {
4213 global $CFG, $SESSION;
4215 $SESSION->inserttextform = $form;
4216 $SESSION->inserttextfield = $field;
4217 $imagetext = '<img src="' . $CFG->pixpath . '/s/smiley.gif" border="0" align="middle" width="15" height="15" alt=""
4218 class="emoticon" style="margin-left: 7px" />';
4220 helpbutton('emoticons', get_string('helpemoticons'), 'moodle', true, true, '', false, $imagetext);
4224 * Print a message and exit.
4226 * @uses $CFG
4227 * @param string $message ?
4228 * @param string $link ?
4229 * @todo Finish documenting this function
4231 function notice ($message, $link='') {
4232 global $CFG;
4234 $message = clean_text($message);
4235 $link = clean_text($link);
4237 if (!$link) {
4238 if (!empty($_SERVER['HTTP_REFERER'])) {
4239 $link = $_SERVER['HTTP_REFERER'];
4240 } else {
4241 $link = $CFG->wwwroot .'/';
4245 echo '<br />';
4246 print_simple_box($message, 'center', '50%', '', '20', 'generalbox', 'notice');
4247 print_continue($link);
4248 print_footer(get_site());
4249 die;
4253 * Print a message along with "Yes" and "No" links for the user to continue.
4255 * @param string $message The text to display
4256 * @param string $linkyes The link to take the user to if they choose "Yes"
4257 * @param string $linkno The link to take the user to if they choose "No"
4259 function notice_yesno ($message, $linkyes, $linkno) {
4261 global $CFG;
4263 $message = clean_text($message);
4264 $linkyes = clean_text($linkyes);
4265 $linkno = clean_text($linkno);
4267 print_simple_box_start('center', '60%', '', 5, 'generalbox', 'notice');
4268 echo '<p align="center">'. $message .'</p>';
4269 echo '<table align="center" cellpadding="20"><tr><td>';
4270 print_single_button($linkyes, NULL, get_string('yes'), 'post', $CFG->framename);
4271 echo '</td><td>';
4272 print_single_button($linkno, NULL, get_string('no'), 'post', $CFG->framename);
4273 echo '</td></tr></table>';
4274 print_simple_box_end();
4278 * Redirects the user to another page, after printing a notice
4280 * @param string $url The url to take the user to
4281 * @param string $message The text message to display to the user about the redirect, if any
4282 * @param string $delay How long before refreshing to the new page at $url?
4283 * @todo '&' needs to be encoded into '&amp;' for XHTML compliance,
4284 * however, this is not true for javascript. Therefore we
4285 * first decode all entities in $url (since we cannot rely on)
4286 * the correct input) and then encode for where it's needed
4287 * echo "<script type='text/javascript'>alert('Redirect $url');</script>";
4289 function redirect($url, $message='', $delay=-1) {
4291 global $CFG;
4293 //$url = clean_text($url);
4294 if (!empty($CFG->usesid) && !isset($_COOKIE[session_name()])) {
4295 $url = sid_process_url($url);
4298 $message = clean_text($message);
4300 $url = html_entity_decode($url); // for php < 4.3.0 this is defined in moodlelib.php
4301 $url = str_replace(array("\n", "\r"), '', $url); // some more cleaning
4302 $encodedurl = htmlentities($url);
4303 $tmpstr = clean_text('<a href="'.$encodedurl.'" />'); //clean encoded URL
4304 $encodedurl = substr($tmpstr, 9, strlen($tmpstr)-13);
4305 $url = addslashes(html_entity_decode($encodedurl));
4307 /// when no message and header printed yet, try to redirect
4308 if (empty($message) and !defined('HEADER_PRINTED')) {
4309 if ($delay == -1) {
4310 $delay = 0;
4312 echo '<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />';
4313 echo '<script type="text/javascript">'. "\n" .'<!--'. "\n". "location.replace('$url');". "\n". '//-->'. "\n". '</script>'; // To cope with Mozilla bug
4314 die;
4317 if ($delay == -1) {
4318 $delay = 3; // if no delay specified wait 3 seconds
4320 if (! defined('HEADER_PRINTED')) {
4321 print_header('', '', '', '', '<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />');
4323 echo '<center>';
4324 echo '<p>'. $message .'</p>';
4325 echo '<p>( <a href="'. $encodedurl .'">'. get_string('continue') .'</a> )</p>';
4326 echo '</center>';
4329 <script type="text/javascript">
4330 <!--
4332 function redirect() {
4333 document.location.replace('<?php echo $url ?>');
4335 setTimeout("redirect()", <?php echo ($delay * 1000) ?>);
4337 </script>
4338 <?php
4339 die;
4343 * Print a bold message in an optional color.
4345 * @param string $message The message to print out
4346 * @param string $style Optional style to display message text in
4347 * @param string $align Alignment option
4348 * @param bool $return whether to return an output string or echo now
4350 function notify($message, $style='notifyproblem', $align='center', $return=false) {
4351 if ($style == 'green') {
4352 $style = 'notifysuccess'; // backward compatible with old color system
4355 $message = clean_text($message);
4357 $output = '<div class="'.$style.'" align="'. $align .'">'. $message .'</div>'."<br />\n";
4359 if ($return) {
4360 return $output;
4362 echo $output;
4367 * Given an email address, this function will return an obfuscated version of it
4369 * @param string $email The email address to obfuscate
4370 * @return string
4372 function obfuscate_email($email) {
4374 $i = 0;
4375 $length = strlen($email);
4376 $obfuscated = '';
4377 while ($i < $length) {
4378 if (rand(0,2)) {
4379 $obfuscated.='%'.dechex(ord($email{$i}));
4380 } else {
4381 $obfuscated.=$email{$i};
4383 $i++;
4385 return $obfuscated;
4389 * This function takes some text and replaces about half of the characters
4390 * with HTML entity equivalents. Return string is obviously longer.
4392 * @param string $plaintext The text to be obfuscated
4393 * @return string
4395 function obfuscate_text($plaintext) {
4397 $i=0;
4398 $length = strlen($plaintext);
4399 $obfuscated='';
4400 $prev_obfuscated = false;
4401 while ($i < $length) {
4402 $c = ord($plaintext{$i});
4403 $numerical = ($c >= ord('0')) && ($c <= ord('9'));
4404 if ($prev_obfuscated and $numerical ) {
4405 $obfuscated.='&#'.ord($plaintext{$i}).';';
4406 } else if (rand(0,2)) {
4407 $obfuscated.='&#'.ord($plaintext{$i}).';';
4408 $prev_obfuscated = true;
4409 } else {
4410 $obfuscated.=$plaintext{$i};
4411 $prev_obfuscated = false;
4413 $i++;
4415 return $obfuscated;
4419 * This function uses the {@link obfuscate_email()} and {@link obfuscate_text()}
4420 * to generate a fully obfuscated email link, ready to use.
4422 * @param string $email The email address to display
4423 * @param string $label The text to dispalyed as hyperlink to $email
4424 * @param boolean $dimmed If true then use css class 'dimmed' for hyperlink
4425 * @return string
4427 function obfuscate_mailto($email, $label='', $dimmed=false) {
4429 if (empty($label)) {
4430 $label = $email;
4432 if ($dimmed) {
4433 $title = get_string('emaildisable');
4434 $dimmed = ' class="dimmed"';
4435 } else {
4436 $title = '';
4437 $dimmed = '';
4439 return sprintf("<a href=\"%s:%s\" $dimmed title=\"$title\">%s</a>",
4440 obfuscate_text('mailto'), obfuscate_email($email),
4441 obfuscate_text($label));
4445 * Prints a single paging bar to provide access to other pages (usually in a search)
4447 * @param int $totalcount Thetotal number of entries available to be paged through
4448 * @param int $page The page you are currently viewing
4449 * @param int $perpage The number of entries that should be shown per page
4450 * @param string $baseurl The url which will be used to create page numbered links. Each page will consist of the base url appended by the page
4451 var an equal sign, then the page number.
4452 * @param string $pagevar This is the variable name that you use for the page number in your code (ie. 'tablepage', 'blogpage', etc)
4454 function print_paging_bar($totalcount, $page, $perpage, $baseurl, $pagevar='page',$nocurr=false) {
4456 $maxdisplay = 18;
4458 if ($totalcount > $perpage) {
4459 echo '<div class="paging">';
4460 echo get_string('page') .':';
4461 if ($page > 0) {
4462 $pagenum = $page - 1;
4463 echo '&nbsp;(<a href="'. $baseurl . $pagevar .'='. $pagenum .'">'. get_string('previous') .'</a>)&nbsp;';
4465 $lastpage = ceil($totalcount / $perpage);
4466 if ($page > 15) {
4467 $startpage = $page - 10;
4468 echo '&nbsp;<a href="'. $baseurl . $pagevar .'=0">1</a>&nbsp;...';
4469 } else {
4470 $startpage = 0;
4472 $currpage = $startpage;
4473 $displaycount = 0;
4474 while ($displaycount < $maxdisplay and $currpage < $lastpage) {
4475 $displaypage = $currpage+1;
4476 if ($page == $currpage && empty($nocurr)) {
4477 echo '&nbsp;&nbsp;'. $displaypage;
4478 } else {
4479 echo '&nbsp;&nbsp;<a href="'. $baseurl . $pagevar .'='. $currpage .'">'. $displaypage .'</a>';
4481 $displaycount++;
4482 $currpage++;
4484 if ($currpage < $lastpage) {
4485 $lastpageactual = $lastpage - 1;
4486 echo '&nbsp;...<a href="'. $baseurl . $pagevar .'='. $lastpageactual .'">'. $lastpage .'</a>&nbsp;';
4488 $pagenum = $page + 1;
4489 if ($pagenum != $displaypage) {
4490 echo '&nbsp;&nbsp;(<a href="'. $baseurl . $pagevar .'='. $pagenum .'">'. get_string('next') .'</a>)';
4492 echo '</div>';
4497 * This function is used to rebuild the <nolink> tag because some formats (PLAIN and WIKI)
4498 * will transform it to html entities
4500 * @param string $text Text to search for nolink tag in
4501 * @return string
4503 function rebuildnolinktag($text) {
4505 $text = preg_replace('/&lt;(\/*nolink)&gt;/i','<$1>',$text);
4507 return $text;
4511 * Prints a nice side block with an optional header. The content can either
4512 * be a block of HTML or a list of text with optional icons.
4514 * @param string $heading ?
4515 * @param string $content ?
4516 * @param array $list ?
4517 * @param array $icons ?
4518 * @param string $footer ?
4519 * @param array $attributes ?
4520 * @todo Finish documenting this function. Show example of various attributes, etc.
4522 function print_side_block($heading='', $content='', $list=NULL, $icons=NULL, $footer='', $attributes = array()) {
4524 //Accessibility: skip block link, with $block_id to differentiate links.
4525 static $block_id = 0;
4526 $block_id++;
4527 $skip_text = get_string('skipblock','access').' '.$block_id;
4528 $skip_link = '<a href="#sb-'.$block_id.'" class="skip-block" title="'.$skip_text.'"><span class="accesshide">'.$skip_text.'</span></a>';
4529 $skip_dest = '<span id="sb-'.$block_id.'" class="skip-block-to"></span>';
4530 if (! empty($heading)) {
4531 $heading .= $skip_link;
4532 } else {
4533 echo $skip_link;
4536 print_side_block_start($heading, $attributes);
4538 if ($content) {
4539 echo $content;
4540 if ($footer) {
4541 echo '<div class="footer">'. $footer .'</div>';
4543 } else {
4544 if ($list) {
4545 $row = 0;
4546 //Accessibility: replaced unnecessary table with list, see themes/standard/styles_layout.css
4547 echo "\n<ul class='list'>\n";
4548 foreach ($list as $key => $string) {
4549 echo '<li class="r'. $row .'">';
4550 if ($icons) {
4551 echo '<span class="icon c0">'. $icons[$key] .'</span>';
4553 echo '<span class="c1">'. $string .'</span>';
4554 echo "</li>\n";
4555 $row = $row ? 0:1;
4557 echo "</ul>\n";
4559 if ($footer) {
4560 echo '<div class="footer">'. $footer .'</div>';
4565 print_side_block_end($attributes);
4566 echo $skip_dest;
4570 * Starts a nice side block with an optional header.
4572 * @param string $heading ?
4573 * @param array $attributes ?
4574 * @todo Finish documenting this function
4576 function print_side_block_start($heading='', $attributes = array()) {
4578 global $CFG;
4580 // If there are no special attributes, give a default CSS class
4581 if (empty($attributes) || !is_array($attributes)) {
4582 $attributes = array('class' => 'sideblock');
4584 } else if(!isset($attributes['class'])) {
4585 $attributes['class'] = 'sideblock';
4587 } else if(!strpos($attributes['class'], 'sideblock')) {
4588 $attributes['class'] .= ' sideblock';
4591 // OK, the class is surely there and in addition to anything
4592 // else, it's tagged as a sideblock
4596 // IE misery: if I do it this way, blocks which start hidden cannot be "unhidden"
4598 // If there is a cookie to hide this thing, start it hidden
4599 if (!empty($attributes['id']) && isset($_COOKIE['hide:'.$attributes['id']])) {
4600 $attributes['class'] = 'hidden '.$attributes['class'];
4604 $attrtext = '';
4605 foreach ($attributes as $attr => $val) {
4606 $attrtext .= ' '.$attr.'="'.$val.'"';
4609 echo '<div '.$attrtext.'>';
4610 if ($heading) {
4611 //Accessibility: replaced <div> with H2; no, H2 more appropriate in moodleblock.class.php: _title_html.
4612 echo '<div class="header">'.$heading.'</div>';
4614 echo '<div class="content">';
4620 * Print table ending tags for a side block box.
4622 function print_side_block_end($attributes = array()) {
4623 global $CFG;
4625 echo '</div></div>';
4627 // IE workaround: if I do it THIS way, it works! WTF?
4628 if (!empty($CFG->allowuserblockhiding) && isset($attributes['id'])) {
4629 echo '<script type="text/javascript"><!-- '."\n".'elementCookieHide("'.$attributes['id'].'"); '."\n".'--></script>';
4636 * Prints out code needed for spellchecking.
4637 * Original idea by Ludo (Marc Alier).
4639 * @uses $CFG
4640 * @param boolean $usehtmleditor ?
4641 * @todo Finish documenting this function
4643 function print_speller_code ($usehtmleditor=false, $return=false) {
4644 global $CFG;
4645 $str = '';
4647 if(!$usehtmleditor) {
4648 $str .= "\n".'<script language="javascript" type="text/javascript">'."\n";
4649 $str .= 'function openSpellChecker() {'."\n";
4650 $str .= "\tvar speller = new spellChecker();\n";
4651 $str .= "\tspeller.popUpUrl = \"" . $CFG->wwwroot ."/lib/speller/spellchecker.html\";\n";
4652 $str .= "\tspeller.spellCheckScript = \"". $CFG->wwwroot ."/lib/speller/server-scripts/spellchecker.php\";\n";
4653 $str .= "\tspeller.spellCheckAll();\n";
4654 $str .= '}'."\n";
4655 $str .= '</script>'."\n";
4656 } else {
4657 $str .= "\nfunction spellClickHandler(editor, buttonId) {\n";
4658 $str .= "\teditor._textArea.value = editor.getHTML();\n";
4659 $str .= "\tvar speller = new spellChecker( editor._textArea );\n";
4660 $str .= "\tspeller.popUpUrl = \"" . $CFG->wwwroot ."/lib/speller/spellchecker.html\";\n";
4661 $str .= "\tspeller.spellCheckScript = \"". $CFG->wwwroot ."/lib/speller/server-scripts/spellchecker.php\";\n";
4662 $str .= "\tspeller._moogle_edit=1;\n";
4663 $str .= "\tspeller._editor=editor;\n";
4664 $str .= "\tspeller.openChecker();\n";
4665 $str .= '}'."\n";
4667 if ($return) {
4668 return $str;
4670 echo $str;
4674 * Print button for spellchecking when editor is disabled
4676 function print_speller_button () {
4677 echo '<input type="button" value="Check spelling" onclick="openSpellChecker();" />'."\n";
4681 function page_id_and_class(&$getid, &$getclass) {
4682 // Create class and id for this page
4683 global $CFG, $ME;
4685 static $class = NULL;
4686 static $id = NULL;
4688 if (empty($CFG->pagepath)) {
4689 $CFG->pagepath = $ME;
4692 if (empty($class) || empty($id)) {
4693 $path = str_replace($CFG->httpswwwroot.'/', '', $CFG->pagepath); //Because the page could be HTTPSPAGEREQUIRED
4694 $path = str_replace('.php', '', $path);
4695 if (substr($path, -1) == '/') {
4696 $path .= 'index';
4698 if (empty($path) || $path == 'index') {
4699 $id = 'site-index';
4700 $class = 'course';
4701 } else if (substr($path, 0, 5) == 'admin') {
4702 $id = str_replace('/', '-', $path);
4703 $class = 'admin';
4704 } else {
4705 $id = str_replace('/', '-', $path);
4706 $class = explode('-', $id);
4707 array_pop($class);
4708 $class = implode('-', $class);
4712 $getid = $id;
4713 $getclass = $class;
4717 * Prints a maintenance message from /maintenance.html
4719 function print_maintenance_message () {
4720 global $CFG, $SITE;
4722 print_header(strip_tags($SITE->fullname), $SITE->fullname, 'home');
4723 print_simple_box_start('center');
4724 print_heading(get_string('sitemaintenance', 'admin'));
4725 @include($CFG->dataroot.'/1/maintenance.html');
4726 print_simple_box_end();
4727 print_footer();
4731 * Adjust the list of allowed tags based on $CFG->allowobjectembed and user roles (admin)
4733 function adjust_allowed_tags() {
4735 global $CFG, $ALLOWED_TAGS;
4737 if (!empty($CFG->allowobjectembed)) {
4738 $ALLOWED_TAGS .= '<embed><object>';
4742 /// Some code to print tabs
4744 /// A class for tabs
4745 class tabobject {
4746 var $id;
4747 var $link;
4748 var $text;
4749 var $linkedwhenselected;
4751 /// A constructor just because I like constructors
4752 function tabobject ($id, $link='', $text='', $title='', $linkedwhenselected=false) {
4753 $this->id = $id;
4754 $this->link = $link;
4755 $this->text = $text;
4756 $this->title = $title ? $title : $text;
4757 $this->linkedwhenselected = $linkedwhenselected;
4761 /// a method to look after the messy business of setting up a tab cell
4762 /// with all the appropriate classes and things
4763 function createtab ($selected=false, $inactive=false, $activetwo=false, $last=false) {
4764 $str = '';
4765 $astr = '';
4766 $cstr = '';
4768 /// The text and anchor for this tab
4769 if ($inactive || $activetwo || ($selected && !$this->linkedwhenselected)) {
4770 $astr .= $this->text;
4771 } else {
4772 $astr .= '<a href="'.$this->link.'" title="'.$this->title.'">'.$this->text.'</a>';
4775 /// There's an IE bug with background images in <a> tags
4776 /// so we put a div around so that we can add a background image
4777 $astr = '<div class="tablink">'.$astr.'</div>';
4779 /// Set the class for inactive cells
4780 if ($inactive) {
4781 $cstr .= ' inactive';
4783 /// Set the class for active cells in the second row
4784 if ($activetwo) {
4785 $cstr .= ' activetwo';
4788 /// Set the class for the selected cell
4789 } else if ($selected) {
4790 $cstr .= ' selected';
4792 /// Set the standard class for a cell
4793 } else {
4794 $cstr .= ' active';
4798 /// Are we on the last tab in this row?
4799 if ($last) {
4800 $astr = '<div class="last">'.$astr.'</div>';
4803 /// Lets set up the tab cell
4804 $str .= '<td';
4805 if (!empty($cstr)) {
4806 $str .= ' class="'.ltrim($cstr).'"';
4808 $str .= '>';
4809 $str .= $astr;
4810 $str .= '</td>';
4812 return $str;
4820 * Returns a string containing a table with tabs inside and formatted with
4821 * CSS styles.
4823 * @param array $tabrows An array of rows where each row is an array of tab objects
4824 * @param string $selected The id of the selected tab
4825 * @param array $inactive Ids of inactive tabs
4827 function print_tabs($tabrows, $selected=NULL, $inactive=NULL, $activetwo=NULL, $return=false) {
4828 global $CFG;
4830 /// Bring the row with the selected tab to the front
4831 if (!empty($CFG->tabselectedtofront) and ($selected !== NULL) ) {
4832 $found = false;
4833 $frontrows = array();
4834 $rearrows = array();
4835 foreach ($tabrows as $row) {
4836 if ($found) {
4837 $rearrows[] = $row;
4838 } else {
4839 foreach ($row as $tab) {
4840 if ($found) {
4841 continue;
4843 $found = ($selected == $tab->id);
4845 $frontrows[] = $row;
4848 $tabrows = array_merge($rearrows,$frontrows);
4851 /// $inactive must be an array
4852 if (!is_array($inactive)) {
4853 $inactive = array();
4856 /// $activetwo must be an array
4857 if (!is_array($activetwo)) {
4858 $activetwo = array();
4861 /// A table to encapsulate the tabs
4862 $str = '<table class="tabs" cellspacing="0">';
4863 $str .= '<tr><td class="left side"></td><td>';
4865 $rowcount = count($tabrows);
4866 /// Cycle through the tab rows
4867 foreach ($tabrows as $row) {
4869 $rowcount--;
4871 $str .= '<table class="tabrow r'.$rowcount.'" cellspacing="0">';
4872 $str .= '<tr>';
4874 $numberoftabs = count($row);
4875 $currenttab = 0;
4876 $cstr = '';
4877 $astr = '';
4880 /// Cycle through the tabs
4881 foreach ($row as $tab) {
4882 $currenttab++;
4884 $str .= $tab->createtab( ($selected == $tab->id), (in_array($tab->id, $inactive)), (in_array($tab->id, $activetwo)), ($currenttab == $numberoftabs) );
4887 $str .= '</tr>';
4888 $str .= '</table>';
4890 $str .= '</td><td class="right side"></td></tr>';
4891 $str .= '</table>';
4893 if ($return) {
4894 return $str;
4896 echo $str;
4901 * Returns a string containing a link to the user documentation for the current
4902 * page. Also contains an icon by default. Shown to teachers and admin only.
4904 * @param string $text The text to be displayed for the link
4905 * @param string $iconpath The path to the icon to be displayed
4907 function page_doc_link($text='', $iconpath='') {
4908 global $ME, $CFG;
4910 if (empty($CFG->docroot) || !isteacherinanycourse()) {
4911 return '';
4914 if (empty($CFG->pagepath)) {
4915 $CFG->pagepath = $ME;
4918 $target = '';
4919 if (!empty($CFG->doctonewwindow)) {
4920 $target = ' target="_blank"';
4923 $path = str_replace($CFG->httpswwwroot.'/','', $CFG->pagepath); // Because the page could be HTTPSPAGEREQUIRED
4924 $path = str_replace('.php', '', $path);
4926 if (empty($path)) { // Not for home page
4927 return '';
4930 $lang = str_replace('_utf8', '', current_language());
4932 $str = '<a href="' .$CFG->docroot. '/' .$lang. '/' .$path. '"' .$target. '>';
4934 if (empty($iconpath)) {
4935 $iconpath = $CFG->wwwroot . '/pix/docs.gif';
4938 $str .= '<img src="' .$iconpath. '" alt="Docs" />' .$text. '</a>';
4940 return $str;
4944 // vim:autoindent:expandtab:shiftwidth=4:tabstop=4:tw=140: