3 ///////////////////////////////////////////////////////////////////////////
5 // NOTICE OF COPYRIGHT //
7 // Moodle - Modular Object-Oriented Dynamic Learning Environment //
8 // http://moodle.com //
10 // Copyright (C) 2001-2003 Martin Dougiamas http://dougiamas.com //
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. //
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: //
22 // http://www.gnu.org/copyleft/gpl.html //
24 ///////////////////////////////////////////////////////////////////////////
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
37 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
41 /// We are going to uses filterlib functions here
42 require_once("$CFG->libdir/filterlib.php");
44 require_once("$CFG->libdir/ajax/ajaxlib.php");
48 /// Define text formatting types ... eventually we can add Wiki, BBcode etc
51 * Does all sorts of transformations and filtering
53 define('FORMAT_MOODLE', '0'); // Does all sorts of transformations and filtering
56 * Plain HTML (with some tags stripped)
58 define('FORMAT_HTML', '1'); // Plain HTML (with some tags stripped)
61 * Plain text (even tags are printed in full)
63 define('FORMAT_PLAIN', '2'); // Plain text (even tags are printed in full)
67 * Deprecated: left here just to note that '3' is not used (at the moment)
68 * and to catch any latent wiki-like text (which generates an error)
70 define('FORMAT_WIKI', '3'); // Wiki-formatted text
73 * Markdown-formatted text http://daringfireball.net/projects/markdown/
75 define('FORMAT_MARKDOWN', '4'); // Markdown-formatted text http://daringfireball.net/projects/markdown/
78 * TRUSTTEXT marker - if present in text, text cleaning should be bypassed
80 define('TRUSTTEXT', '#####TRUSTTEXT#####');
84 * Allowed tags - string of html tags that can be tested against for safe html tags
85 * @global string $ALLOWED_TAGS
88 '<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>';
91 * Allowed protocols - array of protocols that are safe to use in links and so on
92 * @global string $ALLOWED_PROTOCOLS
94 $ALLOWED_PROTOCOLS = array('http', 'https', 'ftp', 'news', 'mailto', 'rtsp', 'teamspeak', 'gopher', 'mms',
95 'color', 'callto', 'cursor', 'text-align', 'font-size', 'font-weight', 'font-style',
96 'border', 'margin', 'padding', 'background'); // CSS as well to get through kses
102 * Add quotes to HTML characters
104 * Returns $var with HTML characters (like "<", ">", etc.) properly quoted.
105 * This function is very similar to {@link p()}
107 * @param string $var the string potentially containing HTML characters
108 * @param boolean $strip to decide if we want to strip slashes or no. Default to false.
109 * true should be used to print data from forms and false for data from DB.
112 function s($var, $strip=false) {
114 if ($var == '0') { // for integer 0, boolean false, string '0'
119 return preg_replace("/&(#\d+);/i", "&$1;", htmlspecialchars(stripslashes_safe($var)));
121 return preg_replace("/&(#\d+);/i", "&$1;", htmlspecialchars($var));
126 * Add quotes to HTML characters
128 * Prints $var with HTML characters (like "<", ">", etc.) properly quoted.
129 * This function is very similar to {@link s()}
131 * @param string $var the string potentially containing HTML characters
132 * @param boolean $strip to decide if we want to strip slashes or no. Default to false.
133 * true should be used to print data from forms and false for data from DB.
136 function p($var, $strip=false) {
137 echo s($var, $strip);
141 * Does proper javascript quoting.
142 * Do not use addslashes anymore, because it does not work when magic_quotes_sybase is enabled.
144 * @since 1.8 - 22/02/2007
146 * @return mixed quoted result
148 function addslashes_js($var) {
149 if (is_string($var)) {
150 $var = str_replace('\\', '\\\\', $var);
151 $var = str_replace(array('\'', '"', "\n", "\r", "\0"), array('\\\'', '\\"', '\\n', '\\r', '\\0'), $var);
152 $var = str_replace('</', '<\/', $var); // XHTML compliance
153 } else if (is_array($var)) {
154 $var = array_map('addslashes_js', $var);
155 } else if (is_object($var)) {
156 $a = get_object_vars($var);
157 foreach ($a as $key=>$value) {
158 $a[$key] = addslashes_js($value);
166 * Remove query string from url
168 * Takes in a URL and returns it without the querystring portion
170 * @param string $url the url which may have a query string attached
173 function strip_querystring($url) {
175 if ($commapos = strpos($url, '?')) {
176 return substr($url, 0, $commapos);
183 * Returns the URL of the HTTP_REFERER, less the querystring portion if required
186 function get_referer($stripquery=true) {
187 if (isset($_SERVER['HTTP_REFERER'])) {
189 return strip_querystring($_SERVER['HTTP_REFERER']);
191 return $_SERVER['HTTP_REFERER'];
200 * Returns the name of the current script, WITH the querystring portion.
201 * this function is necessary because PHP_SELF and REQUEST_URI and SCRIPT_NAME
202 * return different things depending on a lot of things like your OS, Web
203 * server, and the way PHP is compiled (ie. as a CGI, module, ISAPI, etc.)
204 * <b>NOTE:</b> This function returns false if the global variables needed are not set.
210 if (!empty($_SERVER['REQUEST_URI'])) {
211 return $_SERVER['REQUEST_URI'];
213 } else if (!empty($_SERVER['PHP_SELF'])) {
214 if (!empty($_SERVER['QUERY_STRING'])) {
215 return $_SERVER['PHP_SELF'] .'?'. $_SERVER['QUERY_STRING'];
217 return $_SERVER['PHP_SELF'];
219 } else if (!empty($_SERVER['SCRIPT_NAME'])) {
220 if (!empty($_SERVER['QUERY_STRING'])) {
221 return $_SERVER['SCRIPT_NAME'] .'?'. $_SERVER['QUERY_STRING'];
223 return $_SERVER['SCRIPT_NAME'];
225 } else if (!empty($_SERVER['URL'])) { // May help IIS (not well tested)
226 if (!empty($_SERVER['QUERY_STRING'])) {
227 return $_SERVER['URL'] .'?'. $_SERVER['QUERY_STRING'];
229 return $_SERVER['URL'];
232 notify('Warning: Could not find any of these web server variables: $REQUEST_URI, $PHP_SELF, $SCRIPT_NAME or $URL');
238 * Like {@link me()} but returns a full URL
242 function qualified_me() {
246 if (!empty($CFG->wwwroot
)) {
247 $url = parse_url($CFG->wwwroot
);
250 if (!empty($url['host'])) {
251 $hostname = $url['host'];
252 } else if (!empty($_SERVER['SERVER_NAME'])) {
253 $hostname = $_SERVER['SERVER_NAME'];
254 } else if (!empty($_ENV['SERVER_NAME'])) {
255 $hostname = $_ENV['SERVER_NAME'];
256 } else if (!empty($_SERVER['HTTP_HOST'])) {
257 $hostname = $_SERVER['HTTP_HOST'];
258 } else if (!empty($_ENV['HTTP_HOST'])) {
259 $hostname = $_ENV['HTTP_HOST'];
261 notify('Warning: could not find the name of this server!');
265 if (!empty($url['port'])) {
266 $hostname .= ':'.$url['port'];
267 } else if (!empty($_SERVER['SERVER_PORT'])) {
268 if ($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
269 $hostname .= ':'.$_SERVER['SERVER_PORT'];
273 if (isset($_SERVER['HTTPS'])) {
274 $protocol = ($_SERVER['HTTPS'] == 'on') ?
'https://' : 'http://';
275 } else if (isset($_SERVER['SERVER_PORT'])) { # Apache2 does not export $_SERVER['HTTPS']
276 $protocol = ($_SERVER['SERVER_PORT'] == '443') ?
'https://' : 'http://';
278 $protocol = 'http://';
281 $url_prefix = $protocol.$hostname;
282 return $url_prefix . me();
286 * Determine if there is data waiting to be processed from a form
288 * Used on most forms in Moodle to check for data
289 * Returns the data as an object, if it's found.
290 * This object can be used in foreach loops without
291 * casting because it's cast to (array) automatically
293 * Checks that submitted POST data exists and returns it as object.
295 * @param string $url not used anymore
296 * @return mixed false or object
298 function data_submitted($url='') {
303 return (object)$_POST;
308 * Moodle replacement for php stripslashes() function,
309 * works also for objects and arrays.
311 * The standard php stripslashes() removes ALL backslashes
312 * even from strings - so C:\temp becomes C:temp - this isn't good.
313 * This function should work as a fairly safe replacement
314 * to be called on quoted AND unquoted strings (to be sure)
316 * @param mixed something to remove unsafe slashes from
319 function stripslashes_safe($mixed) {
320 // there is no need to remove slashes from int, float and bool types
323 } else if (is_string($mixed)) {
324 if (ini_get_bool('magic_quotes_sybase')) { //only unescape single quotes
325 $mixed = str_replace("''", "'", $mixed);
326 } else { //the rest, simple and double quotes and backslashes
327 $mixed = str_replace("\\'", "'", $mixed);
328 $mixed = str_replace('\\"', '"', $mixed);
329 $mixed = str_replace('\\\\', '\\', $mixed);
331 } else if (is_array($mixed)) {
332 foreach ($mixed as $key => $value) {
333 $mixed[$key] = stripslashes_safe($value);
335 } else if (is_object($mixed)) {
336 $vars = get_object_vars($mixed);
337 foreach ($vars as $key => $value) {
338 $mixed->$key = stripslashes_safe($value);
346 * Recursive implementation of stripslashes()
348 * This function will allow you to strip the slashes from a variable.
349 * If the variable is an array or object, slashes will be stripped
350 * from the items (or properties) it contains, even if they are arrays
351 * or objects themselves.
353 * @param mixed the variable to remove slashes from
356 function stripslashes_recursive($var) {
357 if(is_object($var)) {
358 $properties = get_object_vars($var);
359 foreach($properties as $property => $value) {
360 $var->$property = stripslashes_recursive($value);
363 else if(is_array($var)) {
364 foreach($var as $property => $value) {
365 $var[$property] = stripslashes_recursive($value);
368 else if(is_string($var)) {
369 $var = stripslashes($var);
375 * Recursive implementation of addslashes()
377 * This function will allow you to add the slashes from a variable.
378 * If the variable is an array or object, slashes will be added
379 * to the items (or properties) it contains, even if they are arrays
380 * or objects themselves.
382 * @param mixed the variable to add slashes from
385 function addslashes_recursive($var) {
386 if(is_object($var)) {
387 $properties = get_object_vars($var);
388 foreach($properties as $property => $value) {
389 $var->$property = addslashes_recursive($value);
392 else if(is_array($var)) {
393 foreach($var as $property => $value) {
394 $var[$property] = addslashes_recursive($value);
397 else if(is_string($var)) {
398 $var = addslashes($var);
404 * Given some normal text this function will break up any
405 * long words to a given size by inserting the given character
407 * It's multibyte savvy and doesn't change anything inside html tags.
409 * @param string $string the string to be modified
410 * @param int $maxsize maximum length of the string to be returned
411 * @param string $cutchar the string used to represent word breaks
414 function break_up_long_words($string, $maxsize=20, $cutchar=' ') {
416 /// Loading the textlib singleton instance. We are going to need it.
417 $textlib = textlib_get_instance();
419 /// First of all, save all the tags inside the text to skip them
421 filter_save_tags($string,$tags);
423 /// Process the string adding the cut when necessary
425 $length = $textlib->strlen($string);
428 for ($i=0; $i<$length; $i++
) {
429 $char = $textlib->substr($string, $i, 1);
430 if ($char == ' ' or $char == "\t" or $char == "\n" or $char == "\r" or $char == "<" or $char == ">") {
434 if ($wordlength > $maxsize) {
442 /// Finally load the tags back again
444 $output = str_replace(array_keys($tags), $tags, $output);
451 * This does a search and replace, ignoring case
452 * This function is only used for versions of PHP older than version 5
453 * which do not have a native version of this function.
454 * Taken from the PHP manual, by bradhuizenga @ softhome.net
456 * @param string $find the string to search for
457 * @param string $replace the string to replace $find with
458 * @param string $string the string to search through
461 if (!function_exists('str_ireplace')) { /// Only exists in PHP 5
462 function str_ireplace($find, $replace, $string) {
464 if (!is_array($find)) {
465 $find = array($find);
468 if(!is_array($replace)) {
469 if (!is_array($find)) {
470 $replace = array($replace);
472 // this will duplicate the string into an array the size of $find
476 for ($i = 0; $i < $c; $i++
) {
477 $replace[$i] = $rString;
482 foreach ($find as $fKey => $fItem) {
483 $between = explode(strtolower($fItem),strtolower($string));
485 foreach($between as $bKey => $bItem) {
486 $between[$bKey] = substr($string,$pos,strlen($bItem));
487 $pos +
= strlen($bItem) +
strlen($fItem);
489 $string = implode($replace[$fKey],$between);
496 * Locate the position of a string in another string
498 * This function is only used for versions of PHP older than version 5
499 * which do not have a native version of this function.
500 * Taken from the PHP manual, by dmarsh @ spscc.ctc.edu
502 * @param string $haystack The string to be searched
503 * @param string $needle The string to search for
504 * @param int $offset The position in $haystack where the search should begin.
506 if (!function_exists('stripos')) { /// Only exists in PHP 5
507 function stripos($haystack, $needle, $offset=0) {
509 return strpos(strtoupper($haystack), strtoupper($needle), $offset);
514 * This function will create a HTML link that will work on both
515 * Javascript and non-javascript browsers.
516 * Relies on the Javascript function openpopup in javascript.php
518 * $url must be relative to home page eg /mod/survey/stuff.php
519 * @param string $url Web link relative to home page
520 * @param string $name Name to be assigned to the popup window
521 * @param string $linkname Text to be displayed as web link
522 * @param int $height Height to assign to popup window
523 * @param int $width Height to assign to popup window
524 * @param string $title Text to be displayed as popup page title
525 * @param string $options List of additional options for popup window
526 * @todo Add code examples and list of some options that might be used.
527 * @param boolean $return Should the link to the popup window be returned as a string (true) or printed immediately (false)?
531 function link_to_popup_window ($url, $name='popup', $linkname='click here',
532 $height=400, $width=500, $title='Popup window',
533 $options='none', $return=false) {
537 if ($options == 'none') {
538 $options = 'menubar=0,location=0,scrollbars,resizable,width='. $width .',height='. $height;
542 if (!(strpos($url,$CFG->wwwroot
) === false)) { // some log url entries contain _SERVER[HTTP_REFERRER] in which case wwwroot is already there.
543 $url = substr($url, strlen($CFG->wwwroot
));
546 $link = '<a title="'. s($title) .'" href="'. $CFG->wwwroot
. $url .'" '.
547 "onclick=\"this.target='$name'; return openpopup('$url', '$name', '$options', $fullscreen);\">$linkname</a>";
556 * This function will print a button submit form element
557 * that will work on both Javascript and non-javascript browsers.
558 * Relies on the Javascript function openpopup in javascript.php
560 * $url must be relative to home page eg /mod/survey/stuff.php
561 * @param string $url Web link relative to home page
562 * @param string $name Name to be assigned to the popup window
563 * @param string $linkname Text to be displayed as web link
564 * @param int $height Height to assign to popup window
565 * @param int $width Height to assign to popup window
566 * @param string $title Text to be displayed as popup page title
567 * @param string $options List of additional options for popup window
568 * @param string $return If true, return as a string, otherwise print
572 function button_to_popup_window ($url, $name='popup', $linkname='click here',
573 $height=400, $width=500, $title='Popup window', $options='none', $return=false,
578 if ($options == 'none') {
579 $options = 'menubar=0,location=0,scrollbars,resizable,width='. $width .',height='. $height;
583 $id = ' id="'.$id.'" ';
586 $class = ' class="'.$class.'" ';
590 $button = '<input type="button" name="'.$name.'" title="'. $title .'" value="'. $linkname .' ..." '.$id.$class.
591 "onclick=\"return openpopup('$url', '$name', '$options', $fullscreen);\" />\n";
601 * Prints a simple button to close a window
603 function close_window_button($name='closewindow', $return=false) {
608 $output .= '<div class="closewindow">' . "\n";
609 $output .= '<form action="'.$CFG->wwwroot
.'"><div>'; // We don't use this
610 $output .= '<input type="button" onclick="self.close();" value="'.get_string($name).'" />';
611 $output .= '</div></form>';
612 $output .= '</div>' . "\n";
622 * Try and close the current window immediately using Javascript
624 function close_window($delay=0) {
626 <script type
="text/javascript">
628 function close_this_window() {
631 setTimeout("close_this_window()", <?php
echo $delay * 1000 ?
>);
635 <?php
print_string('pleaseclose') ?
>
643 * Given an array of value, creates a popup menu to be part of a form
644 * $options["value"]["label"]
646 * @param type description
647 * @todo Finish documenting this function
649 function choose_from_menu ($options, $name, $selected='', $nothing='choose', $script='',
650 $nothingvalue='0', $return=false, $disabled=false, $tabindex=0, $id='') {
652 if ($nothing == 'choose') {
653 $nothing = get_string('choose') .'...';
656 $attributes = ($script) ?
'onchange="'. $script .'"' : '';
658 $attributes .= ' disabled="disabled"';
662 $attributes .= ' tabindex="'.$tabindex.'"';
667 // name may contaion [], which would make an invalid id. e.g. numeric question type editing form, assignment quickgrading
668 $id = str_replace('[', '', $id);
669 $id = str_replace(']', '', $id);
672 $output = '<select id="'.$id.'" name="'. $name .'" '. $attributes .'>' . "\n";
674 $output .= ' <option value="'. s($nothingvalue) .'"'. "\n";
675 if ($nothingvalue === $selected) {
676 $output .= ' selected="selected"';
678 $output .= '>'. $nothing .'</option>' . "\n";
680 if (!empty($options)) {
681 foreach ($options as $value => $label) {
682 $output .= ' <option value="'. s($value) .'"';
683 if ((string)$value == (string)$selected) {
684 $output .= ' selected="selected"';
687 $output .= '>'. $value .'</option>' . "\n";
689 $output .= '>'. $label .'</option>' . "\n";
693 $output .= '</select>' . "\n";
703 * Choose value 0 or 1 from a menu with options 'No' and 'Yes'.
704 * Other options like choose_from_menu.
706 function choose_from_menu_yesno($name, $selected, $script = '',
707 $return = false, $disabled = false, $tabindex = 0) {
708 return choose_from_menu(array(get_string('no'), get_string('yes')), $name,
709 $selected, '', $script, '0', $return, $disabled, $tabindex);
713 * Just like choose_from_menu, but takes a nested array (2 levels) and makes a dropdown menu
714 * including option headings with the first level.
716 function choose_from_menu_nested($options,$name,$selected='',$nothing='choose',$script = '',
717 $nothingvalue=0,$return=false,$disabled=false,$tabindex=0) {
719 if ($nothing == 'choose') {
720 $nothing = get_string('choose') .'...';
723 $attributes = ($script) ?
'onchange="'. $script .'"' : '';
725 $attributes .= ' disabled="disabled"';
729 $attributes .= ' tabindex="'.$tabindex.'"';
732 $output = '<select id="menu'.$name.'" name="'. $name .'" '. $attributes .'>' . "\n";
734 $output .= ' <option value="'. $nothingvalue .'"'. "\n";
735 if ($nothingvalue === $selected) {
736 $output .= ' selected="selected"';
738 $output .= '>'. $nothing .'</option>' . "\n";
740 if (!empty($options)) {
741 foreach ($options as $section => $values) {
743 $output .= ' <optgroup label="'. s(format_string($section)) .'">'."\n";
744 foreach ($values as $value => $label) {
745 $output .= ' <option value="'. format_string($value) .'"';
746 if ((string)$value == (string)$selected) {
747 $output .= ' selected="selected"';
750 $output .= '>'. $value .'</option>' . "\n";
752 $output .= '>'. $label .'</option>' . "\n";
755 $output .= ' </optgroup>'."\n";
758 $output .= '</select>' . "\n";
769 * Given an array of values, creates a group of radio buttons to be part of a form
771 * @param array $options An array of value-label pairs for the radio group (values as keys)
772 * @param string $name Name of the radiogroup (unique in the form)
773 * @param string $checked The value that is already checked
775 function choose_from_radio ($options, $name, $checked='', $return=false) {
777 static $idcounter = 0;
783 $output = '<span class="radiogroup '.$name."\">\n";
785 if (!empty($options)) {
787 foreach ($options as $value => $label) {
788 $htmlid = 'auto-rb'.sprintf('%04d', ++
$idcounter);
789 $output .= ' <span class="radioelement '.$name.' rb'.$currentradio."\">";
790 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="radio" value="'.$value.'"';
791 if ($value == $checked) {
792 $output .= ' checked="checked"';
795 $output .= ' /> <label for="'.$htmlid.'">'. $value .'</label></span>' . "\n";
797 $output .= ' /> <label for="'.$htmlid.'">'. $label .'</label></span>' . "\n";
799 $currentradio = ($currentradio +
1) %
2;
803 $output .= '</span>' . "\n";
812 /** Display an standard html checkbox with an optional label
814 * @param string $name The name of the checkbox
815 * @param string $value The valus that the checkbox will pass when checked
816 * @param boolean $checked The flag to tell the checkbox initial state
817 * @param string $label The label to be showed near the checkbox
818 * @param string $alt The info to be inserted in the alt tag
820 function print_checkbox ($name, $value, $checked = true, $label = '', $alt = '', $script='',$return=false) {
822 static $idcounter = 0;
829 $alt = strip_tags($alt);
835 $strchecked = ' checked="checked"';
840 $htmlid = 'auto-cb'.sprintf('%04d', ++
$idcounter);
841 $output = '<span class="checkbox '.$name."\">";
842 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="checkbox" value="'.$value.'" alt="'.$alt.'"'.$strchecked.' '.((!empty($script)) ?
' onclick="'.$script.'" ' : '').' />';
844 $output .= ' <label for="'.$htmlid.'">'.$label.'</label>';
846 $output .= '</span>'."\n";
848 if (empty($return)) {
856 /** Display an standard html text field with an optional label
858 * @param string $name The name of the text field
859 * @param string $value The value of the text field
860 * @param string $label The label to be showed near the text field
861 * @param string $alt The info to be inserted in the alt tag
863 function print_textfield ($name, $value, $alt = '',$size=50,$maxlength=0, $return=false) {
865 static $idcounter = 0;
875 if (!empty($maxlength)) {
876 $maxlength = ' maxlength="'.$maxlength.'" ';
879 $htmlid = 'auto-tf'.sprintf('%04d', ++
$idcounter);
880 $output = '<span class="textfield '.$name."\">";
881 $output .= '<input name="'.$name.'" id="'.$htmlid.'" type="text" value="'.$value.'" size="'.$size.'" '.$maxlength.' alt="'.$alt.'" />';
883 $output .= '</span>'."\n";
885 if (empty($return)) {
895 * Implements a complete little popup form
898 * @param string $common The URL up to the point of the variable that changes
899 * @param array $options Alist of value-label pairs for the popup list
900 * @param string $formid Id must be unique on the page (originaly $formname)
901 * @param string $selected The option that is already selected
902 * @param string $nothing The label for the "no choice" option
903 * @param string $help The name of a help page if help is required
904 * @param string $helptext The name of the label for the help button
905 * @param boolean $return Indicates whether the function should return the text
906 * as a string or echo it directly to the page being rendered
907 * @param string $targetwindow The name of the target page to open the linked page in.
908 * @return string If $return is true then the entire form is returned as a string.
909 * @todo Finish documenting this function<br>
911 function popup_form($common, $options, $formid, $selected='', $nothing='choose', $help='', $helptext='', $return=false, $targetwindow='self', $selectlabel='') {
914 static $go, $choose; /// Locally cached, in case there's lots on a page
916 if (empty($options)) {
921 $go = get_string('go');
924 if ($nothing == 'choose') {
925 if (!isset($choose)) {
926 $choose = get_string('choose');
928 $nothing = $choose.'...';
931 // changed reference to document.getElementById('id_abc') instead of document.abc
933 $output = '<form action="'.$CFG->wwwroot
.'/course/jumpto.php"'.
937 ' class="popupform">';
939 $button = helpbutton($help, $helptext, 'moodle', true, false, '', true);
945 $selectlabel = '<label for="'.$formid.'_jump">'.$selectlabel.'</label>';
948 $output .= '<div>'.$selectlabel.$button.'<select id="'.$formid.'_jump" name="jump" onchange="'.$targetwindow.'.location=document.getElementById(\''.$formid.'\').jump.options[document.getElementById(\''.$formid.'\').jump.selectedIndex].value;">'."\n";
950 if ($nothing != '') {
951 $output .= " <option value=\"javascript:void(0)\">$nothing</option>\n";
956 foreach ($options as $value => $label) {
958 if ($label == '--') { /// we are ending previous optgroup
959 /// Check to see if we already have a valid open optgroup
960 /// XHTML demands that there be at least 1 option within an optgroup
961 if ($inoptgroup and (count($optgr) > 1) ) {
962 $output .= implode('', $optgr);
963 $output .= ' </optgroup>';
968 } else if (substr($label,0,2) == '--') { /// we are starting a new optgroup
970 /// Check to see if we already have a valid open optgroup
971 /// XHTML demands that there be at least 1 option within an optgroup
972 if ($inoptgroup and (count($optgr) > 1) ) {
973 $output .= implode('', $optgr);
974 $output .= ' </optgroup>';
980 $optgr[] = ' <optgroup label="'. s(format_string(substr($label,2))) .'">'; // Plain labels
982 $inoptgroup = true; /// everything following will be in an optgroup
986 if (!empty($CFG->usesid
) && !isset($_COOKIE[session_name()]))
988 $url=sid_process_url( $common . $value );
991 $url=$common . $value;
993 $optstr = ' <option value="' . $url . '"';
995 if ($value == $selected) {
996 $optstr .= ' selected="selected"';
1000 $optstr .= '>'. $label .'</option>' . "\n";
1002 $optstr .= '>'. $value .'</option>' . "\n";
1014 /// catch the final group if not closed
1015 if ($inoptgroup and count($optgr) > 1) {
1016 $output .= implode('', $optgr);
1017 $output .= ' </optgroup>';
1020 $output .= '</select>';
1021 $output .= '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
1022 $output .= '<div id="noscript'.$formid.'" style="display: inline;">';
1023 $output .= '<input type="submit" value="'.$go.'" /></div>';
1024 $output .= '<script type="text/javascript">'.
1026 'document.getElementById("noscript'.$formid.'").style.display = "none";'.
1027 "\n//]]>\n".'</script>';
1028 $output .= '</div>';
1029 $output .= '</form>';
1040 * Prints some red text
1042 * @param string $error The text to be displayed in red
1044 function formerr($error) {
1046 if (!empty($error)) {
1047 echo '<span class="error">'. $error .'</span>';
1052 * Validates an email to make sure it makes sense.
1054 * @param string $address The email address to validate.
1057 function validate_email($address) {
1059 return (ereg('^[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+'.
1060 '(\.[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+)*'.
1062 '[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.
1063 '[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$',
1068 * Extracts file argument either from file parameter or PATH_INFO
1070 * @param string $scriptname name of the calling script
1071 * @return string file path (only safe characters)
1073 function get_file_argument($scriptname) {
1076 $relativepath = FALSE;
1078 // first try normal parameter (compatible method == no relative links!)
1079 $relativepath = optional_param('file', FALSE, PARAM_PATH
);
1080 if ($relativepath === '/testslasharguments') {
1081 echo 'test -1 : Incorrect use - try "file.php/testslasharguments" instead'; //indicate fopen/fread works for health center
1085 // then try extract file from PATH_INFO (slasharguments method)
1086 if (!$relativepath and !empty($_SERVER['PATH_INFO'])) {
1087 $path_info = $_SERVER['PATH_INFO'];
1088 // check that PATH_INFO works == must not contain the script name
1089 if (!strpos($path_info, $scriptname)) {
1090 $relativepath = clean_param(rawurldecode($path_info), PARAM_PATH
);
1091 if ($relativepath === '/testslasharguments') {
1092 echo 'test 1 : Slasharguments test passed. Server confguration is compatible with file.php/1/pic.jpg slashargument setting.'; //indicate ok for health center
1098 // now if both fail try the old way
1099 // (for compatibility with misconfigured or older buggy php implementations)
1100 if (!$relativepath) {
1101 $arr = explode($scriptname, me());
1102 if (!empty($arr[1])) {
1103 $path_info = strip_querystring($arr[1]);
1104 $relativepath = clean_param(rawurldecode($path_info), PARAM_PATH
);
1105 if ($relativepath === '/testslasharguments') {
1106 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
1112 return $relativepath;
1116 * Searches the current environment variables for some slash arguments
1118 * @param string $file ?
1119 * @todo Finish documenting this function
1121 function get_slash_arguments($file='file.php') {
1123 if (!$string = me()) {
1127 $pathinfo = explode($file, $string);
1129 if (!empty($pathinfo[1])) {
1130 return addslashes($pathinfo[1]);
1137 * Extracts arguments from "/foo/bar/something"
1138 * eg http://mysite.com/script.php/foo/bar/something
1140 * @param string $string ?
1142 * @return array|string
1143 * @todo Finish documenting this function
1145 function parse_slash_arguments($string, $i=0) {
1147 if (detect_munged_arguments($string)) {
1150 $args = explode('/', $string);
1152 if ($i) { // return just the required argument
1155 } else { // return the whole array
1156 array_shift($args); // get rid of the empty first one
1162 * Just returns an array of text formats suitable for a popup menu
1164 * @uses FORMAT_MOODLE
1166 * @uses FORMAT_PLAIN
1167 * @uses FORMAT_MARKDOWN
1170 function format_text_menu() {
1172 return array (FORMAT_MOODLE
=> get_string('formattext'),
1173 FORMAT_HTML
=> get_string('formathtml'),
1174 FORMAT_PLAIN
=> get_string('formatplain'),
1175 FORMAT_MARKDOWN
=> get_string('formatmarkdown'));
1179 * Given text in a variety of format codings, this function returns
1180 * the text as safe HTML.
1183 * @uses FORMAT_MOODLE
1185 * @uses FORMAT_PLAIN
1187 * @uses FORMAT_MARKDOWN
1188 * @param string $text The text to be formatted. This is raw text originally from user input.
1189 * @param int $format Identifier of the text format to be used
1190 * (FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN)
1191 * @param array $options ?
1192 * @param int $courseid ?
1194 * @todo Finish documenting this function
1196 function format_text($text, $format=FORMAT_MOODLE
, $options=NULL, $courseid=NULL) {
1198 global $CFG, $COURSE;
1201 return ''; // no need to do any filters and cleaning
1204 if (!isset($options->trusttext
)) {
1205 $options->trusttext
= false;
1208 if (!isset($options->noclean
)) {
1209 $options->noclean
=false;
1211 if (!isset($options->nocache
)) {
1212 $options->nocache
=false;
1214 if (!isset($options->smiley
)) {
1215 $options->smiley
=true;
1217 if (!isset($options->filter
)) {
1218 $options->filter
=true;
1220 if (!isset($options->para
)) {
1221 $options->para
=true;
1223 if (!isset($options->newlines
)) {
1224 $options->newlines
=true;
1227 if (empty($courseid)) {
1228 $courseid = $COURSE->id
;
1231 if (!empty($CFG->cachetext
) and empty($options->nocache
)) {
1232 $time = time() - $CFG->cachetext
;
1233 $md5key = md5($text.'-'.(int)$courseid.'-'.current_language().'-'.(int)$format.(int)$options->trusttext
.(int)$options->noclean
.(int)$options->smiley
.(int)$options->filter
.(int)$options->para
.(int)$options->newlines
);
1234 if ($oldcacheitem = get_record_sql('SELECT * FROM '.$CFG->prefix
.'cache_text WHERE md5key = \''.$md5key.'\'', true)) {
1235 if ($oldcacheitem->timemodified
>= $time) {
1236 return $oldcacheitem->formattedtext
;
1241 // trusttext overrides the noclean option!
1242 if ($options->trusttext
) {
1243 if (trusttext_present($text)) {
1244 $text = trusttext_strip($text);
1245 if (!empty($CFG->enabletrusttext
)) {
1246 $options->noclean
= true;
1248 $options->noclean
= false;
1251 $options->noclean
= false;
1253 } else if (!debugging('', DEBUG_DEVELOPER
)) {
1254 // strip any forgotten trusttext in non-developer mode
1255 // do not forget to disable text cache when debugging trusttext!!
1256 $text = trusttext_strip($text);
1259 $CFG->currenttextiscacheable
= true; // Default status - can be changed by any filter
1263 if ($options->smiley
) {
1264 replace_smilies($text);
1266 if (!$options->noclean
) {
1267 $text = clean_text($text, FORMAT_HTML
);
1269 if ($options->filter
) {
1270 $text = filter_text($text, $courseid);
1275 $text = s($text); // cleans dangerous JS
1276 $text = rebuildnolinktag($text);
1277 $text = str_replace(' ', ' ', $text);
1278 $text = nl2br($text);
1282 // this format is deprecated
1283 $text = '<p>NOTICE: Wiki-like formatting has been removed from Moodle. You should not be seeing
1284 this message as all texts should have been converted to Markdown format instead.
1285 Please post a bug report to http://moodle.org/bugs with information about where you
1286 saw this message.</p>'.s($text);
1289 case FORMAT_MARKDOWN
:
1290 $text = markdown_to_html($text);
1291 if ($options->smiley
) {
1292 replace_smilies($text);
1294 if (!$options->noclean
) {
1295 $text = clean_text($text, FORMAT_HTML
);
1298 if ($options->filter
) {
1299 $text = filter_text($text, $courseid);
1303 default: // FORMAT_MOODLE or anything else
1304 $text = text_to_html($text, $options->smiley
, $options->para
, $options->newlines
);
1305 if (!$options->noclean
) {
1306 $text = clean_text($text, FORMAT_HTML
);
1309 if ($options->filter
) {
1310 $text = filter_text($text, $courseid);
1315 if (empty($options->nocache
) and !empty($CFG->cachetext
) and $CFG->currenttextiscacheable
) {
1316 $newcacheitem = new object();
1317 $newcacheitem->md5key
= $md5key;
1318 $newcacheitem->formattedtext
= addslashes($text);
1319 $newcacheitem->timemodified
= time();
1320 if ($oldcacheitem) { // See bug 4677 for discussion
1321 $newcacheitem->id
= $oldcacheitem->id
;
1322 @update_record
('cache_text', $newcacheitem); // Update existing record in the cache table
1323 // It's unlikely that the cron cache cleaner could have
1324 // deleted this entry in the meantime, as it allows
1325 // some extra time to cover these cases.
1327 @insert_record
('cache_text', $newcacheitem); // Insert a new record in the cache table
1328 // Again, it's possible that another user has caused this
1329 // record to be created already in the time that it took
1330 // to traverse this function. That's OK too, as the
1331 // call above handles duplicate entries, and eventually
1332 // the cron cleaner will delete them.
1339 /** Converts the text format from the value to the 'internal'
1340 * name or vice versa. $key can either be the value or the name
1341 * and you get the other back.
1343 * @param mixed int 0-4 or string one of 'moodle','html','plain','markdown'
1344 * @return mixed as above but the other way around!
1346 function text_format_name( $key ) {
1348 $lookup[FORMAT_MOODLE
] = 'moodle';
1349 $lookup[FORMAT_HTML
] = 'html';
1350 $lookup[FORMAT_PLAIN
] = 'plain';
1351 $lookup[FORMAT_MARKDOWN
] = 'markdown';
1353 if (!is_numeric($key)) {
1354 $key = strtolower( $key );
1355 $value = array_search( $key, $lookup );
1358 if (isset( $lookup[$key] )) {
1359 $value = $lookup[ $key ];
1366 /** Given a simple string, this function returns the string
1367 * processed by enabled filters if $CFG->filterall is enabled
1369 * @param string $string The string to be filtered.
1370 * @param boolean $striplinks To strip any link in the result text (Moodle 1.8 default changed from false to true! MDL-8713)
1371 * @param int $courseid Current course as filters can, potentially, use it
1374 function format_string ($string, $striplinks=true, $courseid=NULL ) {
1376 global $CFG, $COURSE;
1378 //We'll use a in-memory cache here to speed up repeated strings
1379 static $strcache = false;
1381 if ($strcache === false or count($strcache) > 2000 ) { // this number might need some tuning to limit memory usage in cron
1382 $strcache = array();
1386 if (empty($courseid)) {
1387 $courseid = $COURSE->id
;
1391 $md5 = md5($string.'<+>'.$striplinks.'<+>'.$courseid.'<+>'.current_language());
1393 //Fetch from cache if possible
1394 if (isset($strcache[$md5])) {
1395 return $strcache[$md5];
1398 // First replace all ampersands not followed by html entity code
1399 $string = preg_replace("/\&(?![a-z0-9#]{1,8};)/", "&", $string);
1401 if (!empty($CFG->filterall
)) {
1402 $string = filter_string($string, $courseid);
1405 // If the site requires it, strip ALL tags from this string
1406 if (!empty($CFG->formatstringstriptags
)) {
1407 $string = strip_tags($string);
1409 // Otherwise strip just links if that is required (default)
1410 } else if ($striplinks) { //strip links in string
1411 $string = preg_replace('/(<a[^>]+?>)(.+?)(<\/a>)/is','$2',$string);
1415 $strcache[$md5] = $string;
1421 * Given text in a variety of format codings, this function returns
1422 * the text as plain text suitable for plain email.
1424 * @uses FORMAT_MOODLE
1426 * @uses FORMAT_PLAIN
1428 * @uses FORMAT_MARKDOWN
1429 * @param string $text The text to be formatted. This is raw text originally from user input.
1430 * @param int $format Identifier of the text format to be used
1431 * (FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN)
1434 function format_text_email($text, $format) {
1443 $text = wiki_to_html($text);
1444 /// This expression turns links into something nice in a text format. (Russell Jungwirth)
1445 /// From: http://php.net/manual/en/function.eregi-replace.php and simplified
1446 $text = eregi_replace('(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)','\\3 [ \\2 ]', $text);
1447 return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES
)));
1451 return html_to_text($text);
1455 case FORMAT_MARKDOWN
:
1457 $text = eregi_replace('(<a [^<]*href=["|\']?([^ "\']*)["|\']?[^>]*>([^<]*)</a>)','\\3 [ \\2 ]', $text);
1458 return strtr(strip_tags($text), array_flip(get_html_translation_table(HTML_ENTITIES
)));
1464 * Given some text in HTML format, this function will pass it
1465 * through any filters that have been defined in $CFG->textfilterx
1466 * The variable defines a filepath to a file containing the
1467 * filter function. The file must contain a variable called
1468 * $textfilter_function which contains the name of the function
1469 * with $courseid and $text parameters
1471 * @param string $text The text to be passed through format filters
1472 * @param int $courseid ?
1474 * @todo Finish documenting this function
1476 function filter_text($text, $courseid=NULL) {
1477 global $CFG, $COURSE;
1479 if (empty($courseid)) {
1480 $courseid = $COURSE->id
; // (copied from format_text)
1483 if (!empty($CFG->textfilters
)) {
1484 require_once($CFG->libdir
.'/filterlib.php');
1485 $textfilters = explode(',', $CFG->textfilters
);
1486 foreach ($textfilters as $textfilter) {
1487 if (is_readable($CFG->dirroot
.'/'. $textfilter .'/filter.php')) {
1488 include_once($CFG->dirroot
.'/'. $textfilter .'/filter.php');
1489 $functionname = basename($textfilter).'_filter';
1490 if (function_exists($functionname)) {
1491 $text = $functionname($courseid, $text);
1497 /// <nolink> tags removed for XHTML compatibility
1498 $text = str_replace('<nolink>', '', $text);
1499 $text = str_replace('</nolink>', '', $text);
1506 * Given a string (short text) in HTML format, this function will pass it
1507 * through any filters that have been defined in $CFG->stringfilters
1508 * The variable defines a filepath to a file containing the
1509 * filter function. The file must contain a variable called
1510 * $textfilter_function which contains the name of the function
1511 * with $courseid and $text parameters
1513 * @param string $string The text to be passed through format filters
1514 * @param int $courseid The id of a course
1517 function filter_string($string, $courseid=NULL) {
1518 global $CFG, $COURSE;
1520 if (empty($CFG->textfilters
)) { // All filters are disabled anyway so quit
1524 if (empty($courseid)) {
1525 $courseid = $COURSE->id
;
1528 require_once($CFG->libdir
.'/filterlib.php');
1530 if (isset($CFG->stringfilters
)) { // We have a predefined list to use, great!
1531 if (empty($CFG->stringfilters
)) { // but it's blank, so finish now
1534 $stringfilters = explode(',', $CFG->stringfilters
); // ..use the list we have
1536 } else { // Otherwise try to derive a list from textfilters
1537 if (strpos($CFG->textfilters
, 'filter/multilang') !== false) { // Multilang is here
1538 $stringfilters = array('filter/multilang'); // Let's use just that
1539 $CFG->stringfilters
= 'filter/multilang'; // Save it for next time through
1541 $CFG->stringfilters
= ''; // Save the result and return
1547 foreach ($stringfilters as $stringfilter) {
1548 if (is_readable($CFG->dirroot
.'/'. $stringfilter .'/filter.php')) {
1549 include_once($CFG->dirroot
.'/'. $stringfilter .'/filter.php');
1550 $functionname = basename($stringfilter).'_filter';
1551 if (function_exists($functionname)) {
1552 $string = $functionname($courseid, $string);
1557 /// <nolink> tags removed for XHTML compatibility
1558 $string = str_replace('<nolink>', '', $string);
1559 $string = str_replace('</nolink>', '', $string);
1565 * Is the text marked as trusted?
1567 * @param string $text text to be searched for TRUSTTEXT marker
1570 function trusttext_present($text) {
1571 if (strpos($text, TRUSTTEXT
) !== FALSE) {
1579 * This funtion MUST be called before the cleaning or any other
1580 * function that modifies the data! We do not know the origin of trusttext
1581 * in database, if it gets there in tweaked form we must not convert it
1582 * to supported form!!!
1584 * Please be carefull not to use stripslashes on data from database
1585 * or twice stripslashes when processing data recieved from user.
1587 * @param string $text text that may contain TRUSTTEXT marker
1588 * @return text without any TRUSTTEXT marker
1590 function trusttext_strip($text) {
1593 while (true) { //removing nested TRUSTTEXT
1595 $text = str_replace(TRUSTTEXT
, '', $text);
1596 if (strcmp($orig, $text) === 0) {
1603 * Mark text as trusted, such text may contain any HTML tags because the
1604 * normal text cleaning will be bypassed.
1605 * Please make sure that the text comes from trusted user before storing
1608 function trusttext_mark($text) {
1610 if (!empty($CFG->enabletrusttext
) and (strpos($text, TRUSTTEXT
) === FALSE)) {
1611 return TRUSTTEXT
.$text;
1616 function trusttext_after_edit(&$text, $context) {
1617 if (has_capability('moodle/site:trustcontent', $context)) {
1618 $text = trusttext_strip($text);
1619 $text = trusttext_mark($text);
1621 $text = trusttext_strip($text);
1625 function trusttext_prepare_edit(&$text, &$format, $usehtmleditor, $context) {
1628 $options = new object();
1629 $options->smiley
= false;
1630 $options->filter
= false;
1631 if (!empty($CFG->enabletrusttext
)
1632 and has_capability('moodle/site:trustcontent', $context)
1633 and trusttext_present($text)) {
1634 $options->noclean
= true;
1636 $options->noclean
= false;
1638 $text = trusttext_strip($text);
1639 if ($usehtmleditor) {
1640 $text = format_text($text, $format, $options);
1641 $format = FORMAT_HTML
;
1642 } else if (!$options->noclean
){
1643 $text = clean_text($text, $format);
1648 * Given raw text (eg typed in by a user), this function cleans it up
1649 * and removes any nasty tags that could mess up Moodle pages.
1651 * @uses FORMAT_MOODLE
1652 * @uses FORMAT_PLAIN
1653 * @uses ALLOWED_TAGS
1654 * @param string $text The text to be cleaned
1655 * @param int $format Identifier of the text format to be used
1656 * (FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN, FORMAT_WIKI, FORMAT_MARKDOWN)
1657 * @return string The cleaned up text
1659 function clean_text($text, $format=FORMAT_MOODLE
) {
1661 global $ALLOWED_TAGS;
1669 /// Fix non standard entity notations
1670 $text = preg_replace('/(&#[0-9]+)(;?)/', "\\1;", $text);
1671 $text = preg_replace('/(&#x[0-9a-fA-F]+)(;?)/', "\\1;", $text);
1673 /// Remove tags that are not allowed
1674 $text = strip_tags($text, $ALLOWED_TAGS);
1676 /// Clean up embedded scripts and , using kses
1677 $text = cleanAttributes($text);
1679 /// Remove script events
1680 $text = eregi_replace("([^a-z])language([[:space:]]*)=", "\\1Xlanguage=", $text);
1681 $text = eregi_replace("([^a-z])on([a-z]+)([[:space:]]*)=", "\\1Xon\\2=", $text);
1688 * This function takes a string and examines it for HTML tags.
1689 * If tags are detected it passes the string to a helper function {@link cleanAttributes2()}
1690 * which checks for attributes and filters them for malicious content
1691 * 17/08/2004 :: Eamon DOT Costello AT dcu DOT ie
1693 * @param string $str The string to be examined for html tags
1696 function cleanAttributes($str){
1697 $result = preg_replace_callback(
1698 '%(<[^>]*(>|$)|>)%m', #search for html tags
1706 * This function takes a string with an html tag and strips out any unallowed
1707 * protocols e.g. javascript:
1708 * It calls ancillary functions in kses which are prefixed by kses
1709 * 17/08/2004 :: Eamon DOT Costello AT dcu DOT ie
1711 * @param array $htmlArray An array from {@link cleanAttributes()}, containing in its 1st
1712 * element the html to be cleared
1715 function cleanAttributes2($htmlArray){
1717 global $CFG, $ALLOWED_PROTOCOLS;
1718 require_once($CFG->libdir
.'/kses.php');
1720 $htmlTag = $htmlArray[1];
1721 if (substr($htmlTag, 0, 1) != '<') {
1722 return '>'; //a single character ">" detected
1724 if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $htmlTag, $matches)) {
1725 return ''; // It's seriously malformed
1727 $slash = trim($matches[1]); //trailing xhtml slash
1728 $elem = $matches[2]; //the element name
1729 $attrlist = $matches[3]; // the list of attributes as a string
1731 $attrArray = kses_hair($attrlist, $ALLOWED_PROTOCOLS);
1734 foreach ($attrArray as $arreach) {
1735 $arreach['name'] = strtolower($arreach['name']);
1736 if ($arreach['name'] == 'style') {
1737 $value = $arreach['value'];
1739 $prevvalue = $value;
1740 $value = kses_no_null($value);
1741 $value = preg_replace("/\/\*.*\*\//Us", '', $value);
1742 $value = kses_decode_entities($value);
1743 $value = preg_replace('/(&#[0-9]+)(;?)/', "\\1;", $value);
1744 $value = preg_replace('/(&#x[0-9a-fA-F]+)(;?)/', "\\1;", $value);
1745 if ($value === $prevvalue) {
1746 $arreach['value'] = $value;
1750 $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']);
1751 $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']);
1752 } else if ($arreach['name'] == 'href') {
1753 //Adobe Acrobat Reader XSS protection
1754 $arreach['value'] = preg_replace('/(\.(pdf|fdf|xfdf|xdp|xfd))[^a-z0-9_\.\-].*$/i', '$1', $arreach['value']);
1756 $attStr .= ' '.$arreach['name'].'="'.$arreach['value'].'"';
1760 if (preg_match('%/\s*$%', $attrlist)) {
1761 $xhtml_slash = ' /';
1763 return '<'. $slash . $elem . $attStr . $xhtml_slash .'>';
1767 * Replaces all known smileys in the text with image equivalents
1770 * @param string $text Passed by reference. The string to search for smily strings.
1773 function replace_smilies(&$text) {
1777 /// this builds the mapping array only once
1778 static $runonce = false;
1779 static $e = array();
1780 static $img = array();
1781 static $emoticons = array(
1787 'V-.' => 'thoughtful',
1788 ':-P' => 'tongueout',
1791 '8-)' => 'wideeyes',
1798 '8-o' => 'surprise',
1799 'P-|' => 'blackeye',
1805 '(heart)' => 'heart',
1808 '(martin)' => 'martin',
1812 if ($runonce == false) { /// After the first time this is not run again
1813 foreach ($emoticons as $emoticon => $image){
1814 $alttext = get_string($image, 'pix');
1817 $img[] = '<img alt="'. $alttext .'" width="15" height="15" src="'. $CFG->pixpath
.'/s/'. $image .'.gif" />';
1822 // Exclude from transformations all the code inside <script> tags
1823 // Needed to solve Bug 1185. Thanks to jouse 2001 detecting it. :-)
1824 // Based on code from glossary fiter by Williams Castillo.
1827 // Detect all the <script> zones to take out
1828 $excludes = array();
1829 preg_match_all('/<script language(.+?)<\/script>/is',$text,$list_of_excludes);
1831 // Take out all the <script> zones from text
1832 foreach (array_unique($list_of_excludes[0]) as $key=>$value) {
1833 $excludes['<+'.$key.'+>'] = $value;
1836 $text = str_replace($excludes,array_keys($excludes),$text);
1839 /// this is the meat of the code - this is run every time
1840 $text = str_replace($e, $img, $text);
1842 // Recover all the <script> zones to text
1844 $text = str_replace(array_keys($excludes),$excludes,$text);
1849 * Given plain text, makes it into HTML as nicely as possible.
1850 * May contain HTML tags already
1853 * @param string $text The string to convert.
1854 * @param boolean $smiley Convert any smiley characters to smiley images?
1855 * @param boolean $para If true then the returned string will be wrapped in paragraph tags
1856 * @param boolean $newlines If true then lines newline breaks will be converted to HTML newline breaks.
1860 function text_to_html($text, $smiley=true, $para=true, $newlines=true) {
1865 /// Remove any whitespace that may be between HTML tags
1866 $text = eregi_replace(">([[:space:]]+)<", "><", $text);
1868 /// Remove any returns that precede or follow HTML tags
1869 $text = eregi_replace("([\n\r])<", " <", $text);
1870 $text = eregi_replace(">([\n\r])", "> ", $text);
1872 convert_urls_into_links($text);
1874 /// Make returns into HTML newlines.
1876 $text = nl2br($text);
1879 /// Turn smileys into images.
1881 replace_smilies($text);
1884 /// Wrap the whole thing in a paragraph tag if required
1886 return '<p>'.$text.'</p>';
1893 * Given Markdown formatted text, make it into XHTML using external function
1896 * @param string $text The markdown formatted text to be converted.
1897 * @return string Converted text
1899 function markdown_to_html($text) {
1902 require_once($CFG->libdir
.'/markdown.php');
1904 return Markdown($text);
1908 * Given HTML text, make it into plain text using external function
1911 * @param string $html The text to be converted.
1914 function html_to_text($html) {
1918 require_once($CFG->libdir
.'/html2text.php');
1920 return html2text($html);
1924 * Given some text this function converts any URLs it finds into HTML links
1926 * @param string $text Passed in by reference. The string to be searched for urls.
1928 function convert_urls_into_links(&$text) {
1929 /// Make lone URLs into links. eg http://moodle.com/
1930 $text = eregi_replace("([[:space:]]|^|\(|\[)([[:alnum:]]+)://([^[:space:]]*)([[:alnum:]#?/&=])",
1931 "\\1<a href=\"\\2://\\3\\4\" target=\"_blank\">\\2://\\3\\4</a>", $text);
1933 /// eg www.moodle.com
1934 $text = eregi_replace("([[:space:]]|^|\(|\[)www\.([^[:space:]]*)([[:alnum:]#?/&=])",
1935 "\\1<a href=\"http://www.\\2\\3\" target=\"_blank\">www.\\2\\3</a>", $text);
1939 * This function will highlight search words in a given string
1940 * It cares about HTML and will not ruin links. It's best to use
1941 * this function after performing any conversions to HTML.
1942 * Function found here: http://forums.devshed.com/t67822/scdaa2d1c3d4bacb4671d075ad41f0854.html
1944 * @param string $needle The string to search for
1945 * @param string $haystack The string to search for $needle in
1946 * @param int $case ?
1948 * @todo Finish documenting this function
1950 function highlight($needle, $haystack, $case=0,
1951 $left_string='<span class="highlight">', $right_string='</span>') {
1952 if (empty($needle)) {
1956 //$list_of_words = eregi_replace("[^-a-zA-Z0-9&.']", " ", $needle); // bug 3101
1957 $list_of_words = $needle;
1958 $list_array = explode(' ', $list_of_words);
1959 for ($i=0; $i<sizeof($list_array); $i++
) {
1960 if (strlen($list_array[$i]) == 1) {
1961 $list_array[$i] = '';
1964 $list_of_words = implode(' ', $list_array);
1965 $list_of_words_cp = $list_of_words;
1967 preg_match_all('/<(.+?)>/is',$haystack,$list_of_words);
1969 foreach (array_unique($list_of_words[0]) as $key=>$value) {
1970 $final['<|'.$key.'|>'] = $value;
1973 $haystack = str_replace($final,array_keys($final),$haystack);
1974 $list_of_words_cp = eregi_replace(' +', '|', $list_of_words_cp);
1976 if ($list_of_words_cp{0}=='|') {
1977 $list_of_words_cp{0} = '';
1979 if ($list_of_words_cp{strlen($list_of_words_cp)-1}=='|') {
1980 $list_of_words_cp{strlen($list_of_words_cp)-1}='';
1983 $list_of_words_cp = trim($list_of_words_cp);
1985 if ($list_of_words_cp) {
1987 $list_of_words_cp = "(". $list_of_words_cp .")";
1990 $haystack = eregi_replace("$list_of_words_cp", "$left_string"."\\1"."$right_string", $haystack);
1992 $haystack = ereg_replace("$list_of_words_cp", "$left_string"."\\1"."$right_string", $haystack);
1995 $haystack = str_replace(array_keys($final),$final,$haystack);
2001 * This function will highlight instances of $needle in $haystack
2002 * It's faster that the above function and doesn't care about
2005 * @param string $needle The string to search for
2006 * @param string $haystack The string to search for $needle in
2009 function highlightfast($needle, $haystack) {
2011 $parts = explode(moodle_strtolower($needle), moodle_strtolower($haystack));
2015 foreach ($parts as $key => $part) {
2016 $parts[$key] = substr($haystack, $pos, strlen($part));
2017 $pos +
= strlen($part);
2019 $parts[$key] .= '<span class="highlight">'.substr($haystack, $pos, strlen($needle)).'</span>';
2020 $pos +
= strlen($needle);
2023 return (join('', $parts));
2027 * Return a string containing 'lang', xml:lang and optionally 'dir' HTML attributes.
2028 * Internationalisation, for print_header and backup/restorelib.
2029 * @param $dir Default false.
2030 * @return string Attributes.
2032 function get_html_lang($dir = false) {
2035 if (get_string('thisdirection') == 'rtl') {
2036 $direction = ' dir="rtl"';
2038 $direction = ' dir="ltr"';
2041 //Accessibility: added the 'lang' attribute to $direction, used in theme <html> tag.
2042 $language = str_replace('_', '-', str_replace('_utf8', '', current_language()));
2043 @header
('Content-Language: '.$language);
2044 return ($direction.' lang="'.$language.'" xml:lang="'.$language.'"');
2048 /// STANDARD WEB PAGE PARTS ///////////////////////////////////////////////////
2051 * Print a standard header
2056 * @param string $title Appears at the top of the window
2057 * @param string $heading Appears at the top of the page
2058 * @param string $navigation Premade navigation string (for use as breadcrumbs links)
2059 * @param string $focus Indicates form element to get cursor focus on load eg inputform.password
2060 * @param string $meta Meta tags to be added to the header
2061 * @param boolean $cache Should this page be cacheable?
2062 * @param string $button HTML code for a button (usually for module editing)
2063 * @param string $menu HTML code for a popup menu
2064 * @param boolean $usexml use XML for this page
2065 * @param string $bodytags This text will be included verbatim in the <body> tag (useful for onload() etc)
2066 * @param bool $return If true, return the visible elements of the header instead of echoing them.
2068 function print_header ($title='', $heading='', $navigation='', $focus='',
2069 $meta='', $cache=true, $button=' ', $menu='',
2070 $usexml=false, $bodytags='', $return=false) {
2072 global $USER, $CFG, $THEME, $SESSION, $ME, $SITE, $COURSE;
2074 $heading = format_string($heading); // Fix for MDL-8582
2076 /// This makes sure that the header is never repeated twice on a page
2077 if (defined('HEADER_PRINTED')) {
2078 debugging('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().');
2081 define('HEADER_PRINTED', 'true');
2084 /// Add the required stylesheets
2085 $stylesheetshtml = '';
2086 foreach ($CFG->stylesheets
as $stylesheet) {
2087 $stylesheetshtml .= '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'" />'."\n";
2089 $meta = $stylesheetshtml.$meta;
2092 /// Add the meta page from the themes if any were requested
2096 if (!isset($THEME->standardmetainclude
) ||
$THEME->standardmetainclude
) {
2098 include_once($CFG->dirroot
.'/theme/standard/meta.php');
2099 $metapage .= ob_get_contents();
2103 if ($THEME->parent
&& (!isset($THEME->parentmetainclude
) ||
$THEME->parentmetainclude
)) {
2104 if (file_exists($CFG->dirroot
.'/theme/'.$THEME->parent
.'/meta.php')) {
2106 include_once($CFG->dirroot
.'/theme/'.$THEME->parent
.'/meta.php');
2107 $metapage .= ob_get_contents();
2112 if (!isset($THEME->metainclude
) ||
$THEME->metainclude
) {
2113 if (file_exists($CFG->dirroot
.'/theme/'.current_theme().'/meta.php')) {
2115 include_once($CFG->dirroot
.'/theme/'.current_theme().'/meta.php');
2116 $metapage .= ob_get_contents();
2121 $meta = $meta."\n".$metapage;
2124 /// Add the required JavaScript Libraries
2125 $meta .= "\n".require_js();
2128 if ($navigation == 'home') {
2135 /// This is another ugly hack to make navigation elements available to print_footer later
2136 $THEME->title
= $title;
2137 $THEME->heading
= $heading;
2138 $THEME->navigation
= $navigation;
2139 $THEME->button
= $button;
2140 $THEME->menu
= $menu;
2141 $navmenulist = isset($THEME->navmenulist
) ?
$THEME->navmenulist
: '';
2143 if ($button == '') {
2147 if (!$menu and $navigation) {
2148 if (empty($CFG->loginhttps
)) {
2149 $wwwroot = $CFG->wwwroot
;
2151 $wwwroot = str_replace('http:','https:',$CFG->wwwroot
);
2153 $menu = user_login_string($COURSE);
2156 if (isset($SESSION->justloggedin
)) {
2157 unset($SESSION->justloggedin
);
2158 if (!empty($CFG->displayloginfailures
)) {
2159 if (!empty($USER->username
) and $USER->username
!= 'guest') {
2160 if ($count = count_login_failures($CFG->displayloginfailures
, $USER->username
, $USER->lastlogin
)) {
2161 $menu .= ' <font size="1">';
2162 if (empty($count->accounts
)) {
2163 $menu .= get_string('failedloginattempts', '', $count);
2165 $menu .= get_string('failedloginattemptsall', '', $count);
2167 if (has_capability('moodle/site:viewreports', get_context_instance(CONTEXT_SYSTEM
, SITEID
))) {
2168 $menu .= ' (<a href="'.$CFG->wwwroot
.'/course/report/log/index.php'.
2169 '?chooselog=1&id=1&modid=site_errors">'.get_string('logs').'</a>)';
2178 $meta = '<meta http-equiv="content-type" content="text/html; charset=utf-8" />'. "\n". $meta ."\n";
2180 @header
('Content-type: text/html; charset=utf-8');
2183 //Accessibility: added the 'lang' attribute to $direction, used in theme <html> tag.
2184 $direction = get_html_lang($dir=true);
2186 if ($cache) { // Allow caching on "back" (but not on normal clicks)
2187 @header
('Cache-Control: private, pre-check=0, post-check=0, max-age=0');
2188 @header
('Pragma: no-cache');
2189 @header
('Expires: ');
2190 } else { // Do everything we can to always prevent clients and proxies caching
2191 @header
('Cache-Control: no-store, no-cache, must-revalidate');
2192 @header
('Cache-Control: post-check=0, pre-check=0', false);
2193 @header
('Pragma: no-cache');
2194 @header
('Expires: Mon, 20 Aug 1969 09:23:00 GMT');
2195 @header
('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
2197 $meta .= "\n<meta http-equiv=\"pragma\" content=\"no-cache\" />";
2198 $meta .= "\n<meta http-equiv=\"expires\" content=\"0\" />";
2200 @header
('Accept-Ranges: none');
2202 if (empty($usexml)) {
2203 $direction = ' xmlns="http://www.w3.org/1999/xhtml"'. $direction; // See debug_header
2205 $currentlanguage = current_language();
2206 $mathplayer = preg_match("/MathPlayer/i", $_SERVER['HTTP_USER_AGENT']);
2208 header('Content-Type: application/xhtml+xml');
2210 echo '<?xml version="1.0" ?>'."\n";
2211 if (!empty($CFG->xml_stylesheets
)) {
2212 $stylesheets = explode(';', $CFG->xml_stylesheets
);
2213 foreach ($stylesheets as $stylesheet) {
2214 echo '<?xml-stylesheet type="text/xsl" href="'. $CFG->wwwroot
.'/'. $stylesheet .'" ?>' . "\n";
2217 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1';
2218 if (!empty($CFG->xml_doctype_extra
)) {
2219 echo ' plus '. $CFG->xml_doctype_extra
;
2221 echo '//' . strtoupper($currentlanguage) . '" "'. $CFG->xml_dtd
.'">'."\n";
2222 $direction = " xmlns=\"http://www.w3.org/1999/xhtml\"
2223 xmlns:math=\"http://www.w3.org/1998/Math/MathML\"
2224 xmlns:xlink=\"http://www.w3.org/1999/xlink\"
2227 $meta .= '<object id="mathplayer" classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987">' . "\n";
2228 $meta .= '<!--comment required to prevent this becoming an empty tag-->'."\n";
2229 $meta .= '</object>'."\n";
2230 $meta .= '<?import namespace="math" implementation="#mathplayer" ?>' . "\n";
2234 // Clean up the title
2236 $title = strip_tags(format_string($title)); // fix for MDL-8582
2237 $title = str_replace('"', '"', $title);
2239 // Create class and id for this page
2241 page_id_and_class($pageid, $pageclass);
2243 $pageclass .= ' course-'.$COURSE->id
;
2245 if (($pageid != 'site-index') && ($pageid != 'course-view') &&
2246 (strstr($pageid, 'admin') === FALSE)) {
2247 $pageclass .= ' nocoursepage';
2250 if (!isloggedin()) {
2251 $pageclass .= ' notloggedin';
2254 if (!empty($USER->editing
)) {
2255 $pageclass .= ' editing';
2258 if (!empty($CFG->blocksdrag
)) {
2259 $pageclass .= ' drag';
2262 $bodytags .= ' class="'.$pageclass.'" id="'.$pageid.'"';
2265 include($CFG->header
);
2266 $output = ob_get_contents();
2269 $output = force_strict_header($output);
2271 if (!empty($CFG->messaging
)) {
2272 $output .= message_popup_window();
2283 * Debugging aid: serve page as 'application/xhtml+xml' where possible,
2284 * and substitute the XHTML strict document type.
2285 * Note, requires the 'xmlns' fix in function print_header above.
2286 * See: http://tracker.moodle.org/browse/MDL-7883
2289 function force_strict_header($output) {
2291 $strict = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
2292 $xsl = '/lib/xhtml.xsl';
2294 if (!headers_sent() && debugging(NULL, DEBUG_DEVELOPER
)) { // In developer debugging, the browser will barf
2295 $ctype = 'Content-Type: ';
2296 $prolog= "<?xml version='1.0' encoding='utf-8'?>\n";
2298 if (isset($_SERVER['HTTP_ACCEPT'])
2299 && false !== strpos($_SERVER['HTTP_ACCEPT'], 'application/xhtml+xml')) {
2300 //|| false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Safari') //Safari "Entity 'copy' not defined".
2302 $ctype .= 'application/xhtml+xml';
2303 $prolog .= "<!--\n DEBUG: $ctype \n-->\n";
2305 } else if (file_exists($CFG->dirroot
.$xsl)
2306 && preg_match('/MSIE.*Windows NT/', $_SERVER['HTTP_USER_AGENT'])) {
2307 // XSL hack for IE 5+ on Windows.
2308 //$www_xsl = preg_replace('/(http:\/\/.+?\/).*/', '', $CFG->wwwroot) .$xsl;
2309 $www_xsl = $CFG->wwwroot
.$xsl;
2310 $ctype .= 'application/xml';
2311 $prolog .= "<?xml-stylesheet type='text/xsl' href='$www_xsl'?>\n";
2312 $prolog .= "<!--\n DEBUG: $ctype \n-->\n";
2315 //ELSE: Mac/IE, old/non-XML browsers.
2316 $ctype .= 'text/html';
2319 @header
($ctype.'; charset=utf-8');
2320 $output = $prolog . $output;
2322 // Test parser error-handling.
2323 if (isset($_GET['error'])) {
2324 $output .= "__ TEST: XML well-formed error < __\n";
2328 $output = preg_replace('/(<!DOCTYPE.+?>)/s', $strict, $output); // Always change the DOCTYPE to Strict 1.0
2336 * This version of print_header is simpler because the course name does not have to be
2337 * provided explicitly in the strings. It can be used on the site page as in courses
2338 * Eventually all print_header could be replaced by print_header_simple
2340 * @param string $title Appears at the top of the window
2341 * @param string $heading Appears at the top of the page
2342 * @param string $navigation Premade navigation string (for use as breadcrumbs links)
2343 * @param string $focus Indicates form element to get cursor focus on load eg inputform.password
2344 * @param string $meta Meta tags to be added to the header
2345 * @param boolean $cache Should this page be cacheable?
2346 * @param string $button HTML code for a button (usually for module editing)
2347 * @param string $menu HTML code for a popup menu
2348 * @param boolean $usexml use XML for this page
2349 * @param string $bodytags This text will be included verbatim in the <body> tag (useful for onload() etc)
2350 * @param bool $return If true, return the visible elements of the header instead of echoing them.
2352 function print_header_simple($title='', $heading='', $navigation='', $focus='', $meta='',
2353 $cache=true, $button=' ', $menu='', $usexml=false, $bodytags='', $return=false) {
2355 global $COURSE, $CFG;
2358 if ($COURSE->id
!= SITEID
) {
2359 $shortname = '<a href="'.$CFG->wwwroot
.'/course/view.php?id='. $COURSE->id
.'">'. $COURSE->shortname
.'</a> ->';
2362 $output = print_header($COURSE->shortname
.': '. $title, $COURSE->fullname
.' '. $heading, $shortname.' '. $navigation, $focus, $meta,
2363 $cache, $button, $menu, $usexml, $bodytags, true);
2374 * Can provide a course object to make the footer contain a link to
2375 * to the course home page, otherwise the link will go to the site home
2379 * @param course $course {@link $COURSE} object containing course information
2380 * @param ? $usercourse ?
2381 * @todo Finish documenting this function
2383 function print_footer($course=NULL, $usercourse=NULL, $return=false) {
2384 global $USER, $CFG, $THEME, $COURSE;
2388 if (is_string($course) && $course == 'none') { // Don't print any links etc
2392 } else if (is_string($course) && $course == 'home') { // special case for site home page - please do not remove
2393 $course = get_site();
2394 $homelink = '<div class="sitelink">'.
2395 '<a title="moodle '. $CFG->release
.' ('. $CFG->version
.')" href="http://moodle.org/">'.
2396 '<br /><img style="width:100px;height:30px" src="pix/moodlelogo.gif" alt="moodlelogo" /></a></div>';
2399 $homelink = '<div class="homelink"><a '.$CFG->frametarget
.' href="'.$CFG->wwwroot
.
2400 '/course/view.php?id='.$course->id
.'">'.format_string($course->shortname
).'</a></div>';
2404 $course = get_site(); // Set course as site course by default
2405 $homelink = '<div class="homelink"><a '.$CFG->frametarget
.' href="'.$CFG->wwwroot
.'/">'.get_string('home').'</a></div>';
2409 /// Set up some other navigation links (passed from print_header by ugly hack)
2410 $menu = isset($THEME->menu
) ?
str_replace('navmenu', 'navmenufooter', $THEME->menu
) : '';
2411 $title = isset($THEME->title
) ?
$THEME->title
: '';
2412 $button = isset($THEME->button
) ?
$THEME->button
: '';
2413 $heading = isset($THEME->heading
) ?
$THEME->heading
: '';
2414 $navigation = isset($THEME->navigation
) ?
$THEME->navigation
: '';
2415 $navmenulist = isset($THEME->navmenulist
) ?
$THEME->navmenulist
: '';
2418 /// Set the user link if necessary
2419 if (!$usercourse and is_object($course)) {
2420 $usercourse = $course;
2423 if (!isset($loggedinas)) {
2424 $loggedinas = user_login_string($usercourse, $USER);
2427 if ($loggedinas == $menu) {
2431 /// Provide some performance info if required
2432 $performanceinfo = '';
2433 if (defined('MDL_PERF') ||
(!empty($CFG->perfdebug
) and $CFG->perfdebug
> 7)) {
2434 $perf = get_performance_info();
2435 if (defined('MDL_PERFTOLOG')) {
2436 error_log("PERF: " . $perf['txt']);
2438 if (defined('MDL_PERFTOFOOT') ||
debugging() ||
$CFG->perfdebug
> 7) {
2439 $performanceinfo = $perf['html'];
2444 /// Include the actual footer file
2447 include($CFG->footer
);
2448 $output = ob_get_contents();
2459 * Returns the name of the current theme
2466 function current_theme() {
2467 global $CFG, $USER, $SESSION, $COURSE;
2469 if (!empty($CFG->pagetheme
)) { // Page theme is for special page-only themes set by code
2470 return $CFG->pagetheme
;
2472 } else if (!empty($CFG->allowcoursethemes
) and !empty($COURSE->theme
)) { // Course themes override others
2473 return $COURSE->theme
;
2475 } else if (!empty($SESSION->theme
)) { // Session theme can override other settings
2476 return $SESSION->theme
;
2478 } else if (!empty($CFG->allowuserthemes
) and !empty($USER->theme
)) { // User theme can override site theme
2479 return $USER->theme
;
2488 * This function is called by stylesheets to set up the header
2489 * approriately as well as the current path
2492 * @param int $lastmodified ?
2493 * @param int $lifetime ?
2494 * @param string $thename ?
2496 function style_sheet_setup($lastmodified=0, $lifetime=300, $themename='', $forceconfig='', $lang='') {
2498 global $CFG, $THEME;
2500 // Fix for IE6 caching - we don't want the filemtime('styles.php'), instead use now.
2501 $lastmodified = time();
2503 header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $lastmodified) . ' GMT');
2504 header('Expires: ' . gmdate("D, d M Y H:i:s", time() +
$lifetime) . ' GMT');
2505 header('Cache-Control: max-age='. $lifetime);
2507 header('Content-type: text/css'); // Correct MIME type
2509 $DEFAULT_SHEET_LIST = array('styles_layout', 'styles_fonts', 'styles_color');
2511 if (empty($themename)) {
2512 $themename = current_theme(); // So we have something. Normally not needed.
2514 $themename = clean_param($themename, PARAM_SAFEDIR
);
2517 if (!empty($forceconfig)) { // Page wants to use the config from this theme instead
2519 include($CFG->themedir
.'/'.$forceconfig.'/'.'config.php');
2522 /// If this is the standard theme calling us, then find out what sheets we need
2524 if ($themename == 'standard') {
2525 if (!isset($THEME->standardsheets
) or $THEME->standardsheets
=== true) { // Use all the sheets we have
2526 $THEME->sheets
= $DEFAULT_SHEET_LIST;
2527 } else if (empty($THEME->standardsheets
)) { // We can stop right now!
2528 echo "/***** Nothing required from this stylesheet by main theme *****/\n\n";
2530 } else { // Use the provided subset only
2531 $THEME->sheets
= $THEME->standardsheets
;
2534 /// If we are a parent theme, then check for parent definitions
2536 } else if (!empty($THEME->parent
) && $themename == $THEME->parent
) {
2537 if (!isset($THEME->parentsheets
) or $THEME->parentsheets
=== true) { // Use all the sheets we have
2538 $THEME->sheets
= $DEFAULT_SHEET_LIST;
2539 } else if (empty($THEME->parentsheets
)) { // We can stop right now!
2540 echo "/***** Nothing required from this stylesheet by main theme *****/\n\n";
2542 } else { // Use the provided subset only
2543 $THEME->sheets
= $THEME->parentsheets
;
2547 /// Work out the last modified date for this theme
2549 foreach ($THEME->sheets
as $sheet) {
2550 if (file_exists($CFG->themedir
.'/'.$themename.'/'.$sheet.'.css')) {
2551 $sheetmodified = filemtime($CFG->themedir
.'/'.$themename.'/'.$sheet.'.css');
2552 if ($sheetmodified > $lastmodified) {
2553 $lastmodified = $sheetmodified;
2559 /// Get a list of all the files we want to include
2562 foreach ($THEME->sheets
as $sheet) {
2563 $files[] = array($CFG->themedir
, $themename.'/'.$sheet.'.css');
2566 if ($themename == 'standard') { // Add any standard styles included in any modules
2567 if (!empty($THEME->modsheets
)) { // Search for styles.php within activity modules
2568 if ($mods = get_list_of_plugins('mod')) {
2569 foreach ($mods as $mod) {
2570 if (file_exists($CFG->dirroot
.'/mod/'.$mod.'/styles.php')) {
2571 $files[] = array($CFG->dirroot
, '/mod/'.$mod.'/styles.php');
2577 if (!empty($THEME->blocksheets
)) { // Search for styles.php within block modules
2578 if ($mods = get_list_of_plugins('blocks')) {
2579 foreach ($mods as $mod) {
2580 if (file_exists($CFG->dirroot
.'/blocks/'.$mod.'/styles.php')) {
2581 $files[] = array($CFG->dirroot
, '/blocks/'.$mod.'/styles.php');
2587 if (!isset($THEME->courseformatsheets
) ||
$THEME->courseformatsheets
) { // Search for styles.php in course formats
2588 if ($mods = get_list_of_plugins('format','',$CFG->dirroot
.'/course')) {
2589 foreach ($mods as $mod) {
2590 if (file_exists($CFG->dirroot
.'/course/format/'.$mod.'/styles.php')) {
2591 $files[] = array($CFG->dirroot
, '/course/format/'.$mod.'/styles.php');
2597 if (!empty($THEME->langsheets
)) { // Search for styles.php within the current language
2598 if (file_exists($CFG->dirroot
.'/lang/'.$lang.'/styles.php')) {
2599 $files[] = array($CFG->dirroot
, '/lang/'.$lang.'/styles.php');
2606 /// Produce a list of all the files first
2607 echo '/**************************************'."\n";
2608 echo ' * THEME NAME: '.$themename."\n *\n";
2609 echo ' * Files included in this sheet:'."\n *\n";
2610 foreach ($files as $file) {
2611 echo ' * '.$file[1]."\n";
2613 echo ' **************************************/'."\n\n";
2616 /// check if csscobstants is set
2617 if (!empty($THEME->cssconstants
)) {
2618 require_once("$CFG->libdir/cssconstants.php");
2619 /// Actually collect all the files in order.
2621 foreach ($files as $file) {
2622 $css .= '/***** '.$file[1].' start *****/'."\n\n";
2623 $css .= file_get_contents($file[0].'/'.$file[1]);
2624 $ccs .= '/***** '.$file[1].' end *****/'."\n\n";
2626 /// replace css_constants with their values
2627 echo replace_cssconstants($css);
2629 /// Actually output all the files in order.
2630 foreach ($files as $file) {
2631 echo '/***** '.$file[1].' start *****/'."\n\n";
2632 @include_once
($file[0].'/'.$file[1]);
2633 echo '/***** '.$file[1].' end *****/'."\n\n";
2638 return $CFG->themewww
.'/'.$themename; // Only to help old themes (1.4 and earlier)
2642 function theme_setup($theme = '', $params=NULL) {
2643 /// Sets up global variables related to themes
2645 global $CFG, $THEME, $SESSION, $USER, $HTTPSPAGEREQUIRED;
2647 if (empty($theme)) {
2648 $theme = current_theme();
2651 /// If the theme doesn't exist for some reason then revert to standardwhite
2652 if (!file_exists($CFG->themedir
.'/'. $theme .'/config.php')) {
2653 $CFG->theme
= $theme = 'standardwhite';
2656 /// Load up the theme config
2657 $THEME = NULL; // Just to be sure
2658 include($CFG->themedir
.'/'. $theme .'/config.php'); // Main config for current theme
2660 /// Put together the parameters
2664 if ($theme != $CFG->theme
) {
2665 $params[] = 'forceconfig='.$theme;
2668 /// Force language too if required
2669 if (!empty($THEME->langsheets
)) {
2670 $params[] = 'lang='.current_language();
2673 /// Convert params to string
2675 $paramstring = '?'.implode('&', $params);
2680 /// Set up image paths
2681 if(isset($CFG->smartpix
) && $CFG->smartpix
==1) {
2682 if($CFG->slasharguments
) { // Use this method if possible for better caching
2688 $CFG->pixpath
= $CFG->wwwroot
. '/pix/smartpix.php'.$extra.'/'.$theme;
2689 $CFG->modpixpath
= $CFG->wwwroot
.'/pix/smartpix.php'.$extra.'/'.$theme.'/mod';
2690 } else if (empty($THEME->custompix
)) { // Could be set in the above file
2691 $CFG->pixpath
= $CFG->wwwroot
.'/pix';
2692 $CFG->modpixpath
= $CFG->wwwroot
.'/mod';
2694 $CFG->pixpath
= $CFG->themewww
.'/'. $theme .'/pix';
2695 $CFG->modpixpath
= $CFG->themewww
.'/'. $theme .'/pix/mod';
2698 /// Header and footer paths
2699 $CFG->header
= $CFG->themedir
.'/'. $theme .'/header.html';
2700 $CFG->footer
= $CFG->themedir
.'/'. $theme .'/footer.html';
2702 /// Define stylesheet loading order
2703 $CFG->stylesheets
= array();
2704 if ($theme != 'standard') { /// The standard sheet is always loaded first
2705 $CFG->stylesheets
[] = $CFG->themewww
.'/standard/styles.php'.$paramstring;
2707 if (!empty($THEME->parent
)) { /// Parent stylesheets are loaded next
2708 $CFG->stylesheets
[] = $CFG->themewww
.'/'.$THEME->parent
.'/styles.php'.$paramstring;
2710 $CFG->stylesheets
[] = $CFG->themewww
.'/'.$theme.'/styles.php'.$paramstring;
2712 /// We have to change some URLs in styles if we are in a $HTTPSPAGEREQUIRED page
2713 if (!empty($HTTPSPAGEREQUIRED)) {
2714 $CFG->themewww
= str_replace('http:', 'https:', $CFG->themewww
);
2715 $CFG->pixpath
= str_replace('http:', 'https:', $CFG->pixpath
);
2716 $CFG->modpixpath
= str_replace('http:', 'https:', $CFG->modpixpath
);
2717 foreach ($CFG->stylesheets
as $key => $stylesheet) {
2718 $CFG->stylesheets
[$key] = str_replace('http:', 'https:', $stylesheet);
2726 * Returns text to be displayed to the user which reflects their login status
2730 * @param course $course {@link $COURSE} object containing course information
2731 * @param user $user {@link $USER} object containing user information
2734 function user_login_string($course=NULL, $user=NULL) {
2735 global $USER, $CFG, $SITE;
2737 if (empty($user) and !empty($USER->id
)) {
2741 if (empty($course)) {
2745 if (isset($user->realuser
)) {
2746 if ($realuser = get_record('user', 'id', $user->realuser
)) {
2747 $fullname = fullname($realuser, true);
2748 $realuserinfo = " [<a $CFG->frametarget
2749 href=\"$CFG->wwwroot/course/loginas.php?id=$course->id&return=1\">$fullname</a>] ";
2755 if (empty($CFG->loginhttps
)) {
2756 $wwwroot = $CFG->wwwroot
;
2758 $wwwroot = str_replace('http:','https:',$CFG->wwwroot
);
2761 if (empty($course->id
)) {
2762 // $course->id is not defined during installation
2764 } else if (isset($user->id
) and $user->id
) {
2765 $context = get_context_instance(CONTEXT_COURSE
, $course->id
);
2767 $fullname = fullname($user, true);
2768 $username = "<a $CFG->frametarget href=\"$CFG->wwwroot/user/view.php?id=$user->id&course=$course->id\">$fullname</a>";
2769 if (is_mnet_remote_user($user) and $idprovider = get_record('mnet_host', 'id', $user->mnethostid
)) {
2770 $username .= " from <a $CFG->frametarget href=\"{$idprovider->wwwroot}\">{$idprovider->name}</a>";
2772 if (isset($user->username
) && $user->username
== 'guest') {
2773 $loggedinas = $realuserinfo.get_string('loggedinasguest').
2774 " (<a $CFG->frametarget href=\"$wwwroot/login/index.php\">".get_string('login').'</a>)';
2775 } else if (!empty($user->switchrole
[$context->id
])) {
2777 if ($role = get_record('role', 'id', $user->switchrole
[$context->id
])) {
2778 $rolename = ': '.format_string($role->name
);
2780 $loggedinas = get_string('loggedinas', 'moodle', $username).$rolename.
2781 " (<a $CFG->frametarget
2782 href=\"$CFG->wwwroot/course/view.php?id=$course->id&switchrole=0&sesskey=".sesskey()."\">".get_string('switchrolereturn').'</a>)';
2784 $loggedinas = $realuserinfo.get_string('loggedinas', 'moodle', $username).' '.
2785 " (<a $CFG->frametarget href=\"$CFG->wwwroot/login/logout.php?sesskey=".sesskey()."\">".get_string('logout').'</a>)';
2788 $loggedinas = get_string('loggedinnot', 'moodle').
2789 " (<a $CFG->frametarget href=\"$wwwroot/login/index.php\">".get_string('login').'</a>)';
2791 return '<div class="logininfo">'.$loggedinas.'</div>';
2795 * Tests whether $THEME->rarrow, $THEME->larrow have been set (theme/-/config.php).
2796 * If not it applies sensible defaults.
2798 * Accessibility: right and left arrow Unicode characters for breadcrumb, calendar,
2799 * search forum block, etc. Important: these are 'silent' in a screen-reader
2800 * (unlike > »), and must be accompanied by text.
2803 function check_theme_arrows() {
2806 if (!isset($THEME->rarrow
) and !isset($THEME->larrow
)) {
2807 // Default, looks good in Win XP/IE 6, Win/Firefox 1.5, Win/Netscape 8...
2808 // Also OK in Win 9x/2K/IE 5.x
2809 $THEME->rarrow
= '►';
2810 $THEME->larrow
= '◄';
2811 $uagent = $_SERVER['HTTP_USER_AGENT'];
2812 if (false !== strpos($uagent, 'Opera')
2813 ||
false !== strpos($uagent, 'Mac')) {
2814 // Looks good in Win XP/Mac/Opera 8/9, Mac/Firefox 2, Camino, Safari.
2815 // Not broken in Mac/IE 5, Mac/Netscape 7 (?).
2816 $THEME->rarrow
= '▶';
2817 $THEME->larrow
= '◀';
2819 elseif (false !== strpos($uagent, 'Konqueror')) {
2820 $THEME->rarrow
= '→';
2821 $THEME->larrow
= '←';
2823 elseif (isset($_SERVER['HTTP_ACCEPT_CHARSET'])
2824 && false === stripos($_SERVER['HTTP_ACCEPT_CHARSET'], 'utf-8')) {
2825 // (Win/IE 5 doesn't set ACCEPT_CHARSET, but handles Unicode.)
2826 // To be safe, non-Unicode browsers!
2827 $THEME->rarrow
= '>';
2828 $THEME->larrow
= '<';
2834 * Prints breadcrumb trail of links, called in theme/-/header.html
2837 * @param string $navigation The breadcrumb navigation string to be printed
2838 * @param string $separator The breadcrumb trail separator. The default 0 leads to the use
2839 * of $THEME->rarrow, themes could use '→', '/', or '' for a style-sheet solution.
2840 * @param boolean $return False to echo the breadcrumb string (default), true to return it.
2842 function print_navigation ($navigation, $separator=0, $return=false) {
2843 global $CFG, $THEME;
2846 check_theme_arrows();
2847 if (0 === $separator) {
2848 $separator = $THEME->rarrow
;
2850 if (!empty($separator)) {
2851 $separator = '<span class="sep">'. $separator .'</span>';
2856 if (!is_array($navigation)) {
2857 $ar = explode('->', $navigation);
2858 $navigation = array();
2860 foreach ($ar as $a) {
2861 if (strpos($a, '</a>') === false) {
2862 $navigation[] = array('title' => trim(format_string($a)), 'url' => '');
2864 if (preg_match('/<a.*href="([^"]*)">(.*)<\/a>/', $a, $matches)) {
2865 $navigation[] = array('title' => trim(format_string($matches[2])), 'url' => $matches[1]);
2871 if (! $site = get_site()) {
2872 $site = new object();
2873 $site->shortname
= get_string('home');
2876 //Accessibility: breadcrumb links now in a list, » replaced with a 'silent' character.
2877 $nav_text = get_string('youarehere','access');
2878 $output .= '<h2 class="accesshide">'.$nav_text."</h2><ul>\n";
2880 $output .= '<li class="first"><a '.$CFG->frametarget
.' onclick="this.target=\''.$CFG->framename
.'\'" href="'
2881 .$CFG->wwwroot
.((!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM
, SITEID
))
2882 && !empty($USER->id
) && !empty($CFG->mymoodleredirect
) && !isguest())
2883 ?
'/my' : '') .'/">'. format_string($site->shortname
) ."</a></li>\n";
2886 foreach ($navigation as $navitem) {
2888 $title = strip_tags(format_string($title));
2890 $output .= '<li class="first">'."$separator $title</li>\n";
2892 $output .= '<li class="first">' . $separator . ' <a '.$CFG->frametarget
.' onclick="this.target=\''.$CFG->framename
.'\'" href="'
2893 .$url.'">'."$title</a></li>\n";
2897 $output .= "</ul>\n";
2908 * Prints a string in a specified size (retained for backward compatibility)
2910 * @param string $text The text to be displayed
2911 * @param int $size The size to set the font for text display.
2913 function print_headline($text, $size=2, $return=false) {
2914 $output = print_heading($text, '', $size, true);
2923 * Prints text in a format for use in headings.
2925 * @param string $text The text to be displayed
2926 * @param string $align The alignment of the printed paragraph of text
2927 * @param int $size The size to set the font for text display.
2929 function print_heading($text, $align='', $size=2, $class='main', $return=false) {
2931 $align = ' style="text-align:'.$align.';"';
2934 $class = ' class="'.$class.'"';
2936 $output = "<h$size $align $class>".stripslashes_safe($text)."</h$size>";
2946 * Centered heading with attached help button (same title text)
2947 * and optional icon attached
2949 * @param string $text The text to be displayed
2950 * @param string $helppage The help page to link to
2951 * @param string $module The module whose help should be linked to
2952 * @param string $icon Image to display if needed
2954 function print_heading_with_help($text, $helppage, $module='moodle', $icon='', $return=false) {
2956 $output .= '<h2 class="main help">'.$icon.stripslashes_safe($text);
2957 $output .= helpbutton($helppage, $text, $module, true, false, '', true);
2968 function print_heading_block($heading, $class='', $return=false) {
2969 //Accessibility: 'headingblock' is now H1, see theme/standard/styles_*.css: ??
2970 $output = '<h2 class="headingblock header '.$class.'">'.stripslashes($heading).'</h2>';
2981 * Print a link to continue on to another page.
2984 * @param string $link The url to create a link to.
2986 function print_continue($link, $return=false) {
2990 // in case we are logging upgrade in admin/index.php stop it
2991 if (function_exists('upgrade_log_finish')) {
2992 upgrade_log_finish();
2998 if (!empty($_SERVER['HTTP_REFERER'])) {
2999 $link = $_SERVER['HTTP_REFERER'];
3000 $link = str_replace('&', '&', $link); // make it valid XHTML
3002 $link = $CFG->wwwroot
.'/';
3006 $output .= '<div class="continuebutton">';
3008 $output .= print_single_button($link, NULL, get_string('continue'), 'post', $CFG->framename
, true);
3009 $output .= '</div>'."\n";
3020 * Print a message in a standard themed box.
3021 * Replaces print_simple_box (see deprecatedlib.php)
3023 * @param string $message, the content of the box
3024 * @param string $classes, space-separated class names.
3025 * @param string $ids, space-separated id names.
3026 * @param boolean $return, return as string or just print it
3028 function print_box($message, $classes='generalbox', $ids='', $return=false) {
3030 $output = print_box_start($classes, $ids, true);
3031 $output .= stripslashes_safe($message);
3032 $output .= print_box_end(true);
3042 * Starts a box using divs
3043 * Replaces print_simple_box_start (see deprecatedlib.php)
3045 * @param string $classes, space-separated class names.
3046 * @param string $ids, space-separated id names.
3047 * @param boolean $return, return as string or just print it
3049 function print_box_start($classes='generalbox', $ids='', $return=false) {
3053 $ids = ' id="'.$ids.'"';
3056 $output .= '<div'.$ids.' class="box '.$classes.'">';
3067 * Simple function to end a box (see above)
3068 * Replaces print_simple_box_end (see deprecatedlib.php)
3070 * @param boolean $return, return as string or just print it
3072 function print_box_end($return=false) {
3083 * Print a self contained form with a single submit button.
3085 * @param string $link ?
3086 * @param array $options ?
3087 * @param string $label ?
3088 * @param string $method ?
3089 * @todo Finish documenting this function
3091 function print_single_button($link, $options, $label='OK', $method='get', $target='_self', $return=false) {
3093 $link = str_replace('"', '"', $link); //basic XSS protection
3094 $output .= '<div class="singlebutton">';
3095 // taking target out, will need to add later target="'.$target.'"
3096 $output .= '<form action="'. $link .'" method="'. $method .'">';
3099 foreach ($options as $name => $value) {
3100 $output .= '<input type="hidden" name="'. $name .'" value="'. s($value) .'" />';
3103 $output .= '<input type="submit" value="'. s($label) .'" /></div></form></div>';
3114 * Print a spacer image with the option of including a line break.
3116 * @param int $height ?
3117 * @param int $width ?
3118 * @param boolean $br ?
3119 * @todo Finish documenting this function
3121 function print_spacer($height=1, $width=1, $br=true, $return=false) {
3125 $output .= '<img class="spacer" height="'. $height .'" width="'. $width .'" src="'. $CFG->wwwroot
.'/pix/spacer.gif" alt="" />';
3127 $output .= '<br />'."\n";
3138 * Given the path to a picture file in a course, or a URL,
3139 * this function includes the picture in the page.
3141 * @param string $path ?
3142 * @param int $courseid ?
3143 * @param int $height ?
3144 * @param int $width ?
3145 * @param string $link ?
3146 * @todo Finish documenting this function
3148 function print_file_picture($path, $courseid=0, $height='', $width='', $link='', $return=false) {
3153 $height = 'height="'. $height .'"';
3156 $width = 'width="'. $width .'"';
3159 $output .= '<a href="'. $link .'">';
3161 if (substr(strtolower($path), 0, 7) == 'http://') {
3162 $output .= '<img style="height:'.$height.'px;width:'.$width.'px;" src="'. $path .'" />';
3164 } else if ($courseid) {
3165 $output .= '<img style="height:'.$height.'px;width:'.$width.'px;" src="';
3166 if ($CFG->slasharguments
) { // Use this method if possible for better caching
3167 $output .= $CFG->wwwroot
.'/file.php/'. $courseid .'/'. $path;
3169 $output .= $CFG->wwwroot
.'/file.php?file=/'. $courseid .'/'. $path;
3173 $output .= 'Error: must pass URL or course';
3187 * Print the specified user's avatar.
3189 * @param int $userid ?
3190 * @param int $courseid ?
3191 * @param boolean $picture Print the user picture?
3192 * @param int $size Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatability
3193 * @param boolean $return If false print picture to current page, otherwise return the output as string
3194 * @param boolean $link Enclose printed image in a link to view specified course?
3195 * @param string $target link target attribute
3196 * @param boolean $alttext use username or userspecified text in image alt attribute
3198 * @todo Finish documenting this function
3200 function print_user_picture($userid, $courseid, $picture, $size=0, $return=false, $link=true, $target='', $alttext=true) {
3205 $target=' target="_blank"';
3207 $output = '<a '.$target.' href="'. $CFG->wwwroot
.'/user/view.php?id='. $userid .'&course='. $courseid .'">';
3214 } else if ($size === true or $size == 1) {
3217 } else if ($size >= 50) {
3222 $class = "userpicture";
3223 if ($picture) { // Print custom user picture
3224 if ($CFG->slasharguments
) { // Use this method if possible for better caching
3225 $src = $CFG->wwwroot
.'/user/pix.php/'. $userid .'/'. $file .'.jpg';
3227 $src = $CFG->wwwroot
.'/user/pix.php?file=/'. $userid .'/'. $file .'.jpg';
3229 } else { // Print default user pictures (use theme version if available)
3230 $class .= " defaultuserpic";
3231 $src = "$CFG->pixpath/u/$file.png";
3234 if ($alttext and $user = get_record('user','id',$userid)) {
3235 if (!empty($user->imagealt
)) {
3236 $imagealt = $user->imagealt
;
3238 $imagealt = get_string('pictureof','',fullname($user));
3242 $output .= '<img class="'.$class.'" src="'.$src.'" alt="'.s($imagealt).'" />';
3255 * Prints a summary of a user in a nice little box.
3259 * @param user $user A {@link $USER} object representing a user
3260 * @param course $course A {@link $COURSE} object representing a course
3262 function print_user($user, $course, $messageselect=false, $return=false) {
3272 $context = get_context_instance(CONTEXT_COURSE
, $course->id
);
3274 if (empty($string)) { // Cache all the strings for the rest of the page
3276 $string->email
= get_string('email');
3277 $string->location
= get_string('location');
3278 $string->lastaccess
= get_string('lastaccess');
3279 $string->activity
= get_string('activity');
3280 $string->unenrol
= get_string('unenrol');
3281 $string->loginas
= get_string('loginas');
3282 $string->fullprofile
= get_string('fullprofile');
3283 $string->role
= get_string('role');
3284 $string->name
= get_string('name');
3285 $string->never
= get_string('never');
3287 $datestring->day
= get_string('day');
3288 $datestring->days
= get_string('days');
3289 $datestring->hour
= get_string('hour');
3290 $datestring->hours
= get_string('hours');
3291 $datestring->min
= get_string('min');
3292 $datestring->mins
= get_string('mins');
3293 $datestring->sec
= get_string('sec');
3294 $datestring->secs
= get_string('secs');
3296 $countries = get_list_of_countries();
3299 /// Get the hidden field list
3300 if (has_capability('moodle/course:viewhiddenuserfields', $context)) {
3301 $hiddenfields = array();
3303 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields
));
3306 $output .= '<table class="userinfobox">';
3308 $output .= '<td class="left side">';
3309 $output .= print_user_picture($user->id
, $course->id
, $user->picture
, true, true);
3311 $output .= '<td class="content">';
3312 $output .= '<div class="username">'.fullname($user, has_capability('moodle/site:viewfullnames', $context)).'</div>';
3313 $output .= '<div class="info">';
3314 if (!empty($user->role
) and ($user->role
<> $course->teacher
)) {
3315 $output .= $string->role
.': '. $user->role
.'<br />';
3317 if ($user->maildisplay
== 1 or ($user->maildisplay
== 2 and ($course->id
!= SITEID
) and !isguest()) or
3318 has_capability('moodle/course:viewhiddenuserfields', $context)) {
3319 $output .= $string->email
.': <a href="mailto:'. $user->email
.'">'. $user->email
.'</a><br />';
3321 if (($user->city
or $user->country
) and (!isset($hiddenfields['city']) or !isset($hiddenfields['country']))) {
3322 $output .= $string->location
.': ';
3323 if ($user->city
&& !isset($hiddenfields['city'])) {
3324 $output .= $user->city
;
3326 if (!empty($countries[$user->country
]) && !isset($hiddenfields['country'])) {
3327 if ($user->city
&& !isset($hiddenfields['city'])) {
3330 $output .= $countries[$user->country
];
3332 $output .= '<br />';
3335 if (!isset($hiddenfields['lastaccess'])) {
3336 if ($user->lastaccess
) {
3337 $output .= $string->lastaccess
.': '. userdate($user->lastaccess
);
3338 $output .= ' ('. format_time(time() - $user->lastaccess
, $datestring) .')';
3340 $output .= $string->lastaccess
.': '. $string->never
;
3343 $output .= '</div></td><td class="links">';
3345 if ($CFG->bloglevel
> 0) {
3346 $output .= '<a href="'.$CFG->wwwroot
.'/blog/index.php?userid='.$user->id
.'">'.get_string('blogs','blog').'</a><br />';
3349 if (has_capability('moodle/site:viewreports', $context)) {
3350 $timemidnight = usergetmidnight(time());
3351 $output .= '<a href="'. $CFG->wwwroot
.'/course/user.php?id='. $course->id
.'&user='. $user->id
.'">'. $string->activity
.'</a><br />';
3353 if (has_capability('moodle/role:assign', $context, NULL)) { // Includes admins
3354 $output .= '<a href="'. $CFG->wwwroot
.'/course/unenrol.php?id='. $course->id
.'&user='. $user->id
.'">'. $string->unenrol
.'</a><br />';
3356 if ($USER->id
!= $user->id
&& has_capability('moodle/user:loginas', $context) &&
3357 ! has_capability('moodle/site:doanything', $context, $user->id
, false)) {
3358 $output .= '<a href="'. $CFG->wwwroot
.'/course/loginas.php?id='. $course->id
.'&user='. $user->id
.'">'. $string->loginas
.'</a><br />';
3360 $output .= '<a href="'. $CFG->wwwroot
.'/user/view.php?id='. $user->id
.'&course='. $course->id
.'">'. $string->fullprofile
.'...</a>';
3362 if (!empty($messageselect)) {
3363 $output .= '<br /><input type="checkbox" name="user'.$user->id
.'" /> ';
3366 $output .= '</td></tr></table>';
3376 * Print a specified group's avatar.
3378 * @param group $group A {@link group} object representing a group or array of groups
3379 * @param int $courseid ?
3380 * @param boolean $large ?
3381 * @param boolean $return ?
3382 * @param boolean $link ?
3384 * @todo Finish documenting this function
3386 function print_group_picture($group, $courseid, $large=false, $return=false, $link=true) {
3389 if (is_array($group)) {
3391 foreach($group as $g) {
3392 $output .= print_group_picture($g, $courseid, $large, true, $link);
3402 $context = get_context_instance(CONTEXT_COURSE
, $courseid);
3404 if ($group->hidepicture
and !has_capability('moodle/course:managegroups', $context)) {
3408 if ($link or has_capability('moodle/site:accessallgroups', $context)) {
3409 $output = '<a href="'. $CFG->wwwroot
.'/user/index.php?id='. $courseid .'&group='. $group->id
.'">';
3420 if ($group->picture
) { // Print custom group picture
3421 if ($CFG->slasharguments
) { // Use this method if possible for better caching
3422 $output .= '<img class="grouppicture" src="'.$CFG->wwwroot
.'/user/pixgroup.php/'.$group->id
.'/'.$file.'.jpg"'.
3423 ' style="width:'.$size.'px;height:'.$size.'px;" alt="'.s(get_string('group').' '.$group->name
).'" title="'.s($group->name
).'"/>';
3425 $output .= '<img class="grouppicture" src="'.$CFG->wwwroot
.'/user/pixgroup.php?file=/'.$group->id
.'/'.$file.'.jpg"'.
3426 ' style="width:'.$size.'px;height:'.$size.'px;" alt="'.s(get_string('group').' '.$group->name
).'" title="'.s($group->name
).'"/>';
3429 if ($link or has_capability('moodle/site:accessallgroups', $context)) {
3441 * Print a png image.
3443 * @param string $url ?
3444 * @param int $sizex ?
3445 * @param int $sizey ?
3446 * @param boolean $return ?
3447 * @param string $parameters ?
3448 * @todo Finish documenting this function
3450 function print_png($url, $sizex, $sizey, $return, $parameters='alt=""') {
3454 if (!isset($recentIE)) {
3455 $recentIE = check_browser_version('MSIE', '5.0');
3458 if ($recentIE) { // work around the HORRIBLE bug IE has with alpha transparencies
3459 $output .= '<img src="'. $CFG->pixpath
.'/spacer.gif" width="'. $sizex .'" height="'. $sizey .'"'.
3460 ' class="png" style="width: '. $sizex .'px; height: '. $sizey .'px; '.
3461 ' filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='.
3462 "'$url', sizingMethod='scale') ".
3463 ' '. $parameters .' />';
3465 $output .= '<img src="'. $url .'" style="width: '. $sizex .'px; height: '. $sizey .'px; '. $parameters .' />';
3476 * Print a nicely formatted table.
3478 * @param array $table is an object with several properties.
3479 * <ul<li>$table->head - An array of heading names.
3480 * <li>$table->align - An array of column alignments
3481 * <li>$table->size - An array of column sizes
3482 * <li>$table->wrap - An array of "nowrap"s or nothing
3483 * <li>$table->data[] - An array of arrays containing the data.
3484 * <li>$table->width - A percentage of the page
3485 * <li>$table->tablealign - Align the whole table
3486 * <li>$table->cellpadding - Padding on each cell
3487 * <li>$table->cellspacing - Spacing between cells
3489 * @param bool $return whether to return an output string or echo now
3490 * @return boolean or $string
3491 * @todo Finish documenting this function
3493 function print_table($table, $return=false) {
3496 if (isset($table->align
)) {
3497 foreach ($table->align
as $key => $aa) {
3499 $align[$key] = ' text-align:'. $aa.';';
3505 if (isset($table->size
)) {
3506 foreach ($table->size
as $key => $ss) {
3508 $size[$key] = ' width:'. $ss .';';
3514 if (isset($table->wrap
)) {
3515 foreach ($table->wrap
as $key => $ww) {
3517 $wrap[$key] = ' white-space:nowrap;';
3524 if (empty($table->width
)) {
3525 $table->width
= '80%';
3528 if (empty($table->tablealign
)) {
3529 $table->tablealign
= 'center';
3532 if (empty($table->cellpadding
)) {
3533 $table->cellpadding
= '5';
3536 if (empty($table->cellspacing
)) {
3537 $table->cellspacing
= '1';
3540 if (empty($table->class)) {
3541 $table->class = 'generaltable';
3544 $tableid = empty($table->id
) ?
'' : 'id="'.$table->id
.'"';
3546 $output .= '<table width="'.$table->width
.'" ';
3547 $output .= " cellpadding=\"$table->cellpadding\" cellspacing=\"$table->cellspacing\" class=\"$table->class boxalign$table->tablealign\" $tableid>\n";
3551 if (!empty($table->head
)) {
3552 $countcols = count($table->head
);
3554 foreach ($table->head
as $key => $heading) {
3556 if (!isset($size[$key])) {
3559 if (!isset($align[$key])) {
3563 $output .= '<th class="header c'.$key.'" scope="col">'. $heading .'</th>';
3564 // commenting the following code out as <th style does not validate MDL-7861
3565 //$output .= '<th sytle="vertical-align:top;'. $align[$key].$size[$key] .';white-space:nowrap;" class="header c'.$key.'" scope="col">'. $heading .'</th>';
3567 $output .= '</tr>'."\n";
3570 if (!empty($table->data
)) {
3572 foreach ($table->data
as $key => $row) {
3573 $oddeven = $oddeven ?
0 : 1;
3574 $output .= '<tr class="r'.$oddeven.'">'."\n";
3575 if ($row == 'hr' and $countcols) {
3576 $output .= '<td colspan="'. $countcols .'"><div class="tabledivider"></div></td>';
3577 } else { /// it's a normal row of data
3578 foreach ($row as $key => $item) {
3579 if (!isset($size[$key])) {
3582 if (!isset($align[$key])) {
3585 if (!isset($wrap[$key])) {
3588 $output .= '<td style="'. $align[$key].$size[$key].$wrap[$key] .'" class="cell c'.$key.'">'. $item .'</td>';
3591 $output .= '</tr>'."\n";
3594 $output .= '</table>'."\n";
3605 * Creates a nicely formatted table and returns it.
3607 * @param array $table is an object with several properties.
3608 * <ul<li>$table->head - An array of heading names.
3609 * <li>$table->align - An array of column alignments
3610 * <li>$table->size - An array of column sizes
3611 * <li>$table->wrap - An array of "nowrap"s or nothing
3612 * <li>$table->data[] - An array of arrays containing the data.
3613 * <li>$table->class - A css class name
3614 * <li>$table->fontsize - Is the size of all the text
3615 * <li>$table->tablealign - Align the whole table
3616 * <li>$table->width - A percentage of the page
3617 * <li>$table->cellpadding - Padding on each cell
3618 * <li>$table->cellspacing - Spacing between cells
3621 * @todo Finish documenting this function
3623 function make_table($table) {
3625 if (isset($table->align
)) {
3626 foreach ($table->align
as $key => $aa) {
3628 $align[$key] = ' align="'. $aa .'"';
3634 if (isset($table->size
)) {
3635 foreach ($table->size
as $key => $ss) {
3637 $size[$key] = ' width="'. $ss .'"';
3643 if (isset($table->wrap
)) {
3644 foreach ($table->wrap
as $key => $ww) {
3646 $wrap[$key] = ' style="white-space:nowrap;" ';
3653 if (empty($table->width
)) {
3654 $table->width
= '80%';
3657 if (empty($table->tablealign
)) {
3658 $table->tablealign
= 'center';
3661 if (empty($table->cellpadding
)) {
3662 $table->cellpadding
= '5';
3665 if (empty($table->cellspacing
)) {
3666 $table->cellspacing
= '1';
3669 if (empty($table->class)) {
3670 $table->class = 'generaltable';
3673 if (empty($table->fontsize
)) {
3676 $fontsize = '<font size="'. $table->fontsize
.'">';
3679 $output = '<table width="'. $table->width
.'" align="'. $table->tablealign
.'" ';
3680 $output .= ' cellpadding="'. $table->cellpadding
.'" cellspacing="'. $table->cellspacing
.'" class="'. $table->class .'">'."\n";
3682 if (!empty($table->head
)) {
3683 $output .= '<tr valign="top">';
3684 foreach ($table->head
as $key => $heading) {
3685 if (!isset($size[$key])) {
3688 if (!isset($align[$key])) {
3691 $output .= '<th valign="top" '. $align[$key].$size[$key] .' style="white-space:nowrap;" class="'. $table->class .'header" scope="col">'.$fontsize.$heading.'</th>';
3693 $output .= '</tr>'."\n";
3696 foreach ($table->data
as $row) {
3697 $output .= '<tr valign="top">';
3698 foreach ($row as $key => $item) {
3699 if (!isset($size[$key])) {
3702 if (!isset($align[$key])) {
3705 if (!isset($wrap[$key])) {
3708 $output .= '<td '. $align[$key].$size[$key].$wrap[$key] .' class="'. $table->class .'cell">'. $fontsize . $item .'</td>';
3710 $output .= '</tr>'."\n";
3712 $output .= '</table>'."\n";
3717 function print_recent_activity_note($time, $user, $text, $link, $return=false) {
3718 static $strftimerecent;
3721 $context = get_context_instance(CONTEXT_SYSTEM
, SITEID
);
3722 $viewfullnames = has_capability('moodle/site:viewfullnames', $context);
3724 if (empty($strftimerecent)) {
3725 $strftimerecent = get_string('strftimerecent');
3728 $date = userdate($time, $strftimerecent);
3729 $name = fullname($user, $viewfullnames);
3731 $output .= '<div class="head">';
3732 $output .= '<div class="date">'.$date.'</div> '.
3733 '<div class="name">'.fullname($user, $viewfullnames).'</div>';
3734 $output .= '</div>';
3735 $output .= '<div class="info"><a href="'.$link.'">'.format_string($text,true).'</a></div>';
3746 * Prints a basic textarea field.
3749 * @param boolean $usehtmleditor ?
3750 * @param int $rows ?
3751 * @param int $cols ?
3752 * @param null $width <b>Legacy field no longer used!</b> Set to zero to get control over mincols
3753 * @param null $height <b>Legacy field no longer used!</b> Set to zero to get control over minrows
3754 * @param string $name ?
3755 * @param string $value ?
3756 * @param int $courseid ?
3757 * @todo Finish documenting this function
3759 function print_textarea($usehtmleditor, $rows, $cols, $width, $height, $name, $value='', $courseid=0, $return=false, $id='') {
3760 /// $width and height are legacy fields and no longer used as pixels like they used to be.
3761 /// However, you can set them to zero to override the mincols and minrows values below.
3763 global $CFG, $COURSE, $HTTPSPAGEREQUIRED;
3764 static $scriptcount = 0; // For loading the htmlarea script only once.
3771 $id = 'edit-'.$name;
3774 if ( empty($CFG->editorsrc
) ) { // for backward compatibility.
3775 if (empty($courseid)) {
3776 $courseid = $COURSE->id
;
3779 if ($usehtmleditor) {
3780 if (!empty($courseid) and has_capability('moodle/course:managefiles', get_context_instance(CONTEXT_COURSE
, $courseid))) {
3781 $httpsrequired = empty($HTTPSPAGEREQUIRED) ?
'' : '&httpsrequired=1';
3782 // needed for course file area browsing in image insert plugin
3783 $str .= ($scriptcount < 1) ?
'<script type="text/javascript" src="'.
3784 $CFG->httpswwwroot
.'/lib/editor/htmlarea/htmlarea.php?id='.$courseid.$httpsrequired.'"></script>'."\n" : '';
3786 $httpsrequired = empty($HTTPSPAGEREQUIRED) ?
'' : '?httpsrequired=1';
3787 $str .= ($scriptcount < 1) ?
'<script type="text/javascript" src="'.
3788 $CFG->httpswwwroot
.'/lib/editor/htmlarea/htmlarea.php'.$httpsrequired.'"></script>'."\n" : '';
3791 $str .= ($scriptcount < 1) ?
'<script type="text/javascript" src="'.
3792 $CFG->httpswwwroot
.'/lib/editor/htmlarea/lang/en.php"></script>'."\n" : '';
3795 if ($height) { // Usually with legacy calls
3796 if ($rows < $minrows) {
3800 if ($width) { // Usually with legacy calls
3801 if ($cols < $mincols) {
3807 $str .= '<textarea class="form-textarea" id="'. $id .'" name="'. $name .'" rows="'. $rows .'" cols="'. $cols .'">';
3808 if ($usehtmleditor) {
3809 $str .= htmlspecialchars($value); // needed for editing of cleaned text!
3813 $str .= '</textarea>'."\n";
3815 if ($usehtmleditor) {
3816 $str .= editorshortcutshelpbutton();
3826 * Sets up the HTML editor on textareas in the current page.
3827 * If a field name is provided, then it will only be
3828 * applied to that field - otherwise it will be used
3829 * on every textarea in the page.
3831 * In most cases no arguments need to be supplied
3833 * @param string $name Form element to replace with HTMl editor by name
3835 function use_html_editor($name='', $editorhidebuttons='', $id='') {
3836 $editor = 'editor_'.md5($name); //name might contain illegal characters
3838 $id = 'edit-'.$name;
3840 echo "\n".'<script type="text/javascript" defer="defer">'."\n";
3841 echo '//<![CDATA['."\n\n"; // Extra \n is to fix odd wiki problem, MDL-8185
3842 echo "$editor = new HTMLArea('$id');\n";
3843 echo "var config = $editor.config;\n";
3845 echo print_editor_config($editorhidebuttons);
3848 echo "\nHTMLArea.replaceAll($editor.config);\n";
3850 echo "\n$editor.generate();\n";
3853 echo '</script>'."\n";
3856 function print_editor_config($editorhidebuttons='', $return=false) {
3859 $str = "config.pageStyle = \"body {";
3861 if (!(empty($CFG->editorbackgroundcolor
))) {
3862 $str .= " background-color: $CFG->editorbackgroundcolor;";
3865 if (!(empty($CFG->editorfontfamily
))) {
3866 $str .= " font-family: $CFG->editorfontfamily;";
3869 if (!(empty($CFG->editorfontsize
))) {
3870 $str .= " font-size: $CFG->editorfontsize;";
3874 $str .= "config.killWordOnPaste = ";
3875 $str .= (empty($CFG->editorkillword
)) ?
"false":"true";
3877 $str .= 'config.fontname = {'."\n";
3879 $fontlist = isset($CFG->editorfontlist
) ?
explode(';', $CFG->editorfontlist
) : array();
3880 $i = 1; // Counter is used to get rid of the last comma.
3882 foreach ($fontlist as $fontline) {
3883 if (!empty($fontline)) {
3887 list($fontkey, $fontvalue) = split(':', $fontline);
3888 $str .= '"'. $fontkey ."\":\t'". $fontvalue ."'";
3895 if (!empty($editorhidebuttons)) {
3896 $str .= "\nconfig.hideSomeButtons(\" ". $editorhidebuttons ." \");\n";
3897 } else if (!empty($CFG->editorhidebuttons
)) {
3898 $str .= "\nconfig.hideSomeButtons(\" ". $CFG->editorhidebuttons
." \");\n";
3901 if (!empty($CFG->editorspelling
) && !empty($CFG->aspellpath
)) {
3902 $str .= print_speller_code($CFG->htmleditor
, true);
3912 * Returns a turn edit on/off button for course in a self contained form.
3913 * Used to be an icon, but it's now a simple form button
3917 * @param int $courseid The course to update by id as found in 'course' table
3920 function update_course_icon($courseid) {
3924 $coursecontext = get_context_instance(CONTEXT_COURSE
, $courseid);
3928 if (has_capability('moodle/course:manageactivities', $coursecontext) ||
3929 has_capability('moodle/site:manageblocks', $coursecontext)) {
3932 // loop through all child context, see if user has moodle/course:manageactivities or moodle/site:manageblocks
3933 if ($children = get_child_contexts($coursecontext)) {
3934 foreach ($children as $child) {
3935 $childcontext = get_record('context', 'id', $child);
3936 if (has_capability('moodle/course:manageactivities', $childcontext) ||
3937 has_capability('moodle/site:manageblocks', $childcontext)) {
3947 if (!empty($USER->editing
)) {
3948 $string = get_string('turneditingoff');
3951 $string = get_string('turneditingon');
3955 return '<form '.$CFG->frametarget
.' method="get" action="'.$CFG->wwwroot
.'/course/view.php">'.
3957 '<input type="hidden" name="id" value="'.$courseid.'" />'.
3958 '<input type="hidden" name="edit" value="'.$edit.'" />'.
3959 '<input type="hidden" name="sesskey" value="'.sesskey().'" />'.
3960 '<input type="submit" value="'.$string.'" />'.
3966 * Returns a little popup menu for switching roles
3970 * @param int $courseid The course to update by id as found in 'course' table
3973 function switchroles_form($courseid) {
3978 if (!$context = get_context_instance(CONTEXT_COURSE
, $courseid)) {
3982 if (!empty($USER->switchrole
[$context->id
])){ // Just a button to return to normal
3984 $options['id'] = $courseid;
3985 $options['sesskey'] = sesskey();
3986 $options['switchrole'] = 0;
3988 return print_single_button($CFG->wwwroot
.'/course/view.php', $options,
3989 get_string('switchrolereturn'), 'post', '_self', true);
3992 if (has_capability('moodle/role:switchroles', $context)) {
3993 if (!$roles = get_assignable_roles($context)) {
3994 return ''; // Nothing to show!
3996 // unset default user role - it would not work
3997 unset($roles[$CFG->guestroleid
]);
3998 return popup_form($CFG->wwwroot
.'/course/view.php?id='.$courseid.'&sesskey='.sesskey().'&switchrole=',
3999 $roles, 'switchrole', '', get_string('switchroleto'), 'switchrole', get_string('switchroleto'), true);
4007 * Returns a turn edit on/off button for course in a self contained form.
4008 * Used to be an icon, but it's now a simple form button
4012 * @param int $courseid The course to update by id as found in 'course' table
4015 function update_mymoodle_icon() {
4019 if (!empty($USER->editing
)) {
4020 $string = get_string('updatemymoodleoff');
4023 $string = get_string('updatemymoodleon');
4027 return "<form $CFG->frametarget method=\"get\" action=\"$CFG->wwwroot/my/index.php\">".
4029 "<input type=\"hidden\" name=\"edit\" value=\"$edit\" />".
4030 "<input type=\"submit\" value=\"$string\" /></div></form>";
4034 * Prints the editing button on a module "view" page
4037 * @param type description
4038 * @todo Finish documenting this function
4040 function update_module_button($moduleid, $courseid, $string) {
4043 if (has_capability('moodle/course:manageactivities', get_context_instance(CONTEXT_MODULE
, $moduleid))) {
4044 $string = get_string('updatethis', '', $string);
4046 return "<form $CFG->frametarget method=\"get\" action=\"$CFG->wwwroot/course/mod.php\" onsubmit=\"this.target='{$CFG->framename}'; return true\">".//hack to allow edit on framed resources
4048 "<input type=\"hidden\" name=\"update\" value=\"$moduleid\" />".
4049 "<input type=\"hidden\" name=\"return\" value=\"true\" />".
4050 "<input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />".
4051 "<input type=\"submit\" value=\"$string\" /></div></form>";
4058 * Prints the editing button on a category page
4062 * @param int $categoryid ?
4064 * @todo Finish documenting this function
4066 function update_category_button($categoryid) {
4069 if (has_capability('moodle/category:update', get_context_instance(CONTEXT_COURSECAT
, $categoryid))) {
4070 if (!empty($USER->categoryediting
)) {
4071 $string = get_string('turneditingoff');
4074 $string = get_string('turneditingon');
4078 return "<form $CFG->frametarget method=\"get\" action=\"$CFG->wwwroot/course/category.php\">".
4080 "<input type=\"hidden\" name=\"id\" value=\"$categoryid\" />".
4081 "<input type=\"hidden\" name=\"categoryedit\" value=\"$edit\" />".
4082 "<input type=\"hidden\" name=\"sesskey\" value=\"$USER->sesskey\" />".
4083 "<input type=\"submit\" value=\"$string\" /></div></form>";
4088 * Prints the editing button on categories listing
4094 function update_categories_button() {
4097 if (has_capability('moodle/category:update', get_context_instance(CONTEXT_SYSTEM
, SITEID
))) {
4098 if (!empty($USER->categoryediting
)) {
4099 $string = get_string('turneditingoff');
4100 $categoryedit = 'off';
4102 $string = get_string('turneditingon');
4103 $categoryedit = 'on';
4106 return "<form $CFG->frametarget method=\"get\" action=\"$CFG->wwwroot/course/index.php\">".
4108 '<input type="hidden" name="categoryedit" value="'. $categoryedit .'" />'.
4109 '<input type="hidden" name="sesskey" value="'.$USER->sesskey
.'" />'.
4110 '<input type="submit" value="'. $string .'" /></div></form>';
4115 * Prints the editing button on search results listing
4116 * For bulk move courses to another category
4119 function update_categories_search_button($search,$page,$perpage) {
4122 // not sure if this capability is the best here
4123 if (has_capability('moodle/category:update', get_context_instance(CONTEXT_SYSTEM
, SITEID
))) {
4124 if (!empty($USER->categoryediting
)) {
4125 $string = get_string("turneditingoff");
4129 $string = get_string("turneditingon");
4133 return "<form $CFG->frametarget method=\"get\" action=\"$CFG->wwwroot/course/search.php\">".
4135 "<input type=\"hidden\" name=\"edit\" value=\"$edit\" />".
4136 "<input type=\"hidden\" name=\"sesskey\" value=\"$USER->sesskey\" />".
4137 "<input type=\"hidden\" name=\"search\" value=\"".s($search, true)."\" />".
4138 "<input type=\"hidden\" name=\"page\" value=\"$page\" />".
4139 "<input type=\"hidden\" name=\"perpage\" value=\"$perpage\" />".
4140 "<input type=\"submit\" value=\"".s($string)."\" /></div></form>";
4145 * Prints the editing button on group page
4149 * @param int $courseid The course group is associated with
4150 * @param int $groupid The group to update
4153 function update_group_button($courseid, $groupid) {
4156 if (has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_GROUP
, $groupid))) {
4157 $string = get_string('editgroupprofile');
4159 return "<form $CFG->frametarget method=\"get\" action=\"$CFG->wwwroot/course/group.php\">".
4161 '<input type="hidden" name="id" value="'. $courseid .'" />'.
4162 '<input type="hidden" name="group" value="'. $groupid .'" />'.
4163 '<input type="hidden" name="edit" value="on" />'.
4164 '<input type="submit" value="'. $string .'" /></div></form>';
4169 * Prints the editing button on groups page
4173 * @param int $courseid The id of the course to be edited
4175 * @todo Finish documenting this function
4177 function update_groups_button($courseid) {
4180 if (has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE
, $courseid))) {
4181 if (!empty($USER->groupsediting
)) {
4182 $string = get_string('turneditingoff');
4185 $string = get_string('turneditingon');
4189 return "<form $CFG->frametarget method=\"get\" action=\"$CFG->wwwroot/course/groups.php\">".
4191 "<input type=\"hidden\" name=\"id\" value=\"$courseid\" />".
4192 "<input type=\"hidden\" name=\"edit\" value=\"$edit\" />".
4193 "<input type=\"submit\" value=\"$string\" /></div></form>";
4198 * Prints an appropriate group selection menu
4200 * @uses VISIBLEGROUPS
4201 * @param array $groups ?
4202 * @param int $groupmode ?
4203 * @param string $currentgroup ?
4204 * @param string $urlroot ?
4205 * @param boolean $showall: if set to 0, it is a student in separate groups, do not display all participants
4206 * @todo Finish documenting this function
4208 function print_group_menu($groups, $groupmode, $currentgroup, $urlroot, $showall=1, $return=false) {
4212 /// Add an "All groups" to the start of the menu
4214 $groupsmenu[0] = get_string('allparticipants');
4216 foreach ($groups as $key => $groupname) {
4217 $groupsmenu[$key] = $groupname;
4220 if ($groupmode == VISIBLEGROUPS
) {
4221 $grouplabel = get_string('groupsvisible').':';
4223 $grouplabel = get_string('groupsseparate').':';
4225 $output .= popup_form($urlroot.'&group=', $groupsmenu, 'selectgroup', $currentgroup, '', '', '', true, 'self', $grouplabel);
4236 * Given a course and a (current) coursemodule
4237 * This function returns a small popup menu with all the
4238 * course activity modules in it, as a navigation menu
4239 * The data is taken from the serialised array stored in
4242 * @param course $course A {@link $COURSE} object.
4243 * @param course $cm A {@link $COURSE} object.
4244 * @param string $targetwindow ?
4246 * @todo Finish documenting this function
4248 function navmenu($course, $cm=NULL, $targetwindow='self') {
4250 global $CFG, $THEME, $USER;
4252 if (empty($THEME->navmenuwidth
)) {
4255 $width = $THEME->navmenuwidth
;
4262 if ($course->format
== 'weeks') {
4263 $strsection = get_string('week');
4265 $strsection = get_string('topic');
4267 $strjumpto = get_string('jumpto');
4269 /// Casting $course->modinfo to string prevents one notice when the field is null
4270 if (!$modinfo = unserialize((string)$course->modinfo
)) {
4273 $context = get_context_instance(CONTEXT_COURSE
, $course->id
);
4278 $previousmod = NULL;
4286 $sections = get_records('course_sections','course',$course->id
,'section','section,visible,summary');
4288 if (!empty($THEME->makenavmenulist
)) { /// A hack to produce an XHTML navmenu list for use in themes
4289 $THEME->navmenulist
= navmenulist($course, $sections, $modinfo, $strsection, $strjumpto, $width, $cm);
4292 foreach ($modinfo as $mod) {
4293 if ($mod->mod
== 'label') {
4297 if ($mod->section
> $course->numsections
) { /// Don't show excess hidden sections
4301 if ($mod->section
> 0 and $section <> $mod->section
) {
4302 $thissection = $sections[$mod->section
];
4304 if ($thissection->visible
or !$course->hiddensections
or
4305 has_capability('moodle/course:viewhiddensections', $context)) {
4306 $thissection->summary
= strip_tags(format_string($thissection->summary
,true));
4307 if ($course->format
== 'weeks' or empty($thissection->summary
)) {
4308 $menu[] = '--'.$strsection ." ". $mod->section
;
4310 if (strlen($thissection->summary
) < ($width-3)) {
4311 $menu[] = '--'.$thissection->summary
;
4313 $menu[] = '--'.substr($thissection->summary
, 0, $width).'...';
4319 $section = $mod->section
;
4321 //Only add visible or teacher mods to jumpmenu
4322 if ($mod->visible
or has_capability('moodle/course:viewhiddenactivities',
4323 get_context_instance(CONTEXT_MODULE
, $mod->cm
))) {
4324 $url = $mod->mod
.'/view.php?id='. $mod->cm
;
4325 if ($flag) { // the current mod is the "next" mod
4329 if ($cm == $mod->cm
) {
4332 $backmod = $previousmod;
4333 $flag = true; // set flag so we know to use next mod for "next"
4334 $mod->name
= $strjumpto;
4337 $mod->name
= strip_tags(format_string(urldecode($mod->name
),true));
4338 if (strlen($mod->name
) > ($width+
5)) {
4339 $mod->name
= substr($mod->name
, 0, $width).'...';
4341 if (!$mod->visible
) {
4342 $mod->name
= '('.$mod->name
.')';
4345 $menu[$url] = $mod->name
;
4346 $previousmod = $mod;
4349 //Accessibility: added Alt text, replaced > < with 'silent' character and 'accesshide' text.
4350 check_theme_arrows();
4352 if ($selectmod and has_capability('moodle/site:viewreports', $context)) {
4353 $logstext = get_string('alllogs');
4354 $logslink = '<li><a title="'.$logstext.'" '.$CFG->frametarget
.' href="'.
4355 $CFG->wwwroot
.'/course/report/log/index.php?chooselog=1&user=0&date=0&id='.
4356 $course->id
.'&modid='.$selectmod->cm
.'">'.
4357 '<img class="icon log" src="'.$CFG->pixpath
.'/i/log.gif" alt="'.$logstext.'" /></a></li>';
4361 $backtext= get_string('activityprev', 'access');
4362 $backmod = '<li><form action="'.$CFG->wwwroot
.'/mod/'.$backmod->mod
.'/view.php" '.$CFG->frametarget
.'><div>'.
4363 '<input type="hidden" name="id" value="'.$backmod->cm
.'" />'.
4364 '<button type="submit" title="'.$backtext.'">'.$THEME->larrow
.
4365 '<span class="accesshide">'.$backtext.'</span></button></div></form></li>';
4368 $nexttext= get_string('activitynext', 'access');
4369 $nextmod = '<li><form action="'.$CFG->wwwroot
.'/mod/'.$nextmod->mod
.'/view.php" '.$CFG->frametarget
.'><div>'.
4370 '<input type="hidden" name="id" value="'.$nextmod->cm
.'" />'.
4371 '<button type="submit" title="'.$nexttext.'">'.$THEME->rarrow
.
4372 '<span class="accesshide">'.$nexttext.'</span></button></div></form></li>';
4375 return '<div class="navigation"><ul>'.$logslink . $backmod .
4376 '<li>'.popup_form($CFG->wwwroot
.'/mod/', $menu, 'navmenupopup', $selected, $strjumpto,
4377 '', '', true, $targetwindow).'</li>'.
4378 $nextmod . '</ul></div>';
4383 * This function returns a small popup menu with all the
4384 * course activity modules in it, as a navigation menu
4385 * outputs a simple list structure in XHTML
4386 * The data is taken from the serialised array stored in
4389 * @param course $course A {@link $COURSE} object.
4391 * @todo Finish documenting this function
4393 function navmenulist($course, $sections, $modinfo, $strsection, $strjumpto, $width=50, $cmid=0) {
4400 $previousmod = NULL;
4408 $coursecontext = get_context_instance(CONTEXT_COURSE
, $course->id
);
4410 $menu[] = '<ul class="navmenulist"><li class="jumpto section"><span>'.$strjumpto.'</span><ul>';
4411 foreach ($modinfo as $mod) {
4412 if ($mod->mod
== 'label') {
4416 if ($mod->section
> $course->numsections
) { /// Don't show excess hidden sections
4420 if ($mod->section
>= 0 and $section <> $mod->section
) {
4421 $thissection = $sections[$mod->section
];
4423 if ($thissection->visible
or !$course->hiddensections
or
4424 has_capability('moodle/course:viewhiddensections', $coursecontext)) {
4425 $thissection->summary
= strip_tags(format_string($thissection->summary
,true));
4426 if (!empty($doneheading)) {
4427 $menu[] = '</ul></li>';
4429 if ($course->format
== 'weeks' or empty($thissection->summary
)) {
4430 $item = $strsection ." ". $mod->section
;
4432 if (strlen($thissection->summary
) < ($width-3)) {
4433 $item = $thissection->summary
;
4435 $item = substr($thissection->summary
, 0, $width).'...';
4438 $menu[] = '<li class="section"><span>'.$item.'</span>';
4440 $doneheading = true;
4444 $section = $mod->section
;
4446 //Only add visible or teacher mods to jumpmenu
4447 if ($mod->visible
or has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_MODULE
, $mod->id
))) {
4448 $url = $mod->mod
.'/view.php?id='. $mod->cm
;
4449 if ($flag) { // the current mod is the "next" mod
4453 $mod->name
= strip_tags(format_string(urldecode($mod->name
),true));
4454 if (strlen($mod->name
) > ($width+
5)) {
4455 $mod->name
= substr($mod->name
, 0, $width).'...';
4457 if (!$mod->visible
) {
4458 $mod->name
= '('.$mod->name
.')';
4460 $class = 'activity '.$mod->mod
;
4461 $class .= ($cmid == $mod->cm
) ?
' selected' : '';
4462 $menu[] = '<li class="'.$class.'">'.
4463 '<img src="'.$CFG->modpixpath
.'/'.$mod->mod
.'/icon.gif" alt="" />'.
4464 '<a href="'.$CFG->wwwroot
.'/mod/'.$url.'">'.$mod->name
.'</a></li>';
4465 $previousmod = $mod;
4469 $menu[] = '</ul></li>';
4471 $menu[] = '</ul></li></ul>';
4473 return implode("\n", $menu);
4477 * Prints form items with the names $day, $month and $year
4479 * @param string $day fieldname
4480 * @param string $month fieldname
4481 * @param string $year fieldname
4482 * @param int $currenttime A default timestamp in GMT
4483 * @param boolean $return
4485 function print_date_selector($day, $month, $year, $currenttime=0, $return=false) {
4487 if (!$currenttime) {
4488 $currenttime = time();
4490 $currentdate = usergetdate($currenttime);
4492 for ($i=1; $i<=31; $i++
) {
4495 for ($i=1; $i<=12; $i++
) {
4496 $months[$i] = userdate(gmmktime(12,0,0,$i,1,2000), "%B");
4498 for ($i=1970; $i<=2020; $i++
) {
4501 return choose_from_menu($days, $day, $currentdate['mday'], '', '', '0', $return)
4502 .choose_from_menu($months, $month, $currentdate['mon'], '', '', '0', $return)
4503 .choose_from_menu($years, $year, $currentdate['year'], '', '', '0', $return);
4508 *Prints form items with the names $hour and $minute
4510 * @param string $hour fieldname
4511 * @param string ? $minute fieldname
4512 * @param $currenttime A default timestamp in GMT
4513 * @param int $step minute spacing
4514 * @param boolean $return
4516 function print_time_selector($hour, $minute, $currenttime=0, $step=5, $return=false) {
4518 if (!$currenttime) {
4519 $currenttime = time();
4521 $currentdate = usergetdate($currenttime);
4523 $currentdate['minutes'] = ceil($currentdate['minutes']/$step)*$step;
4525 for ($i=0; $i<=23; $i++
) {
4526 $hours[$i] = sprintf("%02d",$i);
4528 for ($i=0; $i<=59; $i+
=$step) {
4529 $minutes[$i] = sprintf("%02d",$i);
4532 return choose_from_menu($hours, $hour, $currentdate['hours'], '','','0',$return)
4533 .choose_from_menu($minutes, $minute, $currentdate['minutes'], '','','0',$return);
4537 * Prints time limit value selector
4540 * @param int $timelimit default
4541 * @param string $unit
4542 * @param string $name
4543 * @param boolean $return
4545 function print_timer_selector($timelimit = 0, $unit = '', $name = 'timelimit', $return=false) {
4553 // Max timelimit is sessiontimeout - 10 minutes.
4554 $maxvalue = ($CFG->sessiontimeout
/ 60) - 10;
4556 for ($i=1; $i<=$maxvalue; $i++
) {
4557 $minutes[$i] = $i.$unit;
4559 return choose_from_menu($minutes, $name, $timelimit, get_string('none'), '','','0',$return);
4563 * Prints a grade menu (as part of an existing form) with help
4564 * Showing all possible numerical grades and scales
4567 * @param int $courseid ?
4568 * @param string $name ?
4569 * @param string $current ?
4570 * @param boolean $includenograde ?
4571 * @todo Finish documenting this function
4573 function print_grade_menu($courseid, $name, $current, $includenograde=true, $return=false) {
4578 $strscale = get_string('scale');
4579 $strscales = get_string('scales');
4581 $scales = get_scales_menu($courseid);
4582 foreach ($scales as $i => $scalename) {
4583 $grades[-$i] = $strscale .': '. $scalename;
4585 if ($includenograde) {
4586 $grades[0] = get_string('nograde');
4588 for ($i=100; $i>=1; $i--) {
4591 $output .= choose_from_menu($grades, $name, $current, '', '', 0, true);
4593 $linkobject = '<span class="helplink"><img class="iconhelp" alt="'.$strscales.'" src="'.$CFG->pixpath
.'/help.gif" /></span>';
4594 $output .= link_to_popup_window ('/course/scales.php?id='. $courseid .'&list=true', 'ratingscales',
4595 $linkobject, 400, 500, $strscales, 'none', true);
4605 * Prints a scale menu (as part of an existing form) including help button
4606 * Just like {@link print_grade_menu()} but without the numeric grades
4608 * @param int $courseid ?
4609 * @param string $name ?
4610 * @param string $current ?
4611 * @todo Finish documenting this function
4613 function print_scale_menu($courseid, $name, $current, $return=false) {
4618 $strscales = get_string('scales');
4619 $output .= choose_from_menu(get_scales_menu($courseid), $name, $current, '', '', 0, true);
4621 $linkobject = '<span class="helplink"><img class="iconhelp" alt="'.$strscales.'" src="'.$CFG->pixpath
.'/help.gif" /></span>';
4622 $output .= link_to_popup_window ('/course/scales.php?id='. $courseid .'&list=true', 'ratingscales',
4623 $linkobject, 400, 500, $strscales, 'none', true);
4632 * Prints a help button about a scale
4635 * @param id $courseid ?
4636 * @param object $scale ?
4637 * @todo Finish documenting this function
4639 function print_scale_menu_helpbutton($courseid, $scale, $return=false) {
4644 $strscales = get_string('scales');
4646 $linkobject = '<span class="helplink"><img class="iconhelp" alt="'.$scale->name
.'" src="'.$CFG->pixpath
.'/help.gif" /></span>';
4647 $output .= link_to_popup_window ('/course/scales.php?id='. $courseid .'&list=true&scaleid='. $scale->id
, 'ratingscale',
4648 $linkobject, 400, 500, $scale->name
, 'none', true);
4657 * Print an error page displaying an error message.
4658 * Old method, don't call directly in new code - use print_error instead.
4663 * @param string $message The message to display to the user about the error.
4664 * @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.
4666 function error ($message, $link='', $adminroot=false) {
4668 global $CFG, $SESSION;
4669 $message = clean_text($message); // In case nasties are in here
4671 if (defined('FULLME') && FULLME
== 'cron') {
4672 // Errors in cron should be mtrace'd.
4677 if (! defined('HEADER_PRINTED')) {
4678 //header not yet printed
4679 @header
('HTTP/1.0 404 Not Found');
4680 print_header(get_string('error'));
4684 print_simple_box($message, '', '', '', '', 'errorbox');
4686 // in case we are logging upgrade in admin/index.php stop it
4687 if (function_exists('upgrade_log_finish')) {
4688 upgrade_log_finish();
4692 if ( !empty($SESSION->fromurl
) ) {
4693 $link = $SESSION->fromurl
;
4694 unset($SESSION->fromurl
);
4696 $link = $CFG->wwwroot
.'/';
4701 admin_externalpage_print_footer($adminroot);
4703 print_continue($link);
4706 for ($i=0;$i<512;$i++
) { // Padding to help IE work with 404
4714 * Print an error page displaying an error message. New method - use this for new code.
4718 * @param string $errorcode The name of the string from error.php to print
4719 * @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.
4720 * @param object $a Extra words and phrases that might be required in the error string
4721 * @param boolean $adminroot Is the page an admin settings page?
4723 function print_error ($errorcode, $module='', $link='', $a=NULL, $adminroot=false) {
4727 if (empty($module) ||
$module == 'moodle' ||
$module == 'core') {
4729 $modulelink = 'moodle';
4731 $modulelink = $module;
4734 if (!empty($CFG->errordocroot
)) {
4735 $errordocroot = $CFG->errordocroot
;
4736 } else if (!empty($CFG->docroot
)) {
4737 $errordocroot = $CFG->docroot
;
4739 $errordocroot = 'http://docs.moodle.org';
4742 $message = '<p class="errormessage">'.get_string($errorcode, $module, $a).'</p>'.
4743 '<p class="errorcode">'.
4744 '<a href="'.$errordocroot.'/en/error/'.$modulelink.'/'.$errorcode.'">'.
4745 get_string('moreinformation').'</a></p>';
4746 error($message, $link, $adminroot);
4749 * Returns a string of html with an image of a help icon linked to a help page on a number of help topics.
4750 * Should be used only with htmleditor or textarea.
4751 * @param mixed $helptopics variable amount of params accepted. Each param may be a string or an array of arguments for
4755 function editorhelpbutton(){
4756 global $CFG, $SESSION;
4757 $items = func_get_args();
4759 $urlparams = array();
4761 foreach ($items as $item){
4762 if (is_array($item)){
4763 $urlparams[] = "keyword$i=".urlencode($item[0]);
4764 $urlparams[] = "title$i=".urlencode($item[1]);
4765 if (isset($item[2])){
4766 $urlparams[] = "module$i=".urlencode($item[2]);
4768 $titles[] = trim($item[1], ". \t");
4769 }elseif (is_string($item)){
4770 $urlparams[] = "button$i=".urlencode($item);
4773 $titles[] = get_string("helpreading");
4776 $titles[] = get_string("helpwriting");
4779 $titles[] = get_string("helpquestions");
4782 $titles[] = get_string("helpemoticons");
4785 $titles[] = get_string('helprichtext');
4788 $titles[] = get_string('helptext');
4791 error('Unknown help topic '.$item);
4796 if (count($titles)>1){
4797 //join last two items with an 'and'
4799 $a->one
= $titles[count($titles) - 2];
4800 $a->two
= $titles[count($titles) - 1];
4801 $titles[count($titles) - 2] = get_string('and', '', $a);
4802 unset($titles[count($titles) - 1]);
4804 $alttag = join (', ', $titles);
4806 $paramstring = join('&', $urlparams);
4807 $linkobject = '<img alt="'.$alttag.'" class="iconhelp" src="'.$CFG->pixpath
.'/help.gif" />';
4808 return link_to_popup_window(s('/lib/form/editorhelp.php?'.$paramstring), $alttag, $linkobject, 400, 500, $alttag, 'none', true);
4812 * Print a help button.
4815 * @param string $page The keyword that defines a help page
4816 * @param string $title The title of links, rollover tips, alt tags etc
4817 * 'Help with' (or the language equivalent) will be prefixed and '...' will be stripped.
4818 * @param string $module Which module is the page defined in
4819 * @param mixed $image Use a help image for the link? (true/false/"both")
4820 * @param boolean $linktext If true, display the title next to the help icon.
4821 * @param string $text If defined then this text is used in the page, and
4822 * the $page variable is ignored.
4823 * @param boolean $return If true then the output is returned as a string, if false it is printed to the current page.
4824 * @param string $imagetext The full text for the helpbutton icon. If empty use default help.gif
4826 * @todo Finish documenting this function
4828 function helpbutton ($page, $title='', $module='moodle', $image=true, $linktext=false, $text='', $return=false,
4830 global $CFG, $course;
4833 if (!empty($course->lang
)) {
4834 $forcelang = $course->lang
;
4839 if ($module == '') {
4843 $tooltip = get_string('helpprefix2', '', trim($title, ". \t"));
4849 // MDL-7469 If text link is displayed with help icon, change to alt to "help with this".
4850 $linkobject .= $title.' ';
4851 $tooltip = get_string('helpwiththis');
4854 $linkobject .= $imagetext;
4856 $linkobject .= '<img class="iconhelp" alt="'.$tooltip.'" src="'.
4857 $CFG->pixpath
.'/help.gif" />';
4860 $linkobject .= $tooltip;
4863 $tooltip .= ' ('.get_string('newwindow').')'; // Warn users about new window for Accessibility
4867 $url = '/help.php?module='. $module .'&text='. s(urlencode($text).'&forcelang='.$forcelang);
4869 $url = '/help.php?module='. $module .'&file='. $page .'.html&forcelang='.$forcelang;
4872 $link = '<span class="helplink">'.
4873 link_to_popup_window ($url, 'popup', $linkobject, 400, 500, $tooltip, 'none', true).
4884 * Print a help button.
4886 * Prints a special help button that is a link to the "live" emoticon popup
4889 * @param string $form ?
4890 * @param string $field ?
4891 * @todo Finish documenting this function
4893 function emoticonhelpbutton($form, $field, $return = false) {
4895 global $CFG, $SESSION;
4897 $SESSION->inserttextform
= $form;
4898 $SESSION->inserttextfield
= $field;
4899 $imagetext = '<img src="' . $CFG->pixpath
. '/s/smiley.gif" alt="" class="emoticon" style="margin-left:3px; padding-right:1px;width:15px;height:15px;" />';
4900 $help = helpbutton('emoticons', get_string('helpemoticons'), 'moodle', true, true, '', true, $imagetext);
4909 * Print a help button.
4911 * Prints a special help button for html editors (htmlarea in this case)
4914 function editorshortcutshelpbutton() {
4917 $imagetext = '<img src="' . $CFG->httpswwwroot
. '/lib/editor/htmlarea/images/kbhelp.gif" alt="'.
4918 get_string('editorshortcutkeys').'" class="iconkbhelp" />';
4920 return helpbutton('editorshortcuts', get_string('editorshortcutkeys'), 'moodle', true, false, '', true, $imagetext);
4924 * Print a message and exit.
4927 * @param string $message ?
4928 * @param string $link ?
4929 * @todo Finish documenting this function
4931 function notice ($message, $link='', $course=NULL, $adminroot='') {
4934 $message = clean_text($message);
4936 print_box($message, 'generalbox', 'notice');
4937 print_continue($link);
4939 // xhtml strict fix, need to make sure it's the right footer
4941 admin_externalpage_print_footer($adminroot);
4945 if (empty($course)) {
4946 print_footer($SITE);
4948 print_footer($course);
4954 * Print a message along with "Yes" and "No" links for the user to continue.
4956 * @param string $message The text to display
4957 * @param string $linkyes The link to take the user to if they choose "Yes"
4958 * @param string $linkno The link to take the user to if they choose "No"
4960 function notice_yesno ($message, $linkyes, $linkno, $optionsyes=NULL, $optionsno=NULL, $methodyes='post', $methodno='post') {
4964 $message = clean_text($message);
4965 $linkyes = clean_text($linkyes);
4966 $linkno = clean_text($linkno);
4968 print_box_start('generalbox', 'notice');
4969 echo '<p>'. $message .'</p>';
4970 echo '<div class="buttons">';
4971 print_single_button($linkyes, $optionsyes, get_string('yes'), $methodyes, $CFG->framename
);
4972 print_single_button($linkno, $optionsno, get_string('no'), $methodno, $CFG->framename
);
4978 * Redirects the user to another page, after printing a notice
4980 * @param string $url The url to take the user to
4981 * @param string $message The text message to display to the user about the redirect, if any
4982 * @param string $delay How long before refreshing to the new page at $url?
4983 * @todo '&' needs to be encoded into '&' for XHTML compliance,
4984 * however, this is not true for javascript. Therefore we
4985 * first decode all entities in $url (since we cannot rely on)
4986 * the correct input) and then encode for where it's needed
4987 * echo "<script type='text/javascript'>alert('Redirect $url');</script>";
4989 function redirect($url, $message='', $delay=-1, $adminroot = '') {
4993 if (!empty($CFG->usesid
) && !isset($_COOKIE[session_name()])) {
4994 $url = sid_process_url($url);
4997 $message = clean_text($message);
4999 $url = html_entity_decode($url);
5000 $url = str_replace(array("\n", "\r"), '', $url); // some more cleaning
5001 $encodedurl = htmlentities($url);
5002 $tmpstr = clean_text('<a href="'.$encodedurl.'" />'); //clean encoded URL
5003 $encodedurl = substr($tmpstr, 9, strlen($tmpstr)-13);
5004 $url = html_entity_decode($encodedurl);
5005 $surl = addslashes($url);
5007 /// At developer debug level. Don't redirect if errors have been printed on screen.
5008 $errorprinted = false;
5009 if (debugging('', DEBUG_DEVELOPER
) && $CFG->debugdisplay
&& error_get_last()) {
5010 $errorprinted = true;
5011 $message = "<strong>Error output, so disabling automatic redirect.</strong></p><p>" . $message;
5014 /// when no message and header printed yet, try to redirect
5015 if (empty($message) and !defined('HEADER_PRINTED')) {
5017 // Technically, HTTP/1.1 requires Location: header to contain
5018 // the absolute path. (In practice browsers accept relative
5019 // paths - but still, might as well do it properly.)
5020 // This code turns relative into absolute.
5021 if (!preg_match('|^[a-z]+:|', $url)) {
5022 // Get host name http://www.wherever.com
5023 $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot
);
5024 if (preg_match('|^/|', $url)) {
5025 // URLs beginning with / are relative to web server root so we just add them in
5026 $url = $hostpart.$url;
5028 // URLs not beginning with / are relative to path of current script, so add that on.
5029 $url = $hostpart.preg_replace('|\?.*$|','',me()).'/../'.$url;
5033 $newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url);
5034 if ($newurl == $url) {
5042 //try header redirection first
5043 @header
($_SERVER['SERVER_PROTOCOL'] . ' 303 See Other'); //302 might not work for POST requests, 303 is ignored by obsolete clients
5044 @header
('Location: '.$url);
5045 //another way for older browsers and already sent headers (eg trailing whitespace in config.php)
5046 echo '<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />';
5047 echo '<script type="text/javascript">'. "\n" .'//<![CDATA['. "\n". "location.replace('$surl');". "\n". '//]]>'. "\n". '</script>'; // To cope with Mozilla bug
5052 $delay = 3; // if no delay specified wait 3 seconds
5054 if (! defined('HEADER_PRINTED')) {
5055 // this type of redirect might not be working in some browsers - such as lynx :-(
5056 print_header('', '', '', '', $errorprinted ?
'' : ('<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />'));
5057 $delay +
= 3; // double redirect prevention, it was sometimes breaking upgrades before 1.7
5059 echo '<div style="text-align:center">';
5060 echo '<p>'. $message .'</p>';
5061 echo '<p>( <a href="'. $encodedurl .'">'. get_string('continue') .'</a> )</p>';
5064 if (!$errorprinted) {
5066 <script type
="text/javascript">
5069 function redirect() {
5070 document
.location
.replace('<?php echo $surl ?>');
5072 setTimeout("redirect()", <?php
echo ($delay * 1000) ?
>);
5078 // fix for MDL-8517, admin pages redirections causes bad xhtml
5080 admin_externalpage_print_footer($adminroot);
5082 print_footer('none');
5088 * Print a bold message in an optional color.
5090 * @param string $message The message to print out
5091 * @param string $style Optional style to display message text in
5092 * @param string $align Alignment option
5093 * @param bool $return whether to return an output string or echo now
5095 function notify($message, $style='notifyproblem', $align='center', $return=false) {
5096 if ($style == 'green') {
5097 $style = 'notifysuccess'; // backward compatible with old color system
5100 $message = clean_text($message);
5102 $output = '<div class="'.$style.'" style="text-align:'. $align .'">'. $message .'</div>'."<br />\n";
5112 * Given an email address, this function will return an obfuscated version of it
5114 * @param string $email The email address to obfuscate
5117 function obfuscate_email($email) {
5120 $length = strlen($email);
5122 while ($i < $length) {
5124 $obfuscated.='%'.dechex(ord($email{$i}));
5126 $obfuscated.=$email{$i};
5134 * This function takes some text and replaces about half of the characters
5135 * with HTML entity equivalents. Return string is obviously longer.
5137 * @param string $plaintext The text to be obfuscated
5140 function obfuscate_text($plaintext) {
5143 $length = strlen($plaintext);
5145 $prev_obfuscated = false;
5146 while ($i < $length) {
5147 $c = ord($plaintext{$i});
5148 $numerical = ($c >= ord('0')) && ($c <= ord('9'));
5149 if ($prev_obfuscated and $numerical ) {
5150 $obfuscated.='&#'.ord($plaintext{$i}).';';
5151 } else if (rand(0,2)) {
5152 $obfuscated.='&#'.ord($plaintext{$i}).';';
5153 $prev_obfuscated = true;
5155 $obfuscated.=$plaintext{$i};
5156 $prev_obfuscated = false;
5164 * This function uses the {@link obfuscate_email()} and {@link obfuscate_text()}
5165 * to generate a fully obfuscated email link, ready to use.
5167 * @param string $email The email address to display
5168 * @param string $label The text to dispalyed as hyperlink to $email
5169 * @param boolean $dimmed If true then use css class 'dimmed' for hyperlink
5172 function obfuscate_mailto($email, $label='', $dimmed=false) {
5174 if (empty($label)) {
5178 $title = get_string('emaildisable');
5179 $dimmed = ' class="dimmed"';
5184 return sprintf("<a href=\"%s:%s\" $dimmed title=\"$title\">%s</a>",
5185 obfuscate_text('mailto'), obfuscate_email($email),
5186 obfuscate_text($label));
5190 * Prints a single paging bar to provide access to other pages (usually in a search)
5192 * @param int $totalcount Thetotal number of entries available to be paged through
5193 * @param int $page The page you are currently viewing
5194 * @param int $perpage The number of entries that should be shown per page
5195 * @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
5196 var an equal sign, then the page number.
5197 * @param string $pagevar This is the variable name that you use for the page number in your code (ie. 'tablepage', 'blogpage', etc)
5198 * @param bool $nocurr do not display the current page as a link
5199 * @param bool $return whether to return an output string or echo now
5200 * @return bool or string
5202 function print_paging_bar($totalcount, $page, $perpage, $baseurl, $pagevar='page',$nocurr=false, $return=false) {
5206 if ($totalcount > $perpage) {
5207 $output .= '<div class="paging">';
5208 $output .= get_string('page') .':';
5210 $pagenum = $page - 1;
5211 $output .= ' (<a href="'. $baseurl . $pagevar .'='. $pagenum .'">'. get_string('previous') .'</a>) ';
5213 $lastpage = ceil($totalcount / $perpage);
5215 $startpage = $page - 10;
5216 $output .= ' <a href="'. $baseurl . $pagevar .'=0">1</a> ...';
5220 $currpage = $startpage;
5222 while ($displaycount < $maxdisplay and $currpage < $lastpage) {
5223 $displaypage = $currpage+
1;
5224 if ($page == $currpage && empty($nocurr)) {
5225 $output .= ' '. $displaypage;
5227 $output .= ' <a href="'. $baseurl . $pagevar .'='. $currpage .'">'. $displaypage .'</a>';
5232 if ($currpage < $lastpage) {
5233 $lastpageactual = $lastpage - 1;
5234 $output .= ' ...<a href="'. $baseurl . $pagevar .'='. $lastpageactual .'">'. $lastpage .'</a> ';
5236 $pagenum = $page +
1;
5237 if ($pagenum != $displaypage) {
5238 $output .= ' (<a href="'. $baseurl . $pagevar .'='. $pagenum .'">'. get_string('next') .'</a>)';
5240 $output .= '</div>';
5252 * This function is used to rebuild the <nolink> tag because some formats (PLAIN and WIKI)
5253 * will transform it to html entities
5255 * @param string $text Text to search for nolink tag in
5258 function rebuildnolinktag($text) {
5260 $text = preg_replace('/<(\/*nolink)>/i','<$1>',$text);
5266 * Prints a nice side block with an optional header. The content can either
5267 * be a block of HTML or a list of text with optional icons.
5269 * @param string $heading Block $title embedded in HTML tags, for example <h2>.
5270 * @param string $content ?
5271 * @param array $list ?
5272 * @param array $icons ?
5273 * @param string $footer ?
5274 * @param array $attributes ?
5275 * @param string $title Plain text title, as embedded in the $heading.
5276 * @todo Finish documenting this function. Show example of various attributes, etc.
5278 function print_side_block($heading='', $content='', $list=NULL, $icons=NULL, $footer='', $attributes = array(), $title='') {
5280 //Accessibility: skip block link, with title-text (or $block_id) to differentiate links.
5281 static $block_id = 0;
5283 if (empty($heading)) {
5284 $skip_text = get_string('skipblock', 'access').' '.$block_id;
5287 $skip_text = get_string('skipa', 'access', strip_tags($title));
5289 $skip_link = '<a href="#sb-'.$block_id.'" class="skip-block" title="'.$skip_text.'"><span class="accesshide">'.$skip_text.'</span></a>';
5290 $skip_dest = '<span id="sb-'.$block_id.'" class="skip-block-to"></span>';
5292 if (! empty($heading)) {
5293 $heading = $skip_link . $heading;
5295 /*else { //ELSE: I think a single link on a page, "Skip block 4" is too confusing - don't print.
5299 print_side_block_start($heading, $attributes);
5304 echo '<div class="footer">'. $footer .'</div>';
5309 //Accessibility: replaced unnecessary table with list, see themes/standard/styles_layout.css
5310 echo "\n<ul class='list'>\n";
5311 foreach ($list as $key => $string) {
5312 echo '<li class="r'. $row .'">';
5314 echo '<div class="icon column c0">'. $icons[$key] .'</div>';
5316 echo '<div class="column c1">'. $string .'</div>';
5323 echo '<div class="footer">'. $footer .'</div>';
5328 print_side_block_end($attributes);
5333 * Starts a nice side block with an optional header.
5335 * @param string $heading ?
5336 * @param array $attributes ?
5337 * @todo Finish documenting this function
5339 function print_side_block_start($heading='', $attributes = array()) {
5341 global $CFG, $THEME;
5343 // If there are no special attributes, give a default CSS class
5344 if (empty($attributes) ||
!is_array($attributes)) {
5345 $attributes = array('class' => 'sideblock');
5347 } else if(!isset($attributes['class'])) {
5348 $attributes['class'] = 'sideblock';
5350 } else if(!strpos($attributes['class'], 'sideblock')) {
5351 $attributes['class'] .= ' sideblock';
5354 // OK, the class is surely there and in addition to anything
5355 // else, it's tagged as a sideblock
5359 // IE misery: if I do it this way, blocks which start hidden cannot be "unhidden"
5361 // If there is a cookie to hide this thing, start it hidden
5362 if (!empty($attributes['id']) && isset($_COOKIE['hide:'.$attributes['id']])) {
5363 $attributes['class'] = 'hidden '.$attributes['class'];
5368 foreach ($attributes as $attr => $val) {
5369 $attrtext .= ' '.$attr.'="'.$val.'"';
5372 echo '<div '.$attrtext.'>';
5375 //Accessibility: replaced <div> with H2; no, H2 more appropriate in moodleblock.class.php: _title_html.
5376 // echo '<div class="header">'.$heading.'</div>';
5377 echo '<div class="header">';
5378 if (!empty($THEME->roundcorners
)) {
5379 echo '<div class="bt"><div></div></div>';
5380 echo '<div class="i1"><div class="i2"><div class="i3">';
5383 if (!empty($THEME->roundcorners
)) {
5384 echo '</div></div></div>';
5388 if (!empty($THEME->roundcorners
)) {
5389 echo '<div class="bt"><div></div></div>';
5393 if (!empty($THEME->roundcorners
)) {
5394 echo '<div class="i1"><div class="i2"><div class="i3">';
5396 echo '<div class="content">';
5402 * Print table ending tags for a side block box.
5404 function print_side_block_end($attributes = array()) {
5405 global $CFG, $THEME;
5409 if (!empty($THEME->roundcorners
)) {
5410 echo '</div></div></div>';
5411 echo '<div class="bb"><div></div></div>';
5416 // IE workaround: if I do it THIS way, it works! WTF?
5417 if (!empty($CFG->allowuserblockhiding
) && isset($attributes['id'])) {
5418 echo '<script type="text/javascript">'."\n//<![CDATA[\n".'elementCookieHide("'.$attributes['id'].'"); '.
5419 "\n//]]>\n".'</script>';
5426 * Prints out code needed for spellchecking.
5427 * Original idea by Ludo (Marc Alier).
5429 * Opening CDATA and <script> are output by weblib::use_html_editor()
5431 * @param boolean $usehtmleditor Normally set by $CFG->htmleditor, can be overriden here
5432 * @param boolean $return If false, echos the code instead of returning it
5433 * @todo Find out if lib/editor/htmlarea/htmlarea.class.php::print_speller_code() is still used, and delete if not
5435 function print_speller_code ($usehtmleditor=false, $return=false) {
5439 if(!$usehtmleditor) {
5440 $str .= 'function openSpellChecker() {'."\n";
5441 $str .= "\tvar speller = new spellChecker();\n";
5442 $str .= "\tspeller.popUpUrl = \"" . $CFG->wwwroot
."/lib/speller/spellchecker.html\";\n";
5443 $str .= "\tspeller.spellCheckScript = \"". $CFG->wwwroot
."/lib/speller/server-scripts/spellchecker.php\";\n";
5444 $str .= "\tspeller.spellCheckAll();\n";
5447 $str .= "function spellClickHandler(editor, buttonId) {\n";
5448 $str .= "\teditor._textArea.value = editor.getHTML();\n";
5449 $str .= "\tvar speller = new spellChecker( editor._textArea );\n";
5450 $str .= "\tspeller.popUpUrl = \"" . $CFG->wwwroot
."/lib/speller/spellchecker.html\";\n";
5451 $str .= "\tspeller.spellCheckScript = \"". $CFG->wwwroot
."/lib/speller/server-scripts/spellchecker.php\";\n";
5452 $str .= "\tspeller._moogle_edit=1;\n";
5453 $str .= "\tspeller._editor=editor;\n";
5454 $str .= "\tspeller.openChecker();\n";
5465 * Print button for spellchecking when editor is disabled
5467 function print_speller_button () {
5468 echo '<input type="button" value="Check spelling" onclick="openSpellChecker();" />'."\n";
5472 function page_id_and_class(&$getid, &$getclass) {
5473 // Create class and id for this page
5476 static $class = NULL;
5479 if (empty($CFG->pagepath
)) {
5480 $CFG->pagepath
= $ME;
5483 if (empty($class) ||
empty($id)) {
5484 $path = str_replace($CFG->httpswwwroot
.'/', '', $CFG->pagepath
); //Because the page could be HTTPSPAGEREQUIRED
5485 $path = str_replace('.php', '', $path);
5486 if (substr($path, -1) == '/') {
5489 if (empty($path) ||
$path == 'index') {
5492 } else if (substr($path, 0, 5) == 'admin') {
5493 $id = str_replace('/', '-', $path);
5496 $id = str_replace('/', '-', $path);
5497 $class = explode('-', $id);
5499 $class = implode('-', $class);
5508 * Prints a maintenance message from /maintenance.html
5510 function print_maintenance_message () {
5513 print_header(strip_tags($SITE->fullname
), $SITE->fullname
, 'home');
5514 print_simple_box_start('center');
5515 print_heading(get_string('sitemaintenance', 'admin'));
5516 @include
($CFG->dataroot
.'/1/maintenance.html');
5517 print_simple_box_end();
5522 * Adjust the list of allowed tags based on $CFG->allowobjectembed and user roles (admin)
5524 function adjust_allowed_tags() {
5526 global $CFG, $ALLOWED_TAGS;
5528 if (!empty($CFG->allowobjectembed
)) {
5529 $ALLOWED_TAGS .= '<embed><object>';
5533 /// Some code to print tabs
5535 /// A class for tabs
5540 var $linkedwhenselected;
5542 /// A constructor just because I like constructors
5543 function tabobject ($id, $link='', $text='', $title='', $linkedwhenselected=false) {
5545 $this->link
= $link;
5546 $this->text
= $text;
5547 $this->title
= $title ?
$title : $text;
5548 $this->linkedwhenselected
= $linkedwhenselected;
5555 * Returns a string containing a nested list, suitable for formatting into tabs with CSS.
5557 * @param array $tabrows An array of rows where each row is an array of tab objects
5558 * @param string $selected The id of the selected tab (whatever row it's on)
5559 * @param array $inactive An array of ids of inactive tabs that are not selectable.
5560 * @param array $activated An array of ids of other tabs that are currently activated
5562 function print_tabs($tabrows, $selected=NULL, $inactive=NULL, $activated=NULL, $return=false) {
5565 /// Bring the row with the selected tab to the front
5566 if (!empty($CFG->tabselectedtofront
) and ($selected !== NULL) ) {
5568 $frontrows = array();
5569 $rearrows = array();
5570 foreach ($tabrows as $row) {
5574 foreach ($row as $tab) {
5578 $found = ($selected == $tab->id
);
5580 $frontrows[] = $row;
5583 $tabrows = array_merge($rearrows,$frontrows);
5586 /// $inactive must be an array
5587 if (!is_array($inactive)) {
5588 $inactive = array();
5591 /// $activated must be an array
5592 if (!is_array($activated)) {
5593 $activated = array();
5596 /// Convert the tab rows into a tree that's easier to process
5597 if (!$tree = convert_tabrows_to_tree($tabrows, $selected, $inactive, $activated)) {
5601 /// Print out the current tree of tabs (this function is recursive)
5603 $output = convert_tree_to_html($tree);
5605 $output = "\n\n".'<div class="tabtree">'.$output.'</div><div class="clearer"> </div>'."\n\n";
5616 function convert_tree_to_html($tree, $row=0) {
5618 $str = "\n".'<ul class="tabrow'.$row.'">'."\n";
5621 $count = count($tree);
5623 foreach ($tree as $tab) {
5624 $count--; // countdown to zero
5628 if ($first && ($count == 0)) { // Just one in the row
5629 $liclass = 'first last';
5631 } else if ($first) {
5634 } else if ($count == 0) {
5638 if ((empty($tab->subtree
)) && (!empty($tab->selected
))) {
5639 $liclass .= (empty($liclass)) ?
'onerow' : ' onerow';
5642 if ($tab->inactive ||
$tab->active ||
($tab->selected
&& !$tab->linkedwhenselected
)) {
5643 if ($tab->selected
) {
5644 $liclass .= (empty($liclass)) ?
'here selected' : ' here selected';
5645 } else if ($tab->active
) {
5646 $liclass .= (empty($liclass)) ?
'here active' : ' here active';
5650 $str .= (!empty($liclass)) ?
'<li class="'.$liclass.'">' : '<li>';
5652 if ($tab->inactive ||
$tab->active ||
($tab->selected
&& !$tab->linkedwhenselected
)) {
5653 $str .= '<a href="#" title="'.$tab->title
.'"><span>'.$tab->text
.'</span></a>';
5655 $str .= '<a href="'.$tab->link
.'" title="'.$tab->title
.'"><span>'.$tab->text
.'</span></a>';
5658 if (!empty($tab->subtree
)) {
5659 $str .= convert_tree_to_html($tab->subtree
, $row+
1);
5660 } else if ($tab->selected
) {
5661 $str .= '<div class="tabrow'.($row+
1).' empty"> </div>'."\n";
5664 $str .= '</li>'."\n";
5666 $str .= '</ul>'."\n";
5672 function convert_tabrows_to_tree($tabrows, $selected, $inactive, $activated) {
5674 /// Work backwards through the rows (bottom to top) collecting the tree as we go.
5676 $tabrows = array_reverse($tabrows);
5680 foreach ($tabrows as $row) {
5683 foreach ($row as $tab) {
5684 $tab->inactive
= in_array((string)$tab->id
, $inactive);
5685 $tab->active
= in_array((string)$tab->id
, $activated);
5686 $tab->selected
= (string)$tab->id
== $selected;
5688 if ($tab->active ||
$tab->selected
) {
5690 $tab->subtree
= $subtree;
5703 * Returns a string containing a link to the user documentation for the current
5704 * page. Also contains an icon by default. Shown to teachers and admin only.
5706 * @param string $text The text to be displayed for the link
5707 * @param string $iconpath The path to the icon to be displayed
5709 function page_doc_link($text='', $iconpath='') {
5712 if (empty($CFG->docroot
) ||
!has_capability('moodle/site:doclinks')) {
5716 if (empty($CFG->pagepath
)) {
5717 $CFG->pagepath
= $ME;
5721 if (!empty($CFG->doctonewwindow
)) {
5722 $target = ' target="_blank"';
5725 $path = str_replace($CFG->httpswwwroot
.'/','', $CFG->pagepath
); // Because the page could be HTTPSPAGEREQUIRED
5726 $path = str_replace('.php', '', $path);
5728 if (empty($path)) { // Not for home page
5732 $lang = str_replace('_utf8', '', current_language());
5734 $str = '<a href="' .$CFG->docroot
. '/' .$lang. '/' .$path. '"' .$target. '>';
5736 if (empty($iconpath)) {
5737 $iconpath = $CFG->httpswwwroot
. '/pix/docs.gif';
5740 // alt left blank intentionally to prevent repetition in screenreaders
5741 $str .= '<img class="iconhelp" src="' .$iconpath. '" alt="" />' .$text. '</a>';
5747 * Returns true if the current site debugging settings are equal or above specified level.
5748 * If passed a parameter it will emit a debugging notice similar to trigger_error(). The
5749 * routing of notices is controlled by $CFG->debugdisplay
5752 * 1) debugging('a normal debug notice');
5753 * 2) debugging('something really picky', DEBUG_ALL);
5754 * 3) debugging('annoying debug message only for develpers', DEBUG_DEVELOPER);
5755 * 4) if (debugging()) { perform extra debugging operations (do not use print or echo) }
5757 * In code blocks controlled by debugging() (such as example 4)
5758 * any output should be routed via debugging() itself, or the lower-level
5759 * trigger_error() or error_log(). Using echo or print will break XHTML
5760 * JS and HTTP headers.
5763 * @param string $message a message to print
5764 * @param int $level the level at which this debugging statement should show
5767 function debugging($message='', $level=DEBUG_NORMAL
) {
5771 if (empty($CFG->debug
)) {
5775 if ($CFG->debug
>= $level) {
5777 $caller = debug_backtrace();
5778 $caller = $caller[0];
5779 $from = " in $caller[file] on line $caller[line]";
5780 if (isset($caller['function'])) {
5781 $from .= " in $caller[function]()";
5783 if (!isset($CFG->debugdisplay
)) {
5784 $CFG->debugdisplay
= ini_get('display_errors');
5786 if ($CFG->debugdisplay
) {
5787 notify($message . $from, 'notifytiny');
5789 trigger_error($message . $from, E_USER_NOTICE
);
5798 * Disable debug messages from debugging(), while keeping PHP error reporting level as is.
5800 function disable_debugging() {
5802 $CFG->debug
= $CFG->debug |
0x80000000; // switch the sign bit in integer number ;-)
5807 * Returns string to add a frame attribute, if required
5809 function frametarget() {
5812 if (empty($CFG->framename
) or ($CFG->framename
== '_top')) {
5815 return ' target="'.$CFG->framename
.'" ';
5819 // vim:autoindent:expandtab:shiftwidth=4:tabstop=4:tw=140: