Make a $homepage flag for use in footers
[moodle.git] / lib / moodlelib.php
1 <?PHP // $Id$
3 //
4 // moodlelib.php
5 //
6 // Large collection of useful functions used by many parts of Moodle.
7 //
8 // Martin Dougiamas, 2000
9 //
11 /// STANDARD WEB PAGE PARTS ///////////////////////////////////////////////////
13 function print_header ($title="", $heading="", $navigation="", $focus="", $meta="", $cache=true, $button="") {
14 // $title - appears top of window
15 // $heading - appears top of page
16 // $navigation - premade navigation string
17 // $focus - indicates form element eg  inputform.password
18 // $meta - meta tags in the header
19 // $cache - should this page be cacheable?
20 // $button - code for a button in the top-right
21     global $USER, $CFG, $THEME;
23     if (file_exists("$CFG->dirroot/theme/$CFG->theme/styles.css")) {
24         $styles = "$CFG->wwwroot/theme/$CFG->theme/styles.css";
25     } else {
26         $styles = "$CFG->wwwroot/theme/standard/styles.css";
27     }
29     if ($navigation == "home") {
30         $home = true;
31         $navigation = "";
32     }
34     if (!$button and $navigation) {
35         if (isset($USER->id)) {
36             $button = "<FONT SIZE=2><A HREF=\"$CFG->wwwroot/login/logout.php\">".get_string("logout")."</A></FONT>";
37         } else {
38             $button = "<FONT SIZE=2><A HREF=\"$CFG->wwwroot/login/index.php\">".get_string("login")."</A></FONT>";
39         }
40     }
42     // Specify character set ... default is iso-8859-1 but some languages might need something else
43     // Could be optimised by carrying the charset variable around in $USER
44     if (current_language() == "en") {
45         $meta .= "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=iso-8859-1\">\n";
46     } else {
47         $meta .= "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=".get_string("thischarset")."\">\n";
48     }
50     if ($CFG->langdir == "RTL") {
51         $direction = " DIR=\"RTL\"";
52     } else {
53         $direction = " DIR=\"LTR\"";
54     }
55  
56     if (!$cache) {   // Do everything we can to prevent clients and proxies caching
57         @header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
58         @header("Pragma: no-cache");
59         $meta .= "\n<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">";
60         $meta .= "\n<META HTTP-EQUIV=\"Expires\" CONTENT=\"0\">";
61     }
63     include ("$CFG->dirroot/theme/$CFG->theme/header.html");
64 }
66 function print_footer ($course=NULL) {
67 // Can provide a course object to make the footer contain a link to 
68 // to the course home page, otherwise the link will go to the site home
69     global $USER, $CFG, $THEME;
72 /// Course links
73     if ($course) {
74         if ($course == "home") {   // special case for site home page - please do not remove
75             $homelink  = "<P ALIGN=center><A TITLE=\"Moodle $CFG->release ($CFG->version)\" HREF=\"http://moodle.com/\">";
76             $homelink .= "<BR><IMG WIDTH=130 HEIGHT=19 SRC=\"pix/madewithmoodle2.gif\" BORDER=0></A></P>";
77             $course = get_site();
78             $homepage = true;
79         } else {
80             $homelink = "<A TARGET=_top HREF=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</A>";
81         }
82     } else {
83         $homelink = "<A TARGET=_top HREF=\"$CFG->wwwroot\">".get_string("home")."</A>";
84         $course = get_site();
85     }
87 /// User links
88     if ($USER->realuser) {
89         if ($realuser = get_record("user", "id", $USER->realuser)) {
90             $realuserinfo = " [<A HREF=\"$CFG->wwwroot/course/loginas.php?id=$course->id&return=$realuser->id\">$realuser->firstname $realuser->lastname</A>] ";
91         }
92     }
94     if ($USER->id) {
95         $username = "<A HREF=\"$CFG->wwwroot/user/view.php?id=$USER->id&course=$course->id\">$USER->firstname $USER->lastname</A>";
96         $loggedinas = $realuserinfo.get_string("loggedinas", "moodle", "$username").
97                       " (<A HREF=\"$CFG->wwwroot/login/logout.php\">".get_string("logout")."</A>)";
98     } else {
99         $loggedinas = get_string("loggedinnot", "moodle").
100                       " (<A HREF=\"$CFG->wwwroot/login/index.php\">".get_string("login")."</A>)";
101     }
103     include ("$CFG->dirroot/theme/$CFG->theme/footer.html");
108 function print_navigation ($navigation) {
109    global $CFG;
111    if ($navigation) {
112        if (! $site = get_site()) {
113            $site->shortname = get_string("home");;
114        }
115        echo "<A TARGET=_top HREF=\"$CFG->wwwroot/\">$site->shortname</A> -> $navigation";
116    }
119 function print_heading($text, $align="CENTER", $size=3) {
120     echo "<P ALIGN=\"$align\"><FONT SIZE=\"$size\"><B>".stripslashes($text)."</B></FONT></P>";
123 function print_heading_with_help($text, $helppage, $module="moodle") {
124 // Centered heading with attached help button (same title text)
125     echo "<P ALIGN=\"CENTER\"><FONT SIZE=\"3\"><B>".stripslashes($text);
126     helpbutton($helppage, $text, $module);
127     echo "</B></FONT></P>";
129     
130 function print_continue($link) {
131     global $HTTP_REFERER;
133     if (!$link) {
134         $link = $HTTP_REFERER;
135     }
137     print_heading("<A HREF=\"$link\">".get_string("continue")."</A>");
141 function print_simple_box($message, $align="", $width="", $color="#FFFFFF", $padding=5, $border=1) {
142     print_simple_box_start($align, $width, $color, $padding, $border);
143     echo "<P>".stripslashes($message)."</P>";
144     print_simple_box_end();
147 function print_simple_box_start($align="", $width="", $color="#FFFFFF", $padding=5, $border=1) {
148     global $THEME;
150     if ($align) {
151         $tablealign = "ALIGN=\"$align\"";
152     }
153     if ($width) {
154         $tablewidth = "WIDTH=\"$width\"";
155         $innertablewidth = "WIDTH=\"100%\"";
156     }
157     echo "<TABLE $tablealign $tablewidth BORDER=0 CELLPADDING=\"$border\" CELLSPACING=0>";
158     echo "<TR><TD BGCOLOR=\"$THEME->borders\">\n";
159     echo "<TABLE $innertablewidth BORDER=0 CELLPADDING=\"$padding\" CELLSPACING=0><TR><TD BGCOLOR=\"$color\">";
162 function print_simple_box_end() {
163     echo "</TD></TR></TABLE>";
164     echo "</TD></TR></TABLE>";
167 function print_single_button($link, $options, $label="OK") {
168     echo "<FORM ACTION=\"$link\" METHOD=GET>";
169     if ($options) {
170         foreach ($options as $name => $value) {
171             echo "<INPUT TYPE=hidden NAME=\"$name\" VALUE=\"$value\">";
172         }
173     }
174     echo "<INPUT TYPE=submit VALUE=\"$label\"></FORM>";
177 function print_spacer($height=1, $width=1, $br=true) {
178     global $CFG;
179     echo "<IMG HEIGHT=\"$height\" WIDTH=\"$width\" SRC=\"$CFG->wwwroot/pix/spacer.gif\" ALT=\"\">";
180     if ($br) {
181         echo "<BR>\n";
182     }
185 function print_file_picture($path, $courseid=0, $height="", $width="", $link="") {
186 // Given the path to a picture file in a course, or a URL,
187 // this function includes the picture in the page.
188     global $CFG;
190     if ($height) {
191         $height = "HEIGHT=\"$height\"";
192     }
193     if ($width) {
194         $width = "WIDTH=\"$width\"";
195     }
196     if ($link) {
197         echo "<A HREF=\"$link\">";
198     }
199     if (substr(strtolower($path), 0, 7) == "http://") {
200         echo "<IMG BORDER=0 $height $width SRC=\"$path\">";
202     } else if ($courseid) {
203         echo "<IMG BORDER=0 $height $width SRC=\"";
204         if ($CFG->slasharguments) {        // Use this method if possible for better caching
205             echo "$CFG->wwwroot/file.php/$courseid/$path";
206         } else {
207             echo "$CFG->wwwroot/file.php?file=$courseid/$path";
208         }
209         echo "\">";
210     } else {
211         echo "Error: must pass URL or course";
212     }
213     if ($link) {
214         echo "</A>";
215     }
218 function print_user_picture($userid, $courseid, $picture, $large=false, $returnstring=false) {
219     global $CFG;
221     $output = "<A HREF=\"$CFG->wwwroot/user/view.php?id=$userid&course=$courseid\">";
222     if ($large) {
223         $file = "f1.jpg";
224         $size = 100;
225     } else {
226         $file = "f2.jpg";
227         $size = 35;
228     }
229     if ($picture) {
230         if ($CFG->slasharguments) {        // Use this method if possible for better caching
231             $output .= "<IMG SRC=\"$CFG->wwwroot/user/pix.php/$userid/$file\" BORDER=0 WIDTH=$size HEIGHT=$size ALT=\"\">";
232         } else {
233             $output .= "<IMG SRC=\"$CFG->wwwroot/user/pix.php?file=/$userid/$file\" BORDER=0 WIDTH=$size HEIGHT=$size ALT=\"\">";
234         }
235     } else {
236         $output .= "<IMG SRC=\"$CFG->wwwroot/user/default/$file\" BORDER=0 WIDTH=$size HEIGHT=$size ALT=\"\">";
237     }
238     $output .= "</A>";
240     if ($returnstring) {
241         return $output;
242     } else {
243         echo $output;
244     }
247 function print_table($table) {
248 // Prints a nicely formatted table.
249 // $table is an object with several properties.
250 //     $table->head      is an array of heading names.
251 //     $table->align     is an array of column alignments
252 //     $table->size      is an array of column sizes
253 //     $table->data[]    is an array of arrays containing the data.
254 //     $table->width     is an percentage of the page
255 //     $table->cellpadding    padding on each cell
256 //     $table->cellspacing    spacing between cells
258     if (isset($table->align)) {
259         foreach ($table->align as $key => $aa) {
260             if ($aa) {
261                 $align[$key] = " ALIGN=\"$aa\"";
262             } else {
263                 $align[$key] = "";
264             }
265         }
266     }
267     if (isset($table->size)) {
268         foreach ($table->size as $key => $ss) {
269             if ($ss) {
270                 $size[$key] = " WIDTH=\"$ss\"";
271             } else {
272                 $size[$key] = "";
273             }
274         }
275     }
277     if (!$table->width) {
278         $table->width = "80%";
279     }
281     if (!$table->cellpadding) {
282         $table->cellpadding = "5";
283     }
285     if (!$table->cellspacing) {
286         $table->cellspacing = "1";
287     }
289     print_simple_box_start("CENTER", "$table->width", "#FFFFFF", 0);
290     echo "<TABLE WIDTH=100% BORDER=0 valign=top align=center ";
291     echo " cellpadding=\"$table->cellpadding\" cellspacing=\"$table->cellspacing\">\n";
293     if ($table->head) {
294         echo "<TR>";
295         foreach ($table->head as $key => $heading) {
296             echo "<TH VALIGN=top ".$align[$key].$size[$key].">$heading</TH>";
297         }
298         echo "</TR>\n";
299     }
301     foreach ($table->data as $row) {
302         echo "<TR VALIGN=TOP>";
303         foreach ($row as $key => $item) {
304             echo "<TD ".$align[$key].$size[$key].">$item</TD>";
305         }
306         echo "</TR>\n";
307     }
308     echo "</TABLE>\n";
309     print_simple_box_end();
311     return true;
314 function print_editing_switch($courseid) {
315     global $CFG, $USER;
317     if (isteacher($courseid)) {
318         if ($USER->editing) {
319             echo "<A HREF=\"$CFG->wwwroot/course/view.php?id=$courseid&edit=off\">Turn editing off</A>";
320         } else {
321             echo "<A HREF=\"$CFG->wwwroot/course/view.php?id=$courseid&edit=on\">Turn editing on</A>";
322         }
323     }
326 function format_float($num, $places=0) {
327     return sprintf("%.$places"."f", $num);
330 function print_textarea($richedit, $rows, $cols, $width, $height, $name, $value="") {
331     global $CFG, $THEME;
333     if ($richedit) {
334         echo "<object id=richedit style=\"BACKGROUND-COLOR: buttonface\"";
335         echo " data=\"$CFG->wwwroot/lib/rte/richedit.html\"";
336         echo " width=\"$width\" height=\"$height\" ";
337         echo " type=\"text/x-scriptlet\" VIEWASTEXT></object>\n";
338         echo "<TEXTAREA style=\"display:none\" NAME=\"$name\" ROWS=1 COLS=1>";
339         p($value);
340         echo "</TEXTAREA>\n";
341     } else {
342         echo "<TEXTAREA name=\"$name\" rows=\"$rows\" cols=\"$cols\" wrap=virtual>";
343         p($value);
344         echo "</TEXTAREA>\n";
345     }
348 function print_richedit_javascript($form, $name, $source="no") {
349     echo "<SCRIPT language=\"JavaScript\" event=\"onload\" for=\"window\">\n";
350     echo "   document.richedit.options = \"history=no;source=$source\";";
351     echo "   document.richedit.docHtml = $form.$name.innerText;";
352     echo "</SCRIPT>";
356 function update_course_icon($courseid) {
357 // Used to be an icon, but it's now a simple form button
358     global $CFG, $USER;
360     if (isteacher($courseid)) {
361         if ($USER->editing) {
362             $string = get_string("turneditingoff");
363             $edit = "off";
364         } else {
365             $string = get_string("turneditingon");
366             $edit = "on";
367         }
368         return "<FORM TARGET=_parent METHOD=GET ACTION=\"$CFG->wwwroot/course/view.php\">".
369                "<INPUT TYPE=hidden NAME=id VALUE=\"$courseid\">".
370                "<INPUT TYPE=hidden NAME=edit VALUE=\"$edit\">".
371                "<INPUT TYPE=submit VALUE=\"$string\"></FORM>";
372     }
375 function update_module_button($moduleid, $courseid, $string) {
376 // Prints the editing button on a module "view" page
377     global $CFG;
379     if (isteacher($courseid)) {
380         $string = get_string("updatethis", "", $string);
381         return "<FORM TARGET=_parent METHOD=GET ACTION=\"$CFG->wwwroot/course/mod.php\">".
382                "<INPUT TYPE=hidden NAME=update VALUE=\"$moduleid\">".
383                "<INPUT TYPE=hidden NAME=return VALUE=\"true\">".
384                "<INPUT TYPE=submit VALUE=\"$string\"></FORM>";
385     }
389 function print_date_selector($day, $month, $year, $currenttime=0) {
390 // Currenttime is a default timestamp in GMT
391 // Prints form items with the names $day, $month and $year
393     if (!$currenttime) {
394         $currenttime = time();
395     }
396     $currentdate = usergetdate($currenttime);
398     for ($i=1; $i<=31; $i++) {
399         $days[$i] = "$i";
400     }
401     for ($i=1; $i<=12; $i++) {
402         $months[$i] = date("F", mktime(0,0,0,$i,1,2000));
403     }
404     for ($i=2000; $i<=2010; $i++) {
405         $years[$i] = $i;
406     }
407     choose_from_menu($days,   $day,   $currentdate[mday], "");
408     choose_from_menu($months, $month, $currentdate[mon],  "");
409     choose_from_menu($years,  $year,  $currentdate[year], "");
412 function print_time_selector($hour, $minute, $currenttime=0) {
413 // Currenttime is a default timestamp in GMT
414 // Prints form items with the names $hour and $minute
416     if (!$currenttime) {
417         $currenttime = time();
418     }
419     $currentdate = usergetdate($currenttime);
420     for ($i=0; $i<=23; $i++) {
421         $hours[$i] = sprintf("%02d",$i);
422     }
423     for ($i=0; $i<=59; $i++) {
424         $minutes[$i] = sprintf("%02d",$i);
425     }
426     choose_from_menu($hours,   $hour,   $currentdate[hours],   "");
427     choose_from_menu($minutes, $minute, $currentdate[minutes], "");
430 function make_timestamp($year, $month=1, $day=1, $hour=0, $minute=0, $second=0) {
431 // Given date parts in user time, produce a GMT timestamp
433    return mktime((int)$hour,(int)$minute,(int)$second,(int)$month,(int)$day,(int)$year);
436 function format_time($totalsecs, $str=NULL) {
437 // Given an amount of time in seconds, prints it 
438 // nicely as months, days, hours etc as needed
440     $totalsecs = abs($totalsecs);
442     if (!$str) {  // Create the str structure the slow way
443         $str->day   = get_string("day");
444         $str->days  = get_string("days");
445         $str->hour  = get_string("hour");
446         $str->hours = get_string("hours");
447         $str->min   = get_string("min");
448         $str->mins  = get_string("mins");
449         $str->sec   = get_string("sec");
450         $str->secs  = get_string("secs");
451     }
453     $days      = floor($totalsecs/86400);
454     $remainder = $totalsecs - ($days*86400);
455     $hours     = floor($remainder/3600);
456     $remainder = $remainder - ($hours*3600);
457     $mins      = floor($remainder/60);
458     $secs      = $remainder - ($mins*60);
460     $ss = ($secs == 1)  ? $str->sec  : $str->secs;
461     $sm = ($mins == 1)  ? $str->min  : $str->mins;
462     $sh = ($hours == 1) ? $str->hour : $str->hours;
463     $sd = ($days == 1)  ? $str->day  : $str->days;
465     if ($days)  $odays  = "$days $sd";
466     if ($hours) $ohours = "$hours $sh";
467     if ($mins)  $omins  = "$mins $sm";
468     if ($secs)  $osecs  = "$secs $ss";
470     if ($days)  return "$odays $ohours";
471     if ($hours) return "$ohours $omins";
472     if ($mins)  return "$omins $osecs";
473     if ($secs)  return "$osecs";
474     return get_string("now");
477 function userdate($date, $format="", $timezone=99) {
478 // Returns a formatted string that represents a date in user time
479 // WARNING: note that the format is for strftime(), not date().
481     global $USER;
483     if ($format == "") {
484         $format = "%A, %e %B %Y, %I:%M %p";
485     }
486     if ($timezone == 99) {
487         if (isset($USER->timezone)) {
488             $timezone = (float)$USER->timezone;
489         }
490     }
491     if (abs($timezone) > 12) {
492         return strftime("$format", $date);
493     }
494     return gmstrftime($format, $date + (int)($timezone * 3600));
497 function usergetdate($date, $timezone=99) {
498 // Given a $date timestamp in GMT, returns an array 
499 // that represents the date in user time
501     global $USER;
503     if ($timezone == 99) {
504         $timezone = (float)$USER->timezone;
505     }
506     if (abs($timezone) > 12) {
507         return getdate($date);
508     }
509     //There is no gmgetdate so I have to fake it...
510     $date = $date + (int)($timezone * 3600);
511     $getdate["seconds"] = gmstrftime("%S", $date);
512     $getdate["minutes"] = gmstrftime("%M", $date);
513     $getdate["hours"]   = gmstrftime("%H", $date);
514     $getdate["mday"]    = gmstrftime("%d", $date);
515     $getdate["wday"]    = gmstrftime("%u", $date);
516     $getdate["mon"]     = gmstrftime("%m", $date);
517     $getdate["year"]    = gmstrftime("%Y", $date);
518     $getdate["yday"]    = gmstrftime("%j", $date);
519     $getdate["weekday"] = gmstrftime("%A", $date);
520     $getdate["month"]   = gmstrftime("%B", $date);
521     return $getdate;
524 function usertime($date, $timezone=99) {
525 // Given a GMT timestamp (seconds since epoch), offsets it by 
526 // the timezone.  eg 3pm in India is 3pm GMT - 7 * 3600 seconds
527     global $USER;
529     if ($timezone == 99) {
530         $timezone = (float)$USER->timezone;
531     }
532     if (abs($timezone) > 12) {
533         return $date;
534     }
535     return $date - (int)($timezone * 3600);
538 function usergetmidnight($date, $timezone=99) {
539 // Given a time, return the GMT timestamp of the most recent midnight
540 // for the current user.
541     global $USER;
543     if ($timezone == 99) {
544         $timezone = (float)$USER->timezone;
545     }
547     $userdate = usergetdate($date, $timezone);
549     if (abs($timezone) > 12) {
550         return mktime(0, 0, 0, $userdate["mon"], $userdate["mday"], $userdate["year"]);
551     }
553     $timemidnight = gmmktime (0, 0, 0, $userdate["mon"], $userdate["mday"], $userdate["year"]);
554     return usertime($timemidnight, $timezone); // Time of midnight of this user's day, in GMT
558 function usertimezone($timezone=99) {
559 // returns a string that prints the user's timezone
560     global $USER;
562     if ($timezone == 99) {
563         $timezone = (float)$USER->timezone;
564     }
565     if (abs($timezone) > 12) {
566         return "server time";
567     }
568     if (abs($timezone) < 0.5) {
569         return "GMT";
570     }
571     if ($timezone > 0) {
572         return "GMT+$timezone";
573     } else {
574         return "GMT$timezone";
575     }
579 function error ($message, $link="") {
580     global $CFG, $SESSION;
582     print_header(get_string("error"));
583     echo "<BR>";
584     print_simple_box($message, "center", "", "#FFBBBB");
585    
586     if (!$link) {
587         if ( !empty($SESSION->fromurl) ) {
588             $link = "$SESSION->fromurl";
589             unset($SESSION->fromurl);
590             save_session("SESSION");
591         } else {
592             $link = "$CFG->wwwroot";
593         }
594     }
595     print_continue($link);
596     print_footer();
597     die;
600 function helpbutton ($page, $title="", $module="moodle", $image=true, $text="") {
601     // $page = the keyword that defines a help page
602     // $title = the title of links, rollover tips, alt tags etc
603     // $module = which module is the page defined in
604     // $image = use a help image for the link?  (otherwise uses text)
605     // $text = if defined then this text is used in the page, and 
606     //         the $page variable is ignored.
607     global $CFG;
609     if ($module == "") {
610         $module = "moodle";
611     }
612     if ($image) {
613         $linkobject = "<IMG BORDER=0 HEIGHT=17 WIDTH=22 ALT=\"$title\" SRC=\"$CFG->wwwroot/pix/help.gif\">";
614     } else {
615         $linkobject = $title;
616     }
617     if ($text) {
618         $url = "/help.php?module=$module&text=$text";
619     } else {
620         $url = "/help.php?module=$module&file=$page.html";
621     }
622     link_to_popup_window ($url, "popup", $linkobject, 400, 500, $title);
625 function notice ($message, $link="") {
626     global $THEME, $HTTP_REFERER;
628     if (!$link) {
629         $link = $HTTP_REFERER;
630     }
632     echo "<BR>";
633     print_simple_box($message, "center", "", "$THEME->cellheading");
634     print_heading("<A HREF=\"$link\">".get_string("continue")."</A>");
635     print_footer(get_site());
636     die;
639 function notice_yesno ($message, $linkyes, $linkno) {
640     global $THEME;
642     print_simple_box_start("center", "", "$THEME->cellheading");
643     echo "<P ALIGN=CENTER><FONT SIZE=3>$message</FONT></P>";
644     echo "<P ALIGN=CENTER><FONT SIZE=3><B>";
645     echo "<A HREF=\"$linkyes\">".get_string("yes")."</A>";
646     echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
647     echo "<A HREF=\"$linkno\">".get_string("no")."</A>";
648     echo "</B></FONT></P>";
649     print_simple_box_end();
652 function redirect($url, $message="", $delay=0) {
653 // Uses META tags to redirect the user, after printing a notice
655     echo "<META HTTP-EQUIV='Refresh' CONTENT='$delay; URL=$url'>";
657     if (!empty($message)) {
658         print_header();
659         echo "<CENTER>";
660         echo "<P>$message</P>";
661         echo "<P>( <A HREF=\"$url\">".get_string("continue")."</A> )</P>";
662         echo "</CENTER>";
663     }
664     die; 
667 function notify ($message) {
668     echo "<P align=center><B><FONT COLOR=#FF0000>$message</FONT></B></P>\n";
673 /// PARAMETER HANDLING ////////////////////////////////////////////////////
675 function require_variable($var) {
676     if (! isset($var)) {
677         error("A required parameter was missing");
678     }
681 function optional_variable(&$var, $default=0) {
682     if (! isset($var)) {
683         $var = $default;
684     }
690 /// DATABASE HANDLING ////////////////////////////////////////////////
692 function execute_sql($command, $feedback=true) {
693 // Completely general
695     global $db;
696     
697     $result = $db->Execute("$command");
699     if ($result) {
700         if ($feedback) {
701             echo "<P><FONT COLOR=green><B>".get_string("success")."</B></FONT></P>";
702         }
703         return true;
704     } else {
705         if ($feedback) {
706             echo "<P><FONT COLOR=red><B>".get_string("error")."</B></FONT></P>";
707         }
708         return false;
709     }
712 function modify_database($sqlfile) {
713 // Assumes that the input text file consists of a number 
714 // of SQL statements ENDING WITH SEMICOLONS.  The semicolons
715 // MUST be the last character in a line.
716 // Lines that are blank or that start with "#" are ignored.
717 // Only tested with mysql dump files (mysqldump -p -d moodle)
720     if (file_exists($sqlfile)) {
721         $success = true;
722         $lines = file($sqlfile);
723         $command = "";
725         while ( list($i, $line) = each($lines) ) {
726             $line = chop($line);
727             $length = strlen($line);
729             if ($length  &&  substr($line, 0, 1) <> "#") { 
730                 if (substr($line, $length-1, 1) == ";") {
731                     $line = substr($line, 0, $length-1);   // strip ;
732                     $command .= $line;
733                     if (! execute_sql($command)) {
734                         $success = false;
735                     }
736                     $command = "";
737                 } else {
738                     $command .= $line;
739                 }
740             }
741         }
743     } else {
744         $success = false;
745         echo "<P>Tried to modify database, but \"$sqlfile\" doesn't exist!</P>";
746     }
748     return $success;
752 function record_exists($table, $field, $value) {
753     global $db;
755     $rs = $db->Execute("SELECT * FROM $table WHERE $field = '$value' LIMIT 1");
756     if (!$rs) return false;
758     if ( $rs->RecordCount() ) {
759         return true;
760     } else {
761         return false;
762     }
765 function record_exists_sql($sql) {
766     global $db;
768     $rs = $db->Execute($sql);
769     if (!$rs) return false;
771     if ( $rs->RecordCount() ) {
772         return true;
773     } else {
774         return false;
775     }
779 function count_records($table, $selector, $value) {
780 // Get all the records and count them
781     global $db;
783     $rs = $db->Execute("SELECT COUNT(*) FROM $table WHERE $selector = '$value'");
784     if (!$rs) return 0;
786     return $rs->fields[0];
789 function count_records_sql($sql) {
790 // Get all the records and count them
791     global $db;
793     $rs = $db->Execute("$sql");
794     if (!$rs) return 0;
796     return $rs->fields[0];
799 function get_record($table, $selector, $value) {
800 // Get a single record as an object
801     global $db;
803     $rs = $db->Execute("SELECT * FROM $table WHERE $selector = '$value'");
804     if (!$rs) return false;
806     if ( $rs->RecordCount() == 1 ) {
807         return (object)$rs->fields;
808     } else {
809         return false;
810     }
813 function get_record_sql($sql) {
814 // Get a single record as an object
815 // The sql statement is provided as a string.
817     global $db;
819     $rs = $db->Execute("$sql");
820     if (!$rs) return false;
822     if ( $rs->RecordCount() == 1 ) {
823         return (object)$rs->fields;
824     } else {
825         return false;
826     }
829 function get_records($table, $selector, $value, $sort="", $fields="*") {
830 // Get a number of records as an array of objects
831 // Can optionally be sorted eg "time ASC" or "time DESC"
832 // If "fields" is specified, only those fields are returned
833 // The "key" is the first column returned, eg usually "id"
834     global $db;
836     if ($sort) {
837         $sortorder = "ORDER BY $sort";
838     }
839     $sql = "SELECT $fields FROM $table WHERE $selector = '$value' $sortorder";
841     return get_records_sql($sql);
845 function get_records_list($table, $selector, $values, $sort="", $fields="*") {
846 // Get a number of records as an array of objects
847 // Differs from get_records() in that the values variable 
848 // can be a comma-separated list of values eg  "4,5,6,10"
849 // Can optionally be sorted eg "time ASC" or "time DESC"
850 // The "key" is the first column returned, eg usually "id"
851     global $db;
853     if ($sort) {
854         $sortorder = "ORDER BY $sort";
855     }
856     $sql = "SELECT $fields FROM $table WHERE $selector in ($values) $sortorder";
858     return get_records_sql($sql);
862 function get_records_sql($sql) {
863 // Get a number of records as an array of objects
864 // The "key" is the first column returned, eg usually "id"
865 // The sql statement is provided as a string.
867     global $db;
869     $rs = $db->Execute("$sql");
870     if (!$rs) return false;
872     if ( $rs->RecordCount() > 0 ) {
873         if ($records = $rs->GetAssoc(true)) {
874             foreach ($records as $key => $record) {
875                 $objects[$key] = (object) $record;
876             }
877             return $objects;
878         } else {
879             return false;
880         }
881     } else {
882         return false;
883     }
886 function get_records_sql_menu($sql) {
887 // Given an SQL select, this function returns an associative 
888 // array of the first two columns.  This is most useful in 
889 // combination with the choose_from_menu function to create 
890 // a form menu.
892     global $db;
894     $rs = $db->Execute("$sql");
895     if (!$rs) return false;
897     if ( $rs->RecordCount() > 0 ) {
898         while (!$rs->EOF) {
899             $menu[$rs->fields[0]] = $rs->fields[1];
900             $rs->MoveNext();
901         }
902         return $menu;
903         
904     } else {
905         return false;
906     }
909 function get_field($table, $field, $selector, $value) {
910     global $db;
912     $rs = $db->Execute("SELECT $field FROM $table WHERE $selector = '$value'");
913     if (!$rs) return false;
915     if ( $rs->RecordCount() == 1 ) {
916         return $rs->fields["$field"];
917     } else {
918         return false;
919     }
922 function set_field($table, $field, $newvalue, $selector, $value) {
923     global $db;
925     return $db->Execute("UPDATE $table SET $field = '$newvalue' WHERE $selector = '$value'");
928 function set_config($name, $value) {
929 // No need for get_config because they are usually always available in $CFG
931     if (get_field("config", "value", "name", $name)) {
932         return set_field("config", "value", $value, "name", $name);
933     } else {
934         $config->name = $name;
935         $config->value = $value;
936         return insert_record("config", $config);
937     }
940 function delete_records($table, $selector, $value) {
941 // Delete one or more records from a table
942     global $db;
944     return $db->Execute("DELETE FROM $table WHERE $selector = '$value'");
947 function insert_record($table, $dataobject) {
948 // Insert a record into a table and return the "id" field
949 // $dataobject is an object containing needed data
951     global $db;
953     // Determine all the fields needed
954     if (! $columns = $db->MetaColumns("$table")) {
955         return false;
956     }
958     $data = (array)$dataobject;
960     // Pull out data matching these fields
961     foreach ($columns as $column) {
962         if ($column->name <> "id" && isset($data[$column->name]) ) {
963             $ddd[$column->name] = $data[$column->name];
964         }
965     }
967     // Construct SQL queries
968     if (! $numddd = count($ddd)) {
969         return 0;
970     }
972     $count = 0;
973     $insert = "";
974     $select = "";
976     foreach ($ddd as $key => $value) {
977         $count++;
978         $insert .= "$key = '$value'";
979         $select .= "$key = '$value'";
980         if ($count < $numddd) {
981             $insert .= ", ";
982             $select .= " AND ";
983         }
984     }
986     if (! $rs = $db->Execute("INSERT INTO $table SET $insert")) {
987         return false;
988     } 
990     // Pull it out again to find the id.  This is the most cross-platform method.
991     if ($rs = $db->Execute("SELECT id FROM $table WHERE $select")) {
992         return $rs->fields[0];
993     } else {
994         return false;
995     }
999 function update_record($table, $dataobject) {
1000 // Update a record in a table
1001 // $dataobject is an object containing needed data
1003     global $db;
1005     if (! isset($dataobject->id) ) {
1006         return false;
1007     }
1009     // Determine all the fields in the table
1010     if (!$columns = $db->MetaColumns($table)) {
1011         return false;
1012     }
1013     $data = (array)$dataobject;
1015     // Pull out data matching these fields
1016     foreach ($columns as $column) {
1017         if ($column->name <> "id" && isset($data[$column->name]) ) {
1018             $ddd[$column->name] = $data[$column->name];
1019         }
1020     }
1022     // Construct SQL queries
1023     $numddd = count($ddd);
1024     $count = 0;
1025     $update = "";
1027     foreach ($ddd as $key => $value) {
1028         $count++;
1029         $update .= "$key = '$value'";
1030         if ($count < $numddd) {
1031             $update .= ", ";
1032         }
1033     }
1035     if ($rs = $db->Execute("UPDATE $table SET $update WHERE id = '$dataobject->id'")) {
1036         return true;
1037     } else {
1038         return false;
1039     }
1043 function print_object($object) {
1044 // Mostly just for debugging
1046     $array = (array)$object;
1047     foreach ($array as $key => $item) {
1048         echo "$key -> $item <BR>";
1049     }
1053 /// USER DATABASE ////////////////////////////////////////////////
1055 function get_user_info_from_db($field, $value) {
1057     global $db;
1059     if (!$field || !$value) 
1060         return false;
1062     if (! $result = $db->Execute("SELECT * FROM user WHERE $field = '$value' AND deleted <> '1'")) {
1063         error("Could not find any active users!");
1064     }
1066     if ( $result->RecordCount() == 1 ) {
1067         $user = (object)$result->fields;
1069         $rs = $db->Execute("SELECT course FROM user_students WHERE user = '$user->id' ");
1070         while (!$rs->EOF) {
1071             $course = $rs->fields["course"];
1072             $user->student["$course"] = true;
1073             $rs->MoveNext();
1074         }
1076         $rs = $db->Execute("SELECT course FROM user_teachers WHERE user = '$user->id' ");
1077         while (!$rs->EOF) {
1078             $course = $rs->fields["course"];
1079             $user->teacher["$course"] = true;
1080             $rs->MoveNext();
1081         }
1083         $rs = $db->Execute("SELECT * FROM user_admins WHERE user = '$user->id' ");
1084         while (!$rs->EOF) {
1085             $user->admin = true;
1086             $rs->MoveNext();
1087         }
1089         if ($course = get_site()) {
1090             // Everyone is always a member of the top course
1091             $user->student["$course->id"] = true;
1092         }
1094         return $user;
1096     } else {
1097         return false;
1098     }
1101 function update_user_in_db() {
1103    global $db, $USER, $REMOTE_ADDR;
1105    if (!isset($USER->id)) 
1106        return false;
1108    $timenow = time();
1109    if ($db->Execute("UPDATE user SET lastIP='$REMOTE_ADDR', lastaccess='$timenow' WHERE id = '$USER->id' ")) {
1110        return true;
1111    } else {
1112        return false;
1113    }
1116 function require_login($courseid=0) {
1117 // This function checks that the current user is logged in, and optionally
1118 // whether they are "logged in" or allowed to be in a particular course.
1119 // If not, then it redirects them to the site login or course enrolment.
1121     global $CFG, $SESSION, $USER, $FULLME, $HTTP_REFERER, $PHPSESSID;
1122       
1123     // First check that the user is logged in to the site.
1125     if (! (isset($USER->loggedin) and $USER->confirmed and ($USER->site == $CFG->wwwroot)) ) { // They're not
1126         $SESSION->wantsurl = $FULLME;
1127         $SESSION->fromurl  = $HTTP_REFERER;
1128         save_session("SESSION");
1129         $USER = NULL;
1130         save_session("USER");
1131         if ($PHPSESSID) { // Cookies not enabled.
1132             redirect("$CFG->wwwroot/login/index.php?PHPSESSID=$PHPSESSID");
1133         } else {
1134             redirect("$CFG->wwwroot/login/index.php");
1135         }
1136         die;
1137     }
1138     
1139     // Next, check if the user can be in a particular course
1140     if ($courseid) {
1141         if ($USER->student[$courseid] || $USER->teacher[$courseid] || $USER->admin) {
1142             if (isset($USER->realuser)) {   // Make sure the REAL person can also access this course
1143                 if (!isteacher($courseid, $USER->realuser)) {
1144                     print_header();
1145                     notice(get_string("studentnotallowed", "", "$USER->firstname $USER->lastname"), $CFG->wwwroot);
1146                 }
1148             } else {  // just update their last login time
1149                 update_user_in_db();
1150             }
1151             if (!$USER->email) {            // User logged in, but has not set up profile!
1152                                             // This can occur with external authentication
1153                 redirect("$CFG->wwwroot/user/edit.php?id=$USER->id&course=$courseid");
1154                 die;
1155             }
1156             return;   // user is a member of this course.
1157         }
1158         if (! $course = get_record("course", "id", $courseid)) {
1159             error("That course doesn't exist");
1160         }
1161         if ($USER->username == "guest") {
1162             switch ($course->guest) {
1163                 case 0: // Guests not allowed
1164                     print_header();
1165                     notice(get_string("guestsnotallowed", "", $course->fullname));
1166                     break;
1167                 case 1: // Guests allowed
1168                     update_user_in_db();
1169                     return;
1170                 case 2: // Guests allowed with key (drop through)
1171                     break;
1172             }
1173         }
1175         // Currently not enrolled in the course, so see if they want to enrol
1176         $SESSION->wantsurl = $FULLME;
1177         save_session("SESSION");
1178         redirect("$CFG->wwwroot/course/enrol.php?id=$courseid");
1179         die;
1180     }
1185 function update_login_count() {
1186     global $SESSION;
1188     $max_logins = 10;
1190     if (empty($SESSION->logincount)) {
1191         $SESSION->logincount = 1;
1192     } else {
1193         $SESSION->logincount++;
1194     }
1195     save_session("SESSION");
1197     if ($SESSION->logincount > $max_logins) {
1198         unset($SESSION->wantsurl);
1199         save_session("SESSION");
1200         error("Sorry, you have exceeded the allowed number of login attempts. Restart your browser.");
1201     }
1204 function remove_admin($user) {
1205     global $db;
1207     return $db->Execute("DELETE FROM user_admins WHERE user = '$user'");
1210 function remove_teacher($user, $course=0) {
1211     global $db;
1213     if ($course) {
1214         /// First delete any crucial stuff that might still send mail
1215         if ($forums = get_records("forum", "course", $course)) {
1216             foreach ($forums as $forum) {
1217                 $db->Execute("DELETE FROM forum_subscriptions WHERE forum = '$forum->id' AND user = '$user'");
1218             }
1219         }
1220         return $db->Execute("DELETE FROM user_teachers WHERE user = '$user' AND course = '$course'");
1221     } else {
1222         delete_records("forum_subscriptions", "user", $user);
1223         return delete_records("user_teachers", "user", $user);
1224     }
1228 function enrol_student($user, $course) {
1229     global $db;
1231         $timenow = time();
1233         $rs = $db->Execute("INSERT INTO user_students (user, course, start, end, time) 
1234                         VALUES ($user, $course, 0, 0, $timenow)");
1235         if ($rs) {
1236                 return true;
1237         } else {
1238             return false;
1239         }
1242 function unenrol_student($user, $course=0) {
1243     global $db;
1245     if ($course) {
1246         /// First delete any crucial stuff that might still send mail
1247         if ($forums = get_records("forum", "course", $course)) {
1248             foreach ($forums as $forum) {
1249                 $db->Execute("DELETE FROM forum_subscriptions WHERE forum = '$forum->id' AND user = '$user'");
1250             }
1251         }
1252         return $db->Execute("DELETE FROM user_students WHERE user = '$user' AND course = '$course'");
1254     } else {
1255         delete_records("forum_subscriptions", "user", $user);
1256         return delete_records("user_students", "user", $user);
1257     }
1261 function isadmin($userid=0) {
1262     global $USER;
1264     if (!$userid) {
1265         return $USER->admin;
1266     }
1268     return record_exists_sql("SELECT * FROM user_admins WHERE user='$userid'");
1271 function isteacher($courseid, $userid=0) {
1272     global $USER;
1274     if (isadmin($userid)) {  // admins can do anything the teacher can
1275         return true;
1276     }
1278     if (!$userid) {
1279         return $USER->teacher[$courseid];
1280     }
1282     return record_exists_sql("SELECT * FROM user_teachers WHERE user='$userid' AND course='$courseid'");
1286 function isstudent($courseid, $userid=0) {
1287     global $USER;
1289     if (!$userid) {
1290         return $USER->student[$courseid];
1291     }
1293     $timenow = time();   // todo:  add time check below
1295     return record_exists_sql("SELECT * FROM user_students WHERE user='$userid' AND course='$courseid'");
1298 function isguest($userid=0) {
1299     global $USER;
1301     if (!$userid) {
1302         return ($USER->username == "guest");
1303     }
1305     return record_exists_sql("SELECT * FROM user WHERE id='$userid' AND username = 'guest' ");
1308 function isediting($courseid, $user=NULL) {
1309     global $USER;
1310     if (!$user){
1311         $user = $USER;
1312     }
1313     return ($user->editing and isteacher($courseid, $user->id));
1316 function reset_login_count() {
1317     global $SESSION;
1319     $SESSION->logincount = 0;
1320     save_session("SESSION");
1324 function set_moodle_cookie($thing) {
1326     $days = 60;
1327     $seconds = 60*60*24*$days;
1329     setCookie ('MOODLEID', "", time() - 3600, "/");
1330     setCookie ('MOODLEID', rc4encrypt($thing), time()+$seconds, "/");
1334 function get_moodle_cookie() {
1335     global $MOODLEID;
1336     return rc4decrypt($MOODLEID);
1340 function save_session($VAR) {
1341 // Copies temporary session variable to permanent sesson variable
1342 // eg $_SESSION["USER"] = $USER;
1343     global $$VAR;
1344     $_SESSION[$VAR] = $$VAR;
1348 function create_user_record($username, $password) {
1349 // Creates a bare-bones user record 
1350     global $REMOTE_ADDR, $CFG;
1352     if ($CFG->auth_update_userinfo and function_exists(auth_get_userinfo)) {
1353         if ($newinfo = auth_get_userinfo($username)) {
1354             foreach ($newinfo as $key=>$value){
1355                 $newuser->$key = $value;
1356             }
1357         }
1358     }
1360     $newuser->username = $username;
1361     $newuser->password = md5($password);
1362     $newuser->lang = $CFG->lang;
1363     $newuser->confirmed = 1;
1364     $newuser->lastIP = $REMOTE_ADDR;
1365     $newuser->timemodified = time();
1367     if (insert_record("user", $newuser)) {
1368         return get_user_info_from_db("username", $username);
1369     }
1370     return false;
1373 function authenticate_user_login($username, $password) {
1374 // Given a username and password, this function looks them 
1375 // up using the currently selected authentication mechanism,
1376 // and if the authentication is successful, it returns a 
1377 // valid $user object from the 'user' table.
1378 //
1379 // Uses auth_ functions from the currently active auth module
1381     global $CFG;
1383     if (!isset($CFG->auth)) {
1384         $CFG->auth = "email";    // Default authentication module
1385     }
1387     require_once("$CFG->dirroot/auth/$CFG->auth/lib.php");
1389     if (auth_user_login($username, $password)) {  // Successful authentication
1391         if ($user = get_user_info_from_db("username", $username)) {
1392             if (md5($password) <> $user->password) {
1393                 set_field("user", "password", md5($password), "username", $username);
1394             }
1395             return $user;
1397         } else {
1398             return create_user_record($username, $password);
1399         }
1400     }
1401     return false;
1405 function get_site () {
1406 // Returns $course object of the top-level site.
1407     if ( $course = get_record("course", "category", 0)) {
1408         return $course;
1409     } else {
1410         return false;
1411     }
1414 function get_admin () {
1415 // Returns $user object of the main admin user
1417     if ( $admins = get_records_sql("SELECT u.* FROM user u, user_admins a WHERE a.user = u.id ORDER BY u.id ASC")) {
1418         foreach ($admins as $admin) {
1419             return $admin;   // ie the first one 
1420         }
1421     } else {
1422         return false;
1423     }
1426 function get_teacher($courseid) {
1427 // Returns $user object of the main teacher for a course
1428     if ( $teachers = get_records_sql("SELECT u.* FROM user u, user_teachers t 
1429                                       WHERE t.user = u.id AND t.course = '$courseid' 
1430                                       ORDER BY t.authority ASC")) {
1431         foreach ($teachers as $teacher) {
1432             if ($teacher->authority) {
1433                 return $teacher;   // the highest authority teacher
1434             }
1435         }
1436     } else {
1437         return false;
1438     }
1441 function get_course_students($courseid, $sort="u.lastaccess DESC") {
1442     return get_records_sql("SELECT u.* FROM user u, user_students s
1443                             WHERE s.course = '$courseid' AND s.user = u.id AND u.deleted = '0'
1444                             ORDER BY $sort");
1447 function get_course_teachers($courseid, $sort="t.authority ASC") {
1448     return get_records_sql("SELECT u.*,t.authority,t.role FROM user u, user_teachers t
1449                             WHERE t.course = '$courseid' AND t.user = u.id AND u.deleted = '0'
1450                             ORDER BY $sort");
1453 function get_course_users($courseid, $sort="u.lastaccess DESC") {
1454 // Using this method because the direct SQL just would not always work!
1456     $teachers = get_course_teachers($courseid, $sort);
1457     $students = get_course_students($courseid, $sort);
1459     if ($teachers and $students) {
1460         return array_merge($teachers, $students);
1461     } else if ($teachers) {
1462         return $teachers;
1463     } else {
1464         return $students;
1465     }
1467 //    return get_records_sql("SELECT u.* FROM user u, user_students s, user_teachers t
1468 //                            WHERE (s.course = '$courseid' AND s.user = u.id) OR 
1469 //                                  (t.course = '$courseid' AND t.user = u.id)
1470 //                            ORDER BY $sort");
1475 /// MODULE FUNCTIONS /////////////////////////////////////////////////
1477 function get_coursemodule_from_instance($modulename, $instance, $courseid) {
1478 // Given an instance of a module, finds the coursemodule description
1480     return get_record_sql("SELECT cm.*, m.name
1481                            FROM course_modules cm, modules md, $modulename m 
1482                            WHERE cm.course = '$courseid' AND 
1483                                  cm.deleted = '0' AND
1484                                  cm.instance = m.id AND 
1485                                  md.name = '$modulename' AND 
1486                                  md.id = cm.module AND
1487                                  m.id = '$instance'");
1491 function get_all_instances_in_course($modulename, $courseid, $sort="cw.section") {
1492 // Returns an array of all the active instances of a particular
1493 // module in a given course.   Returns false on any errors.
1495     return get_records_sql("SELECT m.*,cw.section,cm.id as coursemodule 
1496                             FROM course_modules cm, course_sections cw, modules md, $modulename m 
1497                             WHERE cm.course = '$courseid' AND 
1498                                   cm.instance = m.id AND 
1499                                   cm.deleted = '0' AND
1500                                   cm.section = cw.id AND 
1501                                   md.name = '$modulename' AND 
1502                                   md.id = cm.module
1503                             ORDER BY $sort");
1510 /// CORRESPONDENCE  ////////////////////////////////////////////////
1512 function email_to_user($user, $from, $subject, $messagetext, $messagehtml="", $attachment="", $attachname="") {
1513 //  user        - a user record as an object
1514 //  from        - a user record as an object
1515 //  subject     - plain text subject line of the email
1516 //  messagetext - plain text version of the message
1517 //  messagehtml - complete html version of the message (optional)
1518 //  attachment  - a file on the filesystem, relative to $CFG->dataroot
1519 //  attachname  - the name of the file (extension indicates MIME)
1521     global $CFG, $_SERVER;
1523     include_once("$CFG->libdir/phpmailer/class.phpmailer.php");
1525     if (!$user) {
1526         return false;
1527     }
1528     
1529     $mail = new phpmailer;
1531     $mail->Version = "Moodle $CFG->version";           // mailer version 
1532     $mail->PluginDir = "$CFG->libdir/phpmailer/";      // plugin directory (eg smtp plugin)
1534     if ($CFG->smtphosts) {
1535         $mail->IsSMTP();                               // use SMTP directly
1536         $mail->Host = "$CFG->smtphosts";               // specify main and backup servers
1538         if ($CFG->smtpuser) {                          // Use SMTP authentication
1539             $mail->SMTPAuth = true;
1540             $mail->Username = $CFG->smtpuser;
1541             $mail->Password = $CFG->smtppass;
1542         }
1543     } else {
1544         $mail->IsMail();                               // use PHP mail() = sendmail
1545     }
1547     $mail->From     = "$from->email";
1548     $mail->FromName = "$from->firstname $from->lastname";
1549     $mail->Subject  =  stripslashes($subject);
1551     $mail->AddAddress("$user->email", "$user->firstname $user->lastname"); 
1553     $mail->WordWrap = 70;                               // set word wrap
1555     if ($messagehtml) {
1556         $mail->IsHTML(true);
1557         $mail->Body    =  $messagehtml;
1558         $mail->AltBody =  "\n$messagetext\n";
1559     } else {
1560         $mail->IsHTML(false);
1561         $mail->Body =  "\n$messagetext\n";
1562     }
1564     if ($attachment && $attachname) {
1565         if (ereg( "\\.\\." ,$attachment )) {    // Security check for ".." in dir path
1566             $adminuser = get_admin();
1567             $mail->AddAddress("$adminuser->email", "$adminuser->firstname $adminuser->lastname");
1568             $mail->AddStringAttachment("Error in attachment.  User attempted to attach a filename with a unsafe name.", "error.txt", "8bit", "text/plain");
1569         } else {
1570             include_once("$CFG->dirroot/files/mimetypes.php");
1571             $mimetype = mimeinfo("type", $attachname);
1572             $mail->AddAttachment("$CFG->dataroot/$attachment", "$attachname", "base64", "$mimetype");
1573         }
1574     }
1576     if ($mail->Send()) {
1577         return true;
1578     } else {
1579         echo "ERROR: $mail->ErrorInfo\n";
1580         $site = get_site();
1581         add_to_log($site->id, "library", "mailer", $_SERVER["REQUEST_URI"], "ERROR: $mail->ErrorInfo");
1582         return false;
1583     }
1587 /// FILE HANDLING  /////////////////////////////////////////////
1589 function make_upload_directory($directory) {
1590 // $directory = a string of directory names under $CFG->dataroot
1591 // eg  stuff/assignment/1
1592 // Returns full directory if successful, false if not
1594     global $CFG;
1596     $currdir = $CFG->dataroot;
1597     if (!file_exists($currdir)) {
1598         if (! mkdir($currdir, 0750)) {
1599             notify("ERROR: You need to create the directory $currdir with web server write access");
1600             return false;
1601         }
1602     }
1604     $dirarray = explode("/", $directory);
1606     foreach ($dirarray as $dir) {
1607         $currdir = "$currdir/$dir";
1608         if (! file_exists($currdir)) {
1609             if (! mkdir($currdir, 0750)) {
1610                 notify("ERROR: Could not find or create a directory ($currdir)");
1611                 return false;
1612             }
1613         }
1614     }
1616     return $currdir;
1619 function make_mod_upload_directory($courseid) {
1620     global $CFG;
1622     if (! $moddata = make_upload_directory("$courseid/$CFG->moddata")) {
1623         return false;
1624     }
1626     $strreadme = get_string("readme");
1628     if (file_exists("$CFG->dirroot/lang/$CFG->lang/docs/module_files.txt")) {
1629         copy("$CFG->dirroot/lang/$CFG->lang/docs/module_files.txt", "$moddata/$strreadme.txt");
1630     } else {
1631         copy("$CFG->dirroot/lang/en/docs/module_files.txt", "$moddata/$strreadme.txt");
1632     }
1633     return $moddata;
1637 function valid_uploaded_file($newfile) {
1638 // Returns current name of file on disk if true
1639     if (is_uploaded_file($newfile['tmp_name']) and $newfile['size'] > 0) {
1640         return $newfile['tmp_name'];
1641     } else {
1642         return "";
1643     }
1646 function get_max_upload_file_size() {
1647     if (! $filesize = ini_get("upload_max_filesize")) {
1648         $filesize = "5M";
1649     }
1650     return get_real_size($filesize);
1653 function get_directory_list($rootdir, $excludefile="", $descend=true) {
1654 // Returns an array with all the filenames in 
1655 // all subdirectories, relative to the given rootdir.
1656 // If excludefile is defined, then that file/directory is ignored
1658     $dirs = array();
1659    
1660     $dir = opendir($rootdir);
1662     while ($file = readdir($dir)) {
1663         if ($file != "." and $file != ".." and $file != "CVS" and $file != $excludefile) {
1664             $fullfile = $rootdir."/".$file;
1665             if ($descend and filetype($fullfile) == "dir") {
1666                 $subdirs = get_directory_list($fullfile, $excludefile, $descend);
1667                 foreach ($subdirs as $subdir) {
1668                     $dirs[] = $file."/".$subdir;
1669                 }
1670             } else {
1671                 $dirs[] = $file;
1672             }
1673         }
1674     }
1675     closedir($dir);
1677     asort($dirs);
1679     return $dirs;
1682 function get_real_size($size=0) {
1683 // Converts numbers like 10M into bytes
1684     if (!$size) {
1685         return 0; 
1686     }
1687     $scan['MB'] = 1048576;
1688     $scan['M'] = 1048576;
1689     $scan['KB'] = 1024;
1690     $scan['K'] = 1024;
1692     while (list($key) = each($scan)) {
1693         if ((strlen($size)>strlen($key))&&(substr($size, strlen($size) - strlen($key))==$key)) {
1694             $size = substr($size, 0, strlen($size) - strlen($key)) * $scan[$key];
1695             break;
1696         }
1697     }
1698     return $size;
1701 function display_size($size) {
1702 // Converts bytes into display form
1703     if ($size >= 1073741824) {
1704         $size = round($size / 1073741824 * 10) / 10 . "Gb";
1705     } else if ($size >= 1048576) {
1706         $size = round($size / 1048576 * 10) / 10 . "Mb";
1707     } else if ($size >= 1024) {
1708         $size = round($size / 1024 * 10) / 10 . "Kb";
1709     } else { 
1710         $size = $size . "b";
1711     }
1712     return $size;
1715 function clean_filename($string) {
1716     $string = eregi_replace("\.\.", "", $string);
1717     $string = eregi_replace("[^([:alnum:]|\.)]", "_", $string);
1718     return    eregi_replace("_+", "_", $string);
1722 /// STRING TRANSLATION  ////////////////////////////////////////
1724 function print_string($identifier, $module="", $a=NULL) {
1725     echo get_string($identifier, $module, $a);
1728 function current_language() {
1729 // Returns the code for the current language
1730     global $CFG, $USER;
1732     if (isset($USER->lang)) {    // User language can override site language
1733         return $USER->lang;
1734     } else {
1735         return $CFG->lang;
1736     }
1739 function get_string($identifier, $module="", $a=NULL) {
1740 // Return the translated string specified by $identifier as 
1741 // for $module.  Uses the same format files as STphp.
1742 // $a is an object, string or number that can be used
1743 // within translation strings
1744 //
1745 // eg "hello \$a->firstname \$a->lastname"
1746 // or "hello \$a"
1748     global $CFG;
1750     $lang = current_language();
1752     if ($module == "") {
1753         $module = "moodle";
1754     }
1756     $langpath = "$CFG->dirroot/lang";
1757     $langfile = "$langpath/$lang/$module.php";
1759     if (!file_exists($langfile)) {                // try English instead
1760         $langfile = "$langpath/en/$module.php";
1761         if (!file_exists($langfile)) {
1762             return "ERROR: No lang file ($langpath/en/$module.php)!";
1763         }
1764     }
1766     if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
1768         eval($result);
1769         return $resultstring;
1771     } else {
1772         if ($lang == "en") {
1773             return "[['$identifier']]";
1775         } else {   // Try looking in the english file.
1776             $langfile = "$langpath/en/$module.php";
1777             if (!file_exists($langfile)) {
1778                 return "ERROR: No lang file ($langpath/en/$module.php)!";
1779             }
1780             if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
1781                 eval($result);
1782                 return $resultstring;
1783             } else {
1784                 return "[['$identifier']]";
1785             }
1786         }
1787     }
1791 function get_string_from_file($identifier, $langfile, $destination) {
1792 // This function is only used from get_string().
1793     include ($langfile);
1795     if (!isset ($string[$identifier])) {
1796         return false;
1797     }
1799     return "$destination = sprintf(\"".$string[$identifier]."\");";
1803 function get_list_of_languages() {
1804 /// Returns a list of language codes and their full names
1805     global $CFG;
1807     if (!$langdirs = get_list_of_plugins("lang")) {
1808         return false;
1809     }
1811     foreach ($langdirs as $lang) {
1812         include("$CFG->dirroot/lang/$lang/moodle.php");
1813         $languages[$lang] = $string["thislanguage"]." ($lang)";
1814         unset($string);
1815     }
1816     return $languages;
1820 /// ENCRYPTION  ////////////////////////////////////////////////
1822 function rc4encrypt($data) {
1823     $password = "nfgjeingjk";
1824     return endecrypt($password, $data, "");
1827 function rc4decrypt($data) {
1828     $password = "nfgjeingjk";
1829     return endecrypt($password, $data, "de");
1832 function endecrypt ($pwd, $data, $case) {
1833 // Based on a class by Mukul Sabharwal [mukulsabharwal@yahoo.com]
1835     if ($case == 'de') {
1836         $data = urldecode($data);
1837     }
1839     $key[] = "";
1840     $box[] = "";
1841     $temp_swap = "";
1842     $pwd_length = 0;
1844     $pwd_length = strlen($pwd);
1846     for ($i = 0; $i <= 255; $i++) {
1847         $key[$i] = ord(substr($pwd, ($i % $pwd_length), 1));
1848         $box[$i] = $i;
1849     }
1851     $x = 0;
1853     for ($i = 0; $i <= 255; $i++) {
1854         $x = ($x + $box[$i] + $key[$i]) % 256;
1855         $temp_swap = $box[$i];
1856         $box[$i] = $box[$x];
1857         $box[$x] = $temp_swap;
1858     }
1860     $temp = "";
1861     $k = "";
1863     $cipherby = "";
1864     $cipher = "";
1866     $a = 0;
1867     $j = 0;
1869     for ($i = 0; $i < strlen($data); $i++) {
1870         $a = ($a + 1) % 256;
1871         $j = ($j + $box[$a]) % 256;
1872         $temp = $box[$a];
1873         $box[$a] = $box[$j];
1874         $box[$j] = $temp;
1875         $k = $box[(($box[$a] + $box[$j]) % 256)];
1876         $cipherby = ord(substr($data, $i, 1)) ^ $k;
1877         $cipher .= chr($cipherby);
1878     }
1880     if ($case == 'de') {
1881         $cipher = urldecode(urlencode($cipher));
1882     } else {
1883         $cipher = urlencode($cipher);
1884     }
1886     return $cipher;
1890 /// MISCELLANEOUS ////////////////////////////////////////////////////////////////////
1892 function count_words($string) {
1893     $string = strip_tags($string);
1894     return count(preg_split("/\w\b/", $string)) - 1;
1897 function getweek ($startdate, $thedate) {
1898 // Given dates in seconds, how many weeks is the date from startdate
1899 // The first week is 1, the second 2 etc ... 
1900     
1901     if ($thedate < $startdate) {   // error
1902         return 0;  
1903     }
1905     return floor(($thedate - $startdate) / 604800.0) + 1;
1908 function add_to_log($course, $module, $action, $url="", $info="") {
1909 // Add an entry to the log table.  These are "action" focussed rather
1910 // than web server hits, and provide a way to easily reconstruct what 
1911 // any particular student has been doing.
1912 //
1913 // course = the course id
1914 // module = forum, journal, resource, course, user etc
1915 // action = view, edit, post (often but not always the same as the file.php)
1916 // url    = the file and parameters used to see the results of the action
1917 // info   = additional description information 
1920     global $db, $USER, $REMOTE_ADDR;
1922     if (isset($USER->realuser)) {  // Don't log
1923         return;
1924     }
1926     $timenow = time();
1927     $info = addslashes($info);
1929     $result = $db->Execute("INSERT INTO log
1930                             SET time = '$timenow', 
1931                                 user = '$USER->id',
1932                                 course = '$course',
1933                                 ip = '$REMOTE_ADDR', 
1934                                 module = '$module',
1935                                 action = '$action',
1936                                 url = '$url',
1937                                 info = '$info'");
1938     if (!$result) {
1939         echo "<P>Error: Could not insert a new entry to the Moodle log</P>";  // Don't throw an error
1940     }    
1943 function generate_password($maxlen=10) {
1944 // returns a randomly generated password of length $maxlen.  inspired by
1945 // http://www.phpbuilder.com/columns/jesus19990502.php3 
1947     global $CFG;
1949     $fillers = "1234567890!$-+";
1950     $wordlist = file($CFG->wordlist);
1952     srand((double) microtime() * 1000000);
1953     $word1 = trim($wordlist[rand(0, count($wordlist) - 1)]);
1954     $word2 = trim($wordlist[rand(0, count($wordlist) - 1)]);
1955     $filler1 = $fillers[rand(0, strlen($fillers) - 1)];
1957     return substr($word1 . $filler1 . $word2, 0, $maxlen);
1960 function moodle_needs_upgrading() {
1961 // Checks version numbers of Main code and all modules to see
1962 // if there are any mismatches ... returns true or false
1963     global $CFG;
1965     include_once("$CFG->dirroot/version.php");  # defines $version and upgrades
1966     if ($CFG->version) { 
1967         if ($version > $CFG->version) {
1968             return true;
1969         }
1970         if ($mods = get_list_of_plugins("mod")) {
1971             foreach ($mods as $mod) {
1972                 $fullmod = "$CFG->dirroot/mod/$mod";
1973                 unset($module);
1974                 include_once("$fullmod/version.php");  # defines $module with version etc
1975                 if ($currmodule = get_record("modules", "name", $mod)) {
1976                     if ($module->version > $currmodule->version) {
1977                         return true;
1978                     }
1979                 }
1980             }
1981         }
1982     } else {
1983         return true;
1984     }
1985     return false;
1989 function get_list_of_plugins($plugin="mod") {
1990 // Lists plugin directories within some directory
1992     global $CFG;
1994     $basedir = opendir("$CFG->dirroot/$plugin");
1995     while ($dir = readdir($basedir)) {
1996         if ($dir == "." || $dir == ".." || $dir == "CVS") {
1997             continue;
1998         }
1999         if (filetype("$CFG->dirroot/$plugin/$dir") != "dir") {
2000             continue;
2001         }
2002         $plugins[] = $dir;
2003     }
2004     if ($plugins) {
2005         asort($plugins);
2006     }
2007     return $plugins;
2011 function check_php_version($version="4.1.0") {
2012 // Returns true is the current version of PHP is greater that the specified one
2013     $minversion = intval(str_replace(".", "", $version));
2014     $curversion = intval(str_replace(".", "", phpversion()));
2015     return ($curversion >= $minversion);
2018 function check_browser_version($brand="MSIE", $version=5.5) {
2019 // Checks to see if is a browser matches the specified
2020 // brand and is equal or better version.
2021     global $HTTP_USER_AGENT;
2023     if (!$HTTP_USER_AGENT) {
2024         return false;
2025     }
2026     $string = explode(";", $HTTP_USER_AGENT);
2027     if (!isset($string[1])) {
2028         return false;
2029     }
2030     $string = explode(" ", trim($string[1]));
2031     if (!isset($string[0]) and !isset($string[1])) {
2032         return false;
2033     }
2034     if ($string[0] == $brand and (float)$string[1] >= $version ) {
2035         return true;
2036     }
2037     return false;
2040 function can_use_richtext_editor() {
2041     global $USER, $CFG;
2042     if ($USER->htmleditor and $CFG->htmleditor) {
2043         return check_browser_version("MSIE", 5.5);
2044     }
2045     return false;
2049 function check_gd_version() {
2050     ob_start();
2051     phpinfo();
2052     $phpinfo = ob_get_contents();
2053     ob_end_clean();
2055     $phpinfo = explode("\n",$phpinfo);
2057     $gdversion = 0;
2059     foreach ($phpinfo as $text) {
2060         $parts = explode('</b>',$text);
2061         foreach ($parts as $key => $val) {
2062             $parts[$key] = strip_tags($val);
2063         }
2064         if ($parts[0]=="GD Version") {
2065             $gdversion = intval($parts[1]);
2066         }
2067     }
2069     return $gdversion;   // 1, 2 or 0
2074 ?>