Added word count
[moodle.git] / lib / moodlelib.php
CommitLineData
f9903ed0 1<?PHP // $Id$
2
3//
4// moodlelib.php
5//
6// Large collection of useful functions used by many parts of Moodle.
7//
8// Martin Dougiamas, 2000
9//
10
11
12/// STANDARD WEB PAGE PARTS ///////////////////////////////////////////////////
13
c7e3ac2a 14function print_header ($title="", $heading="", $navigation="", $focus="", $meta="", $cache=true, $button="") {
f9903ed0 15// $title - appears top of window
16// $heading - appears top of page
17// $navigation - premade navigation string
18// $focus - indicates form element eg inputform.password
19// $meta - meta tags in the header
c7e3ac2a 20// $cache - should this page be cacheable?
21// $button - code for a button in the top-right
f9903ed0 22 global $USER, $CFG, $THEME;
23
24 if (file_exists("$CFG->dirroot/theme/$CFG->theme/styles.css")) {
25 $styles = "$CFG->wwwroot/theme/$CFG->theme/styles.css";
26 } else {
27 $styles = "$CFG->wwwroot/theme/standard/styles.css";
28 }
29
30 if (!$cache) { // Do everything we can to prevent clients and proxies caching
31 @header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
32 @header("Pragma: no-cache");
33 $meta .= "\n<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">";
34 $meta .= "\n<META HTTP-EQUIV=\"Expires\" CONTENT=\"0\">";
35 }
36
37 include ("$CFG->dirroot/theme/$CFG->theme/header.html");
38}
39
40function print_footer ($course=NULL) {
41// Can provide a course object to make the footer contain a link to
42// to the course home page, otherwise the link will go to the site home
43 global $USER, $CFG, $THEME;
44
45 if ($course) {
46 $homelink = "<A TARGET=_top HREF=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</A>";
47 } else {
48 $homelink = "<A TARGET=_top HREF=\"$CFG->wwwroot\">Home</A>";
49 }
50 include ("$CFG->dirroot/theme/$CFG->theme/footer.html");
51}
52
53function print_navigation ($navigation) {
54 global $CFG;
55
56 if ($navigation) {
a83fded1 57 if (! $site = get_site()) {
bcc83c41 58 $site->shortname = get_string("home");;
59 }
a2eaeb91 60 echo "<A TARGET=_top HREF=\"$CFG->wwwroot/\">$site->shortname</A> -> $navigation";
f9903ed0 61 }
62}
63
2a46a71b 64function print_heading($text, $align="CENTER", $size=3) {
65 echo "<P ALIGN=\"$align\"><FONT SIZE=\"$size\"><B>$text</B></FONT></P>";
f9903ed0 66}
67
4216daa6 68function print_simple_box($message, $align="", $width="", $color="#FFFFFF", $padding=5, $border=1) {
69 print_simple_box_start($align, $width, $color, $padding, $border);
f9903ed0 70 echo "<P>$message</P>";
71 print_simple_box_end();
72}
73
4216daa6 74function print_simple_box_start($align="", $width="", $color="#FFFFFF", $padding=5, $border=1) {
f9903ed0 75 global $THEME;
76
77 if ($align) {
78 $tablealign = "ALIGN=\"$align\"";
79 }
80 if ($width) {
81 $tablewidth = "WIDTH=\"$width\"";
82 $innertablewidth = "WIDTH=\"100%\"";
83 }
4216daa6 84 echo "<TABLE $tablealign $tablewidth BORDER=0 CELLPADDING=\"$border\" CELLSPACING=0>";
f9903ed0 85 echo "<TR><TD BGCOLOR=\"$THEME->borders\">\n";
86 echo "<TABLE $innertablewidth BORDER=0 CELLPADDING=\"$padding\" CELLSPACING=0><TR><TD BGCOLOR=\"$color\">";
87}
88
89function print_simple_box_end() {
90 echo "</TD></TR></TABLE>";
91 echo "</TD></TR></TABLE>";
92}
93
94function print_single_button($link, $options, $label="OK") {
95 echo "<FORM ACTION=\"$link\" METHOD=GET>";
96 foreach ($options as $name => $value) {
97 echo "<INPUT TYPE=hidden NAME=\"$name\" VALUE=\"$value\">";
98 }
99 echo "<INPUT TYPE=submit VALUE=\"$label\"></FORM>";
100}
101
136dabd8 102function print_user_picture($userid, $courseid, $picture, $large=false, $returnstring=false) {
f9903ed0 103 global $CFG;
104
136dabd8 105 $output = "<A HREF=\"$CFG->wwwroot/user/view.php?id=$userid&course=$courseid\">";
f9903ed0 106 if ($large) {
107 $file = "f1.jpg";
108 $size = 100;
109 } else {
110 $file = "f2.jpg";
111 $size = 35;
112 }
113 if ($picture) {
136dabd8 114 $output .= "<IMG SRC=\"$CFG->wwwroot/user/pix.php/$userid/$file\" BORDER=0 WIDTH=$size HEIGHT=$size ALT=\"\">";
f9903ed0 115 } else {
136dabd8 116 $output .= "<IMG SRC=\"$CFG->wwwroot/user/default/$file\" BORDER=0 WIDTH=$size HEIGHT=$size ALT=\"\">";
117 }
118 $output .= "</A>";
119
120 if ($returnstring) {
121 return $output;
122 } else {
123 echo $output;
f9903ed0 124 }
f9903ed0 125}
126
127function print_table($table) {
128// Prints a nicely formatted table.
129// $table is an object with three properties.
130// $table->head is an array of heading names.
131// $table->align is an array of column alignments
132// $table->data[] is an array of arrays containing the data.
133
37b15514 134 if ($table->align) {
f9903ed0 135 foreach ($table->align as $key => $aa) {
136 if ($aa) {
137 $align[$key] = "ALIGN=\"$aa\"";
138 } else {
139 $align[$key] = "";
140 }
141 }
142 }
143
37b15514 144 print_simple_box_start("CENTER", "80%", "#FFFFFF", 0);
145 echo "<TABLE WIDTH=100% BORDER=0 valign=top align=center cellpadding=10 cellspacing=1>\n";
f9903ed0 146
147 if ($table->head) {
148 echo "<TR>";
149 foreach ($table->head as $heading) {
150 echo "<TH>$heading</TH>";
151 }
152 echo "</TR>\n";
153 }
154
155 foreach ($table->data as $row) {
156 echo "<TR VALIGN=TOP>";
157 foreach ($row as $key => $item) {
158 echo "<TD ".$align[$key].">$item</TD>";
159 }
160 echo "</TR>\n";
161 }
162 echo "</TABLE>\n";
163 print_simple_box_end();
164
165 return true;
166}
167
21ddaf60 168function print_editing_switch($courseid) {
169 global $CFG, $USER;
170
c7e3ac2a 171 if (isteacher($courseid)) {
21ddaf60 172 if ($USER->editing) {
173 echo "<A HREF=\"$CFG->wwwroot/course/view.php?id=$courseid&edit=off\">Turn editing off</A>";
174 } else {
175 echo "<A HREF=\"$CFG->wwwroot/course/view.php?id=$courseid&edit=on\">Turn editing on</A>";
176 }
177 }
178}
179
c7e3ac2a 180function update_course_icon($courseid) {
181 global $CFG, $USER;
182
183 if (isteacher($courseid)) {
184 if ($USER->editing) {
185 return "<A TITLE=\"Turn editing OFF\" HREF=\"$CFG->wwwroot/course/view.php?id=$courseid&edit=off\"
186 TARGET=_top><IMG SRC=\"$CFG->wwwroot/pix/i/edit.gif\" ALIGN=right BORDER=0></A>";
187 } else {
188 return "<A TITLE=\"Turn editing ON\" HREF=\"$CFG->wwwroot/course/view.php?id=$courseid&edit=on\"
189 TARGET=_top><IMG SRC=\"$CFG->wwwroot/pix/i/edit.gif\" ALIGN=right BORDER=0></A>";
190 }
191 }
192}
193
bcc83c41 194function update_module_icon($moduleid, $courseid) {
c7e3ac2a 195 global $CFG;
196
197 if (isteacher($courseid)) {
e07635f4 198 return "<A TITLE=\"Edit this activity\" HREF=\"$CFG->wwwroot/course/mod.php?update=$moduleid&return=true\" TARGET=_top><IMG
c7e3ac2a 199 SRC=\"$CFG->wwwroot/pix/i/edit.gif\" ALIGN=right BORDER=0></A>";
200 }
201}
202
f9903ed0 203
5fa51a39 204function userdate($date, $format="", $timezone=99) {
d552ead0 205// Returns a formatted string that represents a date in user time
7a302afc 206// WARNING: note that the format is for strftime(), not date().
207
873960de 208 global $USER;
209
5fa51a39 210 if ($format == "") {
7a302afc 211 $format = "%A, %e %B %Y, %I:%M %p";
5fa51a39 212 }
213 if ($timezone == 99) {
214 $timezone = (float)$USER->timezone;
215 }
216 if (abs($timezone) > 12) {
6d9d8344 217 return strftime("$format", $date);
873960de 218 }
7a302afc 219 return gmstrftime($format, $date + (int)($timezone * 3600));
873960de 220}
221
5fa51a39 222function usergetdate($date, $timezone=99) {
d552ead0 223// Returns an array that represents a date in user time
873960de 224 global $USER;
225
5fa51a39 226 if ($timezone == 99) {
227 $timezone = (float)$USER->timezone;
228 }
229 if (abs($timezone) > 12) {
873960de 230 return getdate($date);
231 }
d2d6171f 232 //There is no gmgetdate so I have to fake it...
233 $date = $date + (int)($timezone * 3600);
234 $getdate["seconds"] = gmstrftime("%S", $date);
235 $getdate["minutes"] = gmstrftime("%M", $date);
236 $getdate["hours"] = gmstrftime("%H", $date);
237 $getdate["mday"] = gmstrftime("%d", $date);
238 $getdate["wday"] = gmstrftime("%u", $date);
239 $getdate["mon"] = gmstrftime("%m", $date);
240 $getdate["year"] = gmstrftime("%Y", $date);
241 $getdate["yday"] = gmstrftime("%j", $date);
242 $getdate["weekday"] = gmstrftime("%A", $date);
243 $getdate["month"] = gmstrftime("%B", $date);
244 return $getdate;
d552ead0 245}
246
247function usertime($date, $timezone=99) {
248// Given a GMT timestamp (seconds since epoch), offsets it by
249// the timezone. eg 3pm in India is 3pm GMT - 7 * 3600 seconds
250 global $USER;
251
252 if ($timezone == 99) {
253 $timezone = (float)$USER->timezone;
254 }
255 if (abs($timezone) > 12) {
256 return $date;
257 }
258 return $date - (int)($timezone * 3600);
259}
260
edf7fe8c 261function usergetmidnight($date, $timezone=99) {
262// Given a time, return the GMT timestamp of the most recent midnight
263// for the current user.
264
265 global $USER;
266
edf7fe8c 267 $userdate = usergetdate($date, $timezone);
268 $timemidnight = gmmktime (0, 0, 0, $userdate["mon"], $userdate["mday"], $userdate["year"]);
269 return usertime($timemidnight, $timezone); // Time of midnight of this user's day, in GMT
270
271}
272
d552ead0 273function usertimezone($timezone=99) {
274// returns a string that prints the user's timezone
275 global $USER;
276
277 if ($timezone == 99) {
278 $timezone = (float)$USER->timezone;
279 }
280 if (abs($timezone) > 12) {
281 return "server time";
282 }
283 if (abs($timezone) < 0.5) {
284 return "GMT";
285 }
286 if ($timezone > 0) {
287 return "GMT+$timezone";
288 } else {
289 return "GMT$timezone";
290 }
f9903ed0 291}
292
293
294function error ($message, $link="") {
295 global $CFG, $SESSION;
296
297 print_header("Error");
298 echo "<BR>";
299 print_simple_box($message, "center", "", "#FFBBBB");
300
301 if (!$link) {
302 if ( !empty($SESSION->fromurl) ) {
303 $link = "$SESSION->fromurl";
304 unset($SESSION->fromurl);
305 } else {
306 $link = "$CFG->wwwroot";
307 }
308 }
309 print_heading("<A HREF=\"$link\">Continue</A>");
310 print_footer();
311 die;
312}
313
65cf9fc3 314function helpbutton ($page, $title="", $module="moodle", $image=true, $text="") {
315 // $page = the keyword that defines a help page
316 // $title = the title of links, rollover tips, alt tags etc
317 // $module = which module is the page defined in
318 // $image = use a help image for the link? (otherwise uses text)
319 // $text = if defined then this text is used in the page, and
320 // the $page variable is ignored.
34c8915d 321 global $CFG;
65cf9fc3 322 if ($module == "") {
323 $module = "moodle";
324 }
325 if ($image) {
326 $linkobject = "<IMG BORDER=0 ALT=\"$title\" SRC=\"$CFG->wwwroot/pix/help.gif\">";
327 } else {
328 $linkobject = $title;
329 }
330 if ($text) {
331 $url = "/help.php?module=$module&text=$text";
332 } else {
333 $url = "/help.php?module=$module&file=help.$page.php";
334 }
335 link_to_popup_window ($url, "popup", $linkobject, 400, 500, $title);
34c8915d 336}
337
f9903ed0 338function notice ($message, $link="") {
339 global $THEME, $HTTP_REFERER;
340
341 if (!$link) {
342 $link = $HTTP_REFERER;
343 }
344
345 echo "<BR>";
346 print_simple_box($message, "center", "", "$THEME->cellheading");
347 print_heading("<A HREF=\"$link\">Continue</A>");
348 print_footer();
349 die;
350}
351
352function notice_yesno ($message, $linkyes, $linkno) {
353 global $THEME;
354
355 print_simple_box_start("center", "", "$THEME->cellheading");
356 echo "<P ALIGN=CENTER><FONT SIZE=3>$message</FONT></P>";
357 echo "<P ALIGN=CENTER><FONT SIZE=3><B>";
358 echo "<A HREF=\"$linkyes\">Yes</A>";
359 echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
360 echo "<A HREF=\"$linkno\">No</A>";
361 echo "</B></FONT></P>";
362 print_simple_box_end();
363}
364
365function redirect($url, $message="", $delay=0) {
366// Uses META tags to redirect the user, after printing a notice
367 global $THEME;
368
369 echo "<META HTTP-EQUIV='Refresh' CONTENT='$delay; URL=$url'>";
370
371 if (!empty($message)) {
372 print_header();
373 echo "<CENTER>";
374 echo "<P>$message</P>";
375 echo "<P>( <A HREF=\"$url\">Continue</A> )</P>";
376 echo "</CENTER>";
377 }
378 die;
379}
380
381function notify ($message) {
382 echo "<P align=center><B><FONT COLOR=#FF0000>$message</FONT></B></P>\n";
383}
384
385
386
387/// PARAMETER HANDLING ////////////////////////////////////////////////////
388
389function require_variable($var) {
f9903ed0 390 if (! isset($var)) {
391 error("A required parameter was missing");
392 }
393}
394
395function optional_variable(&$var, $default=0) {
396 if (! isset($var)) {
397 $var = $default;
398 }
399}
400
401
402
403
404/// DATABASE HANDLING ////////////////////////////////////////////////
405
406function execute_sql($command) {
407// Completely general
408
409 global $db;
410
411 $result = $db->Execute("$command");
412
413 if ($result) {
414 echo "<P><FONT COLOR=green>SUCCESS: $command</FONT></P>";
415 return true;
416 } else {
417 echo "<P><FONT COLOR=red>ERROR: $command </FONT></P>";
418 return false;
419 }
420}
421
422function modify_database($sqlfile) {
423// Assumes that the input text file consists of a number
424// of SQL statements ENDING WITH SEMICOLONS. The semicolons
425// MUST be the last character in a line.
426// Lines that are blank or that start with "#" are ignored.
427// Only tested with mysql dump files (mysqldump -p -d moodle)
428
429
430 if (file_exists($sqlfile)) {
431 $success = true;
432 $lines = file($sqlfile);
433 $command = "";
434
435 while ( list($i, $line) = each($lines) ) {
436 $line = chop($line);
437 $length = strlen($line);
438
439 if ($length && substr($line, 0, 1) <> "#") {
440 if (substr($line, $length-1, 1) == ";") {
441 $line = substr($line, 0, $length-1); // strip ;
442 $command .= $line;
443 if (! execute_sql($command)) {
444 $success = false;
445 }
446 $command = "";
447 } else {
448 $command .= $line;
449 }
450 }
451 }
452
453 } else {
454 $success = false;
455 echo "<P>Tried to modify database, but \"$sqlfile\" doesn't exist!</P>";
456 }
457
458 return $success;
459}
460
461
462function record_exists($table, $field, $value) {
463 global $db;
464
465 $rs = $db->Execute("SELECT * FROM $table WHERE $field = '$value' LIMIT 1");
466 if (!$rs) return false;
467
468 if ( $rs->RecordCount() ) {
469 return true;
470 } else {
471 return false;
472 }
473}
474
475function record_exists_sql($sql) {
476 global $db;
477
478 $rs = $db->Execute($sql);
479 if (!$rs) return false;
480
481 if ( $rs->RecordCount() ) {
482 return true;
483 } else {
484 return false;
485 }
486}
487
488
489function count_records($table, $selector, $value) {
490// Get all the records and count them
491 global $db;
492
493 $rs = $db->Execute("SELECT COUNT(*) FROM $table WHERE $selector = '$value'");
494 if (!$rs) return 0;
495
496 return $rs->fields[0];
497}
498
499function count_records_sql($sql) {
500// Get all the records and count them
501 global $db;
502
503 $rs = $db->Execute("$sql");
504 if (!$rs) return 0;
505
506 return $rs->fields[0];
507}
508
509function get_record($table, $selector, $value) {
510// Get a single record as an object
511 global $db;
512
513 $rs = $db->Execute("SELECT * FROM $table WHERE $selector = '$value'");
514 if (!$rs) return false;
515
516 if ( $rs->RecordCount() == 1 ) {
517 return (object)$rs->fields;
518 } else {
519 return false;
520 }
521}
522
523function get_record_sql($sql) {
524// Get a single record as an object
525// The sql statement is provided as a string.
526
527 global $db;
528
529 $rs = $db->Execute("$sql");
530 if (!$rs) return false;
531
532 if ( $rs->RecordCount() == 1 ) {
533 return (object)$rs->fields;
534 } else {
535 return false;
536 }
537}
538
539function get_records($table, $selector, $value, $sort="") {
540// Get a number of records as an array of objects
541// Can optionally be sorted eg "time ASC" or "time DESC"
542// The "key" is the first column returned, eg usually "id"
543 global $db;
544
545 if ($sort) {
546 $sortorder = "ORDER BY $sort";
547 }
548 $sql = "SELECT * FROM $table WHERE $selector = '$value' $sortorder";
549
550 return get_records_sql($sql);
551}
552
553function get_records_sql($sql) {
554// Get a number of records as an array of objects
555// The "key" is the first column returned, eg usually "id"
556// The sql statement is provided as a string.
557
558 global $db;
559
560 $rs = $db->Execute("$sql");
561 if (!$rs) return false;
562
563 if ( $rs->RecordCount() > 0 ) {
5c0bef5d 564 if ($records = $rs->GetAssoc(true)) {
565 foreach ($records as $key => $record) {
566 $objects[$key] = (object) $record;
567 }
568 return $objects;
569 } else {
570 return false;
f9903ed0 571 }
f9903ed0 572 } else {
573 return false;
574 }
575}
576
577function get_records_sql_menu($sql) {
578// Given an SQL select, this function returns an associative
579// array of the first two columns. This is most useful in
580// combination with the choose_from_menu function to create
581// a form menu.
582
583 global $db;
584
585 $rs = $db->Execute("$sql");
586 if (!$rs) return false;
587
588 if ( $rs->RecordCount() > 0 ) {
589 while (!$rs->EOF) {
590 $menu[$rs->fields[0]] = $rs->fields[1];
591 $rs->MoveNext();
592 }
593 return $menu;
594
595 } else {
596 return false;
597 }
598}
599
600function get_field($table, $field, $selector, $value) {
601 global $db;
602
603 $rs = $db->Execute("SELECT $field FROM $table WHERE $selector = '$value'");
604 if (!$rs) return false;
605
606 if ( $rs->RecordCount() == 1 ) {
607 return $rs->fields["$field"];
608 } else {
609 return false;
610 }
611}
612
613function set_field($table, $field, $newvalue, $selector, $value) {
614 global $db;
615
616 return $db->Execute("UPDATE $table SET $field = '$newvalue' WHERE $selector = '$value'");
617}
618
619
620function delete_records($table, $selector, $value) {
621// Delete one or more records from a table
622 global $db;
623
624 return $db->Execute("DELETE FROM $table WHERE $selector = '$value'");
625}
626
627function insert_record($table, $dataobject) {
628// Insert a record into a table and return the "id" field
629// $dataobject is an object containing needed data
630
631 global $db;
632
633 // Determine all the fields needed
634 if (! $columns = $db->MetaColumns("$table")) {
635 return false;
636 }
637
638 $data = (array)$dataobject;
639
640 // Pull out data matching these fields
641 foreach ($columns as $column) {
642 if ($column->name <> "id" && $data[$column->name] ) {
643 $ddd[$column->name] = $data[$column->name];
644 }
645 }
646
647 // Construct SQL queries
648 if (! $numddd = count($ddd)) {
649 return 0;
650 }
651
652 $count = 0;
653 $insert = "";
654 $select = "";
655
656 foreach ($ddd as $key => $value) {
657 $count++;
658 $insert .= "$key = '$value'";
659 $select .= "$key = '$value'";
660 if ($count < $numddd) {
661 $insert .= ", ";
662 $select .= " AND ";
663 }
664 }
665
666 if (! $rs = $db->Execute("INSERT INTO $table SET $insert")) {
667 return false;
668 }
669
670 // Pull it out again to find the id. This is the most cross-platform method.
671 if ($rs = $db->Execute("SELECT id FROM $table WHERE $select")) {
672 return $rs->fields[0];
673 } else {
674 return false;
675 }
676}
677
678
679function update_record($table, $dataobject) {
680// Update a record in a table
681// $dataobject is an object containing needed data
682
683 global $db;
684
5c0bef5d 685 if (! isset($dataobject->id) ) {
f9903ed0 686 return false;
687 }
688
689 // Determine all the fields in the table
1afd014e 690 if (!$columns = $db->MetaColumns($table)) {
691 return false;
692 }
f9903ed0 693 $data = (array)$dataobject;
694
695 // Pull out data matching these fields
696 foreach ($columns as $column) {
5c0bef5d 697 if ($column->name <> "id" && isset($data[$column->name]) ) {
f9903ed0 698 $ddd[$column->name] = $data[$column->name];
699 }
700 }
701
702 // Construct SQL queries
703 $numddd = count($ddd);
704 $count = 0;
705 $update = "";
706
707 foreach ($ddd as $key => $value) {
708 $count++;
709 $update .= "$key = '$value'";
710 if ($count < $numddd) {
711 $update .= ", ";
712 }
713 }
714
715 if ($rs = $db->Execute("UPDATE $table SET $update WHERE id = '$dataobject->id'")) {
716 return true;
717 } else {
718 return false;
719 }
720}
721
722
f93f848a 723function print_object($object) {
724// Mostly just for debugging
725
726 $array = (array)$object;
727 foreach ($array as $key => $item) {
728 echo "$key -> $item <BR>";
729 }
730}
731
732
f9903ed0 733
734/// USER DATABASE ////////////////////////////////////////////////
735
736function get_user_info_from_db($field, $value) {
737
738 global $db;
739
740 if (!$field || !$value)
741 return false;
742
743 $result = $db->Execute("SELECT * FROM user WHERE $field = '$value'");
744
745 if ( $result->RecordCount() == 1 ) {
746 $user = (object)$result->fields;
747
748 $rs = $db->Execute("SELECT course FROM user_students WHERE user = '$user->id' ");
749 while (!$rs->EOF) {
750 $course = $rs->fields["course"];
751 $user->student["$course"] = true;
752 $rs->MoveNext();
753 }
754
755 $rs = $db->Execute("SELECT course FROM user_teachers WHERE user = '$user->id' ");
756 while (!$rs->EOF) {
757 $course = $rs->fields["course"];
758 $user->teacher["$course"] = true;
759 $rs->MoveNext();
760 }
761
762 $rs = $db->Execute("SELECT * FROM user_admins WHERE user = '$user->id' ");
763 while (!$rs->EOF) {
764 $user->admin = true;
765 $rs->MoveNext();
766 }
767
a83fded1 768 if ($course = get_site()) {
f9903ed0 769 // Everyone is always a member of the top course
770 $user->student["$course->id"] = true;
771 }
772
773 return $user;
774
775 } else {
776 return false;
777 }
778}
779
780function update_user_in_db() {
781
782 global $db, $USER, $REMOTE_ADDR;
783
784 if (!isset($USER->id))
785 return false;
786
787 $timenow = time();
788 if ($db->Execute("UPDATE LOW_PRIORITY user SET lastIP='$REMOTE_ADDR', lastaccess='$timenow'
789 WHERE id = '$USER->id' ")) {
790 return true;
791 } else {
792 return false;
793 }
794}
795
da5c172a 796function require_login($courseid=0) {
797// This function checks that the current user is logged in, and optionally
798// whether they are "logged in" or allowed to be in a particular course.
799// If not, then it redirects them to the site login or course enrolment.
f9903ed0 800
801 global $CFG, $SESSION, $USER, $FULLME, $HTTP_REFERER, $PHPSESSID;
802
da5c172a 803 // First check that the user is logged in to the site.
f9903ed0 804 if (! (isset( $USER->loggedin ) && $USER->confirmed) ) {
805 $SESSION->wantsurl = $FULLME;
806 $SESSION->fromurl = $HTTP_REFERER;
807 if ($PHPSESSID) { // Cookies not enabled.
808 redirect("$CFG->wwwroot/login/?PHPSESSID=$PHPSESSID");
809 } else {
810 redirect("$CFG->wwwroot/login/");
811 }
812 die;
f9903ed0 813 }
da5c172a 814
815 // Next, check if the user can be in a particular course
816 if ($courseid) {
817 if ($USER->student[$courseid] || $USER->teacher[$courseid] || $USER->admin) {
818 update_user_in_db();
819 return; // user is a member of this course.
820 }
821 if (! $course = get_record("course", "id", $courseid)) {
822 error("That course doesn't exist");
823 }
824 if ($course->guest && ($USER->username == "guest")) {
825 update_user_in_db();
826 return; // user is a guest and this course allows guests
827 }
f9903ed0 828
da5c172a 829 // Not allowed in the course, so see if they want to enrol
830
831 $SESSION->wantsurl = $FULLME;
832 redirect("$CFG->wwwroot/course/enrol.php?id=$courseid");
833 die;
834 }
f9903ed0 835}
836
837
838
839function update_login_count() {
840 global $SESSION;
841
842 $max_logins = 10;
843
844 if (empty($SESSION->logincount)) {
845 $SESSION->logincount = 1;
846 } else {
847 $SESSION->logincount++;
848 }
849
850 if ($SESSION->logincount > $max_logins) {
851 unset($SESSION->wantsurl);
852 error("Sorry, you have exceeded the allowed number of login attempts. Restart your browser.");
853 }
854}
855
856
857function isadmin($userid=0) {
858 global $USER;
859
860 if (!$userid) {
861 return $USER->admin;
862 }
863
864 return record_exists_sql("SELECT * FROM user_admins WHERE user='$userid'");
865}
866
867function isteacher($course, $userid=0) {
868 global $USER;
869
d115a57f 870 if (isadmin($userid)) { // admins can do anything the teacher can
871 return true;
872 }
873
f9903ed0 874 if (!$userid) {
875 return $USER->teacher[$course];
876 }
877
878 return record_exists_sql("SELECT * FROM user_teachers WHERE user='$userid' AND course='$course'");
879}
880
881
882function isstudent($course, $userid=0) {
883 global $USER;
884
885 if (!$userid) {
886 return $USER->student[$course];
887 }
888
889 $timenow = time(); // todo: add time check below
890
891 return record_exists_sql("SELECT * FROM user_students WHERE user='$userid' AND course='$course'");
892}
893
da5c172a 894function isguest($userid=0) {
895 global $USER;
896
897 if (!$userid) {
898 return ($USER->username == "guest");
899 }
900
901 return record_exists_sql("SELECT * FROM user WHERE user='$userid' AND username = 'guest' ");
902}
903
f9903ed0 904
905function reset_login_count() {
906 global $SESSION;
907
908 $SESSION->logincount = 0;
909}
910
911
912function set_moodle_cookie($thing) {
913
914 $days = 60;
915 $seconds = 60*60*24*$days;
916
d115a57f 917 setCookie ('MOODLEID', "", time() - 3600, "/");
f9903ed0 918 setCookie ('MOODLEID', rc4encrypt($thing), time()+$seconds, "/");
919}
920
921
922function get_moodle_cookie() {
923 global $MOODLEID;
924 return rc4decrypt($MOODLEID);
925}
926
927
928
929function verify_login($username, $password) {
930
931 $user = get_user_info_from_db("username", $username);
932
933 if (! $user) {
934 return false;
935 } else if ( $user->password == md5($password) ) {
936 return $user;
937 } else {
938 return false;
939 }
940}
941
942function get_site () {
943// Returns $course object of the top-level site.
944 if ( $course = get_record("course", "category", 0)) {
945 return $course;
946 } else {
947 return false;
948 }
949}
950
951function get_admin () {
952// Returns $user object of the main admin user
953
954 if ( $admins = get_records_sql("SELECT u.* FROM user u, user_admins a WHERE a.user = u.id ORDER BY u.id ASC")) {
955 foreach ($admins as $admin) {
956 return $admin; // ie the first one (yeah I know it's bodgy)
957 }
958 } else {
959 return false;
960 }
961}
962
963function get_teacher($courseid) {
964// Returns $user object of the main teacher for a course
965 if ( $teachers = get_records_sql("SELECT u.* FROM user u, user_teachers t
966 WHERE t.user = u.id AND t.course = '$courseid'
967 ORDER BY t.authority ASC")) {
968 foreach ($teachers as $teacher) {
969 return $teacher; // ie the first one (yeah I know it's bodgy)
970 }
971 } else {
972 return false;
973 }
974}
975
976
977
978/// MODULE FUNCTIONS /////////////////////////////////////////////////
979
980function get_coursemodule_from_instance($modulename, $instance, $course) {
981// Given an instance of a module, finds the coursemodule description
982
983 return get_record_sql("SELECT cm.*, m.name
984 FROM course_modules cm, modules md, $modulename m
985 WHERE cm.course = '$course' AND
986 cm.deleted = '0' AND
987 cm.instance = m.id AND
988 md.name = '$modulename' AND
989 md.id = cm.module AND
990 m.id = '$instance'");
991
992}
993
9ccbad71 994function get_all_instances_in_course($modulename, $course, $sort="cw.section") {
f9903ed0 995// Returns an array of all the active instances of a particular
996// module in a given course. Returns false on any errors.
997
9ccbad71 998 return get_records_sql("SELECT m.*,cw.section,cm.id as coursemodule
999 FROM course_modules cm, course_sections cw, modules md, $modulename m
f9903ed0 1000 WHERE cm.course = '$course' AND
1001 cm.instance = m.id AND
1002 cm.deleted = '0' AND
9ccbad71 1003 cm.section = cw.id AND
f9903ed0 1004 md.name = '$modulename' AND
1005 md.id = cm.module
1006 ORDER BY $sort");
1007
1008}
1009
f9903ed0 1010
1011
1012
1013
1014/// CORRESPONDENCE ////////////////////////////////////////////////
1015
5fa51a39 1016function email_to_user($user, $from, $subject, $messagetext, $messagehtml="", $attachment="", $attachname="") {
1017// user - a user record as an object
1018// from - a user record as an object
1019// subject - plain text subject line of the email
136dabd8 1020// messagetext - plain text version of the message
1021// messagehtml - complete html version of the message (optional)
1022// attachment - a file on the filesystem, relative to $CFG->dataroot
1023// attachname - the name of the file (extension indicates MIME)
f9903ed0 1024
4216daa6 1025 global $CFG, $_SERVER;
f9903ed0 1026
136dabd8 1027 include_once("$CFG->libdir/phpmailer/class.phpmailer.php");
f9903ed0 1028
5fa51a39 1029 if (!$user) {
f9903ed0 1030 return false;
1031 }
1032
f9903ed0 1033 $mail = new phpmailer;
1034
1e411ffc 1035 $mail->Version = "Moodle $CFG->moodleversion"; // mailer version
136dabd8 1036 $mail->PluginDir = "$CFG->libdir/phpmailer/"; // plugin directory (eg smtp plugin)
7f86ce17 1037 if ($CFG->smtphosts) {
1e411ffc 1038 $mail->IsSMTP(); // use SMTP directly
1039 $mail->Host = "$CFG->smtphosts"; // specify main and backup servers
7f86ce17 1040 } else {
1e411ffc 1041 $mail->IsMail(); // use PHP mail() = sendmail
7f86ce17 1042 }
f9903ed0 1043
136dabd8 1044 $mail->From = "$from->email";
1045 $mail->FromName = "$from->firstname $from->lastname";
1046 $mail->Subject = stripslashes($subject);
f9903ed0 1047
5fa51a39 1048 $mail->AddBCC("$user->email","$user->firstname $user->lastname");
f9903ed0 1049
f9903ed0 1050 $mail->WordWrap = 70; // set word wrap
f9903ed0 1051
136dabd8 1052 if ($messagehtml) {
1053 $mail->IsHTML(true);
1054 $mail->Body = $messagehtml;
78681899 1055 $mail->AltBody = "\n$messagetext\n";
136dabd8 1056 } else {
1057 $mail->IsHTML(false);
78681899 1058 $mail->Body = "\n$messagetext\n";
f9903ed0 1059 }
1060
136dabd8 1061 if ($attachment && $attachname) {
1062 if (ereg( "\\.\\." ,$attachment )) { // Security check for ".." in dir path
4216daa6 1063 $adminuser = get_admin();
1064 $mail->AddAddress("$adminuser->email", "$adminuser->firstname $adminuser->lastname");
1065 $mail->AddStringAttachment("Error in attachment. User attempted to attach a filename with a unsafe name.", "error.txt", "8bit", "text/plain");
136dabd8 1066 } else {
1067 include_once("$CFG->dirroot/files/mimetypes.php");
1068 $mimetype = mimeinfo("type", $attachname);
1069 $mail->AddAttachment("$CFG->dataroot/$attachment", "$attachname", "base64", "$mimetype");
1070 }
f9903ed0 1071 }
1072
136dabd8 1073 if ($mail->Send()) {
1074 return true;
1075 } else {
4216daa6 1076 echo "ERROR: $mail->ErrorInfo\n";
1077 $site = get_site();
1078 add_to_log($site->id, "library", "mailer", $_SERVER["REQUEST_URI"], "ERROR: $mail->ErrorInfo");
f9903ed0 1079 return false;
1080 }
f9903ed0 1081}
1082
136dabd8 1083
f9903ed0 1084/// FILE HANDLING /////////////////////////////////////////////
1085
1086function get_directory_list( $rootdir ) {
1087// Returns an array with all the filenames in
1088// all subdirectories, relative to the given rootdir.
1089
1090 $dirs = array();
1091
1092 $dir = opendir( $rootdir );
1093
1094 while( $file = readdir( $dir ) ) {
1095 $fullfile = $rootdir."/".$file;
1096 if ($file != "." and $file != "..") {
1097 if (filetype($fullfile) == "dir") {
1098 $subdirs = get_directory_list($fullfile);
1099 foreach ($subdirs as $subdir) {
1100 $dirs[] = $file."/".$subdir;
1101 }
1102 } else {
1103 $dirs[] = $file;
1104 }
1105 }
1106 }
1107
1108 return $dirs;
1109}
1110
1180c6dc 1111/// STRING TRANSLATION ////////////////////////////////////////
1112
a83fded1 1113function print_string($identifier, $module="", $a=NULL) {
1114 echo get_string($identifier, $module, $a);
bcc83c41 1115}
1116
1117
a83fded1 1118function get_string($identifier, $module="", $a=NULL) {
1180c6dc 1119// Return the translated string specified by $identifier as
1120// for $module. Uses the same format files as STphp.
a83fded1 1121// $a is an object, string or number that can be used
1180c6dc 1122// within translation strings
a83fded1 1123//
1124// eg "hello \$a->firstname \$a->lastname"
1125// or "hello \$a"
1180c6dc 1126
1127 global $CFG, $USER;
1128
1129 if (isset($USER->lang)) { // User language can override site language
1130 $lang = $USER->lang;
1131 } else {
1132 $lang = $CFG->lang;
1133 }
1134
1135 if ($module == "" or $module == "moodle") {
1136 $langpath = "$CFG->dirroot/lang";
1137 } else {
1138 $langpath = "$CFG->dirroot/mod/$module/lang";
1139 }
1140
1141 $langfile = "$langpath/$lang/strings.php";
1142
1143 if (!file_exists($langfile)) { // try English instead
1144 $langfile = "$langpath/en/strings.php";
1145 if (!file_exists($langfile)) {
7a302afc 1146 return "ERROR: No lang file";
1180c6dc 1147 }
1148 }
1149
1150 if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
1151
1152 eval($result);
1153 return $resultstring;
1154
1155 } else {
1156 if ($lang == "en") {
7a302afc 1157 return "ERROR: '$identifier' is missing!";
1180c6dc 1158
1159 } else { // Try looking in the english file.
1160 $langfile = "$langpath/en/strings.php";
1161 if (!file_exists($langfile)) {
7a302afc 1162 return "ERROR: No lang file";
1180c6dc 1163 }
1164 if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
1165 eval($result);
1166 return $resultstring;
1167 } else {
7a302afc 1168 return "ERROR: '$identifier' is missing!";
1180c6dc 1169 }
1170 }
1171 }
1172}
1173
1174
1180c6dc 1175function get_string_from_file($identifier, $langfile, $destination) {
1176// This function is only used from get_string().
1177 include ($langfile);
1178
1179 if (!isset ($string[$identifier])) {
1180 return false;
1181 }
1182
a83fded1 1183 return "$destination = sprintf(\"".$string[$identifier]."\");";
1180c6dc 1184}
f9903ed0 1185
1186
1187/// ENCRYPTION ////////////////////////////////////////////////
1188
1189function rc4encrypt($data) {
1190 $password = "nfgjeingjk";
1191 return endecrypt($password, $data, "");
1192}
1193
1194function rc4decrypt($data) {
1195 $password = "nfgjeingjk";
1196 return endecrypt($password, $data, "de");
1197}
1198
1199function endecrypt ($pwd, $data, $case) {
1200// Based on a class by Mukul Sabharwal [mukulsabharwal@yahoo.com]
1201
1202 if ($case == 'de') {
1203 $data = urldecode($data);
1204 }
1205
1206 $key[] = "";
1207 $box[] = "";
1208 $temp_swap = "";
1209 $pwd_length = 0;
1210
1211 $pwd_length = strlen($pwd);
1212
1213 for ($i = 0; $i <= 255; $i++) {
1214 $key[$i] = ord(substr($pwd, ($i % $pwd_length), 1));
1215 $box[$i] = $i;
1216 }
1217
1218 $x = 0;
1219
1220 for ($i = 0; $i <= 255; $i++) {
1221 $x = ($x + $box[$i] + $key[$i]) % 256;
1222 $temp_swap = $box[$i];
1223 $box[$i] = $box[$x];
1224 $box[$x] = $temp_swap;
1225 }
1226
1227 $temp = "";
1228 $k = "";
1229
1230 $cipherby = "";
1231 $cipher = "";
1232
1233 $a = 0;
1234 $j = 0;
1235
1236 for ($i = 0; $i < strlen($data); $i++) {
1237 $a = ($a + 1) % 256;
1238 $j = ($j + $box[$a]) % 256;
1239 $temp = $box[$a];
1240 $box[$a] = $box[$j];
1241 $box[$j] = $temp;
1242 $k = $box[(($box[$a] + $box[$j]) % 256)];
1243 $cipherby = ord(substr($data, $i, 1)) ^ $k;
1244 $cipher .= chr($cipherby);
1245 }
1246
1247 if ($case == 'de') {
1248 $cipher = urldecode(urlencode($cipher));
1249 } else {
1250 $cipher = urlencode($cipher);
1251 }
1252
1253 return $cipher;
1254}
1255
1256
1257/// MISCELLANEOUS ////////////////////////////////////////////////////////////////////
1258
1259function getweek ($startdate, $thedate) {
1260// Given dates in seconds, how many weeks is the date from startdate
1261// The first week is 1, the second 2 etc ...
1262
1263 if ($thedate < $startdate) { // error
1264 return 0;
1265 }
1266
1267 return floor(($thedate - $startdate) / 604800.0) + 1;
1268}
1269
4216daa6 1270function add_to_log($course, $module, $action, $url="", $info="") {
1271// Add an entry to the log table. These are "action" focussed rather
1272// than web server hits, and provide a way to easily reconstruct what
1273// any particular student has been doing.
1274//
1275// course = the course id
1276// module = discuss, journal, reading, course, user etc
1277// action = view, edit, post (often but not always the same as the file.php)
1278// url = the file and parameters used to see the results of the action
1279// info = additional description information
1280
1281
f9903ed0 1282 global $db, $USER, $REMOTE_ADDR;
1283
1284 $timenow = time();
4216daa6 1285 $info = addslashes($info);
1286
1287 $result = $db->Execute("INSERT INTO log
1288 SET time = '$timenow',
1289 user = '$USER->id',
1290 course = '$course',
1291 ip = '$REMOTE_ADDR',
1292 module = '$module',
1293 action = '$action',
1294 url = '$url',
1295 info = '$info'");
f9903ed0 1296 if (!$result) {
4216daa6 1297 echo "<P>Error: Could not insert a new entry to the Moodle log</P>"; // Don't throw an error
f9903ed0 1298 }
1299}
1300
1301function generate_password($maxlen=10) {
1302/* returns a randomly generated password of length $maxlen. inspired by
1303 * http://www.phpbuilder.com/columns/jesus19990502.php3 */
1304
1305 global $CFG;
1306
1307 $fillers = "1234567890!$-+";
1308 $wordlist = file($CFG->wordlist);
1309
1310 srand((double) microtime() * 1000000);
1311 $word1 = trim($wordlist[rand(0, count($wordlist) - 1)]);
1312 $word2 = trim($wordlist[rand(0, count($wordlist) - 1)]);
1313 $filler1 = $fillers[rand(0, strlen($fillers) - 1)];
1314
1315 return substr($word1 . $filler1 . $word2, 0, $maxlen);
1316}
1317
1318
1319function format_time($totalsecs) {
1320
1321 $days = floor($totalsecs/86400);
1322 $remainder = $totalsecs - ($days*86400);
1323 $hours = floor($remainder/3600);
1324 $remainder = $remainder - ($hours*3600);
1325 $mins = floor($remainder/60);
1326 $secs = $remainder - ($mins*60);
1327
1328 if ($secs != 1) $ss = "s";
1329 if ($mins != 1) $ms = "s";
1330 if ($hours != 1) $hs = "s";
1331 if ($days != 1) $ds = "s";
1332
1333 if ($days) $odays = "$days day$ds";
1334 if ($hours) $ohours = "$hours hr$hs";
1335 if ($mins) $omins = "$mins min$ms";
1336 if ($secs) $osecs = "$secs sec$ss";
1337
1338 if ($days) return "$odays $ohours";
1339 if ($hours) return "$ohours $omins";
1340 if ($mins) return "$omins $osecs";
1341 if ($secs) return "$osecs";
1342 return "now";
1343}
1344
f9903ed0 1345?>