Capitalized $user->sessionIP to $USER->sessionIP. Probably was a typo,
[moodle.git] / lib / moodlelib.php
CommitLineData
ef1e97c7 1<?php // $Id$
f9903ed0 2
9fa49e22 3///////////////////////////////////////////////////////////////////////////
4// //
5// NOTICE OF COPYRIGHT //
6// //
7// Moodle - Modular Object-Oriented Dynamic Learning Environment //
abc3b857 8// http://moodle.org //
9fa49e22 9// //
abc3b857 10// Copyright (C) 1999-2004 Martin Dougiamas http://dougiamas.com //
9fa49e22 11// //
12// This program is free software; you can redistribute it and/or modify //
13// it under the terms of the GNU General Public License as published by //
14// the Free Software Foundation; either version 2 of the License, or //
15// (at your option) any later version. //
16// //
17// This program is distributed in the hope that it will be useful, //
18// but WITHOUT ANY WARRANTY; without even the implied warranty of //
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
20// GNU General Public License for more details: //
21// //
22// http://www.gnu.org/copyleft/gpl.html //
23// //
24///////////////////////////////////////////////////////////////////////////
65ccdd8c 25
7cf1c7bd 26/**
89dcb99d 27 * moodlelib.php - Moodle main library
7cf1c7bd 28 *
29 * Main library file of miscellaneous general-purpose Moodle functions.
30 * Other main libraries:
8c3dba73 31 * - weblib.php - functions that produce web output
32 * - datalib.php - functions that access the database
7cf1c7bd 33 * @author Martin Dougiamas
34 * @version $Id$
89dcb99d 35 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
7cf1c7bd 36 * @package moodlecore
37 */
f374fb10 38/// CONSTANTS /////////////////////////////////////////////////////////////
39
6b94a807 40/**
41 * Used by some scripts to check they are being called by Moodle
42 */
43define('MOODLE_INTERNAL', true);
44
45
7cf1c7bd 46/**
47 * No groups used?
48 */
d8ba183c 49define('NOGROUPS', 0);
7cf1c7bd 50
51/**
52 * Groups used?
53 */
f374fb10 54define('SEPARATEGROUPS', 1);
7cf1c7bd 55
56/**
57 * Groups visible?
58 */
f374fb10 59define('VISIBLEGROUPS', 2);
60
7a5672c9 61/**
2f87145b 62 * Time constant - the number of seconds in a week
7a5672c9 63 */
361855e6 64define('WEEKSECS', 604800);
2f87145b 65
66/**
67 * Time constant - the number of seconds in a day
68 */
7a5672c9 69define('DAYSECS', 86400);
2f87145b 70
71/**
72 * Time constant - the number of seconds in an hour
73 */
7a5672c9 74define('HOURSECS', 3600);
2f87145b 75
76/**
77 * Time constant - the number of seconds in a minute
78 */
7a5672c9 79define('MINSECS', 60);
2f87145b 80
81/**
82 * Time constant - the number of minutes in a day
83 */
7a5672c9 84define('DAYMINS', 1440);
2f87145b 85
86/**
87 * Time constant - the number of minutes in an hour
88 */
7a5672c9 89define('HOURMINS', 60);
f9903ed0 90
e0d346ff 91/**
3af57507 92 * Parameter constants - if set then the parameter is cleaned of scripts etc
e0d346ff 93 */
3af57507 94define('PARAM_RAW', 0x00);
e0d346ff 95define('PARAM_CLEAN', 0x01);
e0d346ff 96define('PARAM_INT', 0x02);
3af57507 97define('PARAM_INTEGER', 0x02); // Alias for PARAM_INT
98define('PARAM_ALPHA', 0x04);
99define('PARAM_ACTION', 0x04); // Alias for PARAM_ALPHA
100define('PARAM_FORMAT', 0x04); // Alias for PARAM_ALPHA
101define('PARAM_NOTAGS', 0x08);
102define('PARAM_FILE', 0x10);
103define('PARAM_PATH', 0x20);
e0d346ff 104
105
9fa49e22 106/// PARAMETER HANDLING ////////////////////////////////////////////////////
6b174680 107
e0d346ff 108/**
361855e6 109 * Returns a particular value for the named variable, taken from
110 * POST or GET. If the parameter doesn't exist then an error is
e0d346ff 111 * thrown because we require this variable.
112 *
361855e6 113 * This function should be used to initialise all required values
114 * in a script that are based on parameters. Usually it will be
e0d346ff 115 * used like this:
116 * $id = required_param('id');
117 *
118 * @param string $varname the name of the parameter variable we want
119 * @param integer $options a bit field that specifies any cleaning needed
120 * @return mixed
121 */
122function required_param($varname, $options=PARAM_CLEAN) {
e0d346ff 123
124 if (isset($_POST[$varname])) { // POST has precedence
125 $param = $_POST[$varname];
126 } else if (isset($_GET[$varname])) {
127 $param = $_GET[$varname];
128 } else {
3af57507 129 error('A required parameter ('.$varname.') was missing');
e0d346ff 130 }
131
132 return clean_param($param, $options);
133}
134
135/**
361855e6 136 * Returns a particular value for the named variable, taken from
e0d346ff 137 * POST or GET, otherwise returning a given default.
138 *
361855e6 139 * This function should be used to initialise all optional values
140 * in a script that are based on parameters. Usually it will be
e0d346ff 141 * used like this:
142 * $name = optional_param('name', 'Fred');
143 *
144 * @param string $varname the name of the parameter variable we want
145 * @param mixed $default the default value to return if nothing is found
146 * @param integer $options a bit field that specifies any cleaning needed
147 * @return mixed
148 */
149function optional_param($varname, $default=NULL, $options=PARAM_CLEAN) {
e0d346ff 150
151 if (isset($_POST[$varname])) { // POST has precedence
152 $param = $_POST[$varname];
153 } else if (isset($_GET[$varname])) {
154 $param = $_GET[$varname];
155 } else {
156 return $default;
157 }
158
159 return clean_param($param, $options);
160}
161
162/**
361855e6 163 * Used by {@link optional_param()} and {@link required_param()} to
164 * clean the variables and/or cast to specific types, based on
e0d346ff 165 * an options field.
166 *
167 * @param mixed $param the variable we are cleaning
168 * @param integer $options a bit field that specifies the cleaning needed
169 * @return mixed
170 */
171function clean_param($param, $options) {
e0d346ff 172
3af57507 173 if (!$options) {
174 return $param; // Return raw value
175 }
176
7228f796 177 if ((string)$param == (string)(int)$param) { // It's just an integer
e0d346ff 178 return (int)$param;
179 }
180
181 if ($options & PARAM_CLEAN) {
182 $param = clean_text($param); // Sweep for scripts, etc
183 }
184
185 if ($options & PARAM_INT) {
186 $param = (int)$param; // Convert to integer
187 }
188
3af57507 189 if ($options & PARAM_ALPHA) { // Remove everything not a-z
190 $param = eregi_replace('[^a-z]', '', $param);
191 }
192
193 if ($options & PARAM_NOTAGS) { // Strip all tags completely
194 $param = strip_tags($param);
195 }
196
197 if ($options & PARAM_FILE) { // Strip all suspicious characters from filename
d52d5a8e 198 $param = clean_param($param, PARAM_PATH);
199 $pos = strrpos($param,'/');
200 if ($pos !== FALSE) {
201 $param = substr($param, $pos+1);
202 }
7e6b7f8d 203 if ($param === '.' or $param === ' ') {
204 $param = '';
361855e6 205 }
3af57507 206 }
207
208 if ($options & PARAM_PATH) { // Strip all suspicious characters from file path
d52d5a8e 209 $param = str_replace('\\\'', '\'', $param);
210 $param = str_replace('\\"', '"', $param);
7e6b7f8d 211 $param = str_replace('\\', '/', $param);
d52d5a8e 212 $param = ereg_replace('[[:cntrl:]]|[<>"`\|\']', '', $param);
7e6b7f8d 213 $param = ereg_replace('\.\.+', '', $param);
d52d5a8e 214 $param = ereg_replace('//+', '/', $param);
3af57507 215 }
216
e0d346ff 217 return $param;
218}
219
7cf1c7bd 220/**
7228f796 221 * For security purposes, this function will check that the currently
222 * given sesskey (passed as a parameter to the script or this function)
223 * matches that of the current user.
7cf1c7bd 224 *
7228f796 225 * @param string $sesskey optionally provided sesskey
226 * @return boolean
227 */
228function confirm_sesskey($sesskey=NULL) {
229 global $USER;
230
089e9eae 231 if (!empty($USER->ignoresesskey)) {
232 return true;
233 }
234
7228f796 235 if (empty($sesskey)) {
236 $sesskey = required_param('sesskey'); // Check script parameters
237 }
238
239 if (!isset($USER->sesskey)) {
240 return false;
241 }
242
243 return ($USER->sesskey === $sesskey);
244}
245
246
247/**
248 * Ensure that a variable is set
249 *
250 * If $var is undefined throw an error, otherwise return $var.
251 * This function will soon be made obsolete by {@link required_param()}
7cf1c7bd 252 *
7228f796 253 * @param mixed $var the variable which may be unset
254 * @param mixed $default the value to return if $var is unset
7cf1c7bd 255 */
9fa49e22 256function require_variable($var) {
9fa49e22 257 if (! isset($var)) {
b0ccd3fb 258 error('A required parameter was missing');
6b174680 259 }
260}
261
7cf1c7bd 262
263/**
264 * Ensure that a variable is set
265 *
266 * If $var is undefined set it (by reference), otherwise return $var.
7228f796 267 * This function will soon be made obsolete by {@link optional_param()}
7cf1c7bd 268 *
269 * @param mixed $var the variable which may be unset
270 * @param mixed $default the value to return if $var is unset
271 */
9fa49e22 272function optional_variable(&$var, $default=0) {
9fa49e22 273 if (! isset($var)) {
274 $var = $default;
6b174680 275 }
276}
277
7cf1c7bd 278/**
279 * Set a key in global configuration
280 *
89dcb99d 281 * Set a key/value pair in both this session's {@link $CFG} global variable
7cf1c7bd 282 * and in the 'config' database table for future sessions.
283 *
284 * @param string $name the key to set
285 * @param string $value the value to set
286 * @uses $CFG
287 * @return bool
288 */
9fa49e22 289function set_config($name, $value) {
290/// No need for get_config because they are usually always available in $CFG
70812e39 291
42282810 292 global $CFG;
293
7cf1c7bd 294
42282810 295 $CFG->$name = $value; // So it's defined for this invocation at least
dfc9ba9b 296
b0ccd3fb 297 if (get_field('config', 'name', 'name', $name)) {
298 return set_field('config', 'value', $value, 'name', $name);
d897cae4 299 } else {
9fa49e22 300 $config->name = $name;
301 $config->value = $value;
b0ccd3fb 302 return insert_record('config', $config);
39917a09 303 }
39917a09 304}
305
7cf1c7bd 306/**
307 * Refresh current $USER session global variable with all their current preferences.
308 * @uses $USER
309 */
70812e39 310function reload_user_preferences() {
70812e39 311
312 global $USER;
313
070e2616 314 if(empty($USER) || empty($USER->id)) {
315 return false;
316 }
317
d8ba183c 318 unset($USER->preference);
70812e39 319
320 if ($preferences = get_records('user_preferences', 'userid', $USER->id)) {
321 foreach ($preferences as $preference) {
322 $USER->preference[$preference->name] = $preference->value;
323 }
4586d60c 324 } else {
325 //return empty preference array to hold new values
326 $USER->preference = array();
c6d15803 327 }
70812e39 328}
329
7cf1c7bd 330/**
331 * Sets a preference for the current user
332 * Optionally, can set a preference for a different user object
333 * @uses $USER
334 * @todo Add a better description and include usage examples.
335 * @param string $name The key to set as preference for the specified user
336 * @param string $value The value to set forthe $name key in the specified user's record
c6d15803 337 * @param int $userid A moodle user ID
7cf1c7bd 338 * @todo Add inline links to $USER and user functions in above line.
339 * @return boolean
340 */
13af52a6 341function set_user_preference($name, $value, $otheruser=NULL) {
70812e39 342
343 global $USER;
344
13af52a6 345 if (empty($otheruser)){
346 if (!empty($USER) && !empty($USER->id)) {
070e2616 347 $userid = $USER->id;
13af52a6 348 } else {
070e2616 349 return false;
350 }
13af52a6 351 } else {
352 $userid = $otheruser;
d35757eb 353 }
354
70812e39 355 if (empty($name)) {
356 return false;
357 }
358
a3f1f815 359 if ($preference = get_record('user_preferences', 'userid', $userid, 'name', $name)) {
b0ccd3fb 360 if (set_field('user_preferences', 'value', $value, 'id', $preference->id)) {
13af52a6 361 if (empty($otheruser) and !empty($USER)) {
070e2616 362 $USER->preference[$name] = $value;
363 }
066af654 364 return true;
365 } else {
366 return false;
367 }
70812e39 368
369 } else {
a3f1f815 370 $preference->userid = $userid;
70812e39 371 $preference->name = $name;
372 $preference->value = (string)$value;
066af654 373 if (insert_record('user_preferences', $preference)) {
13af52a6 374 if (empty($otheruser) and !empty($USER)) {
070e2616 375 $USER->preference[$name] = $value;
376 }
70812e39 377 return true;
378 } else {
379 return false;
380 }
381 }
382}
383
6eb3e776 384/**
385 * Unsets a preference completely by deleting it from the database
386 * Optionally, can set a preference for a different user id
387 * @uses $USER
388 * @param string $name The key to unset as preference for the specified user
c6d15803 389 * @param int $userid A moodle user ID
6eb3e776 390 * @return boolean
391 */
392function unset_user_preference($name, $userid=NULL) {
393
394 global $USER;
395
361855e6 396 if (empty($userid)){
070e2616 397 if(!empty($USER) && !empty($USER->id)) {
398 $userid = $USER->id;
399 }
400 else {
401 return false;
402 }
6eb3e776 403 }
404
405 return delete_records('user_preferences', 'userid', $userid, 'name', $name);
406}
407
408
7cf1c7bd 409/**
410 * Sets a whole array of preferences for the current user
411 * @param array $prefarray An array of key/value pairs to be set
c6d15803 412 * @param int $userid A moodle user ID
7cf1c7bd 413 * @return boolean
414 */
a3f1f815 415function set_user_preferences($prefarray, $userid=NULL) {
416
417 global $USER;
70812e39 418
419 if (!is_array($prefarray) or empty($prefarray)) {
420 return false;
421 }
422
361855e6 423 if (empty($userid)){
070e2616 424 if(!empty($USER) && !empty($USER->id)) {
425 $userid = $USER->id;
426 }
427 else {
428 return false;
429 }
a3f1f815 430 }
431
70812e39 432 $return = true;
433 foreach ($prefarray as $name => $value) {
070e2616 434 // The order is important; if the test for return is done first, then
435 // if one function call fails all the remaining ones will be "optimized away"
a3f1f815 436 $return = set_user_preference($name, $value, $userid) and $return;
70812e39 437 }
438 return $return;
439}
440
7cf1c7bd 441/**
442 * If no arguments are supplied this function will return
361855e6 443 * all of the current user preferences as an array.
7cf1c7bd 444 * If a name is specified then this function
445 * attempts to return that particular preference value. If
446 * none is found, then the optional value $default is returned,
447 * otherwise NULL.
448 * @param string $name Name of the key to use in finding a preference value
449 * @param string $default Value to be returned if the $name key is not set in the user preferences
c6d15803 450 * @param int $userid A moodle user ID
7cf1c7bd 451 * @uses $USER
452 * @return string
453 */
a3f1f815 454function get_user_preferences($name=NULL, $default=NULL, $userid=NULL) {
70812e39 455
456 global $USER;
457
a3f1f815 458 if (empty($userid)) { // assume current user
459 if (empty($USER->preference)) {
460 return $default; // Default value (or NULL)
461 }
462 if (empty($name)) {
463 return $USER->preference; // Whole array
464 }
465 if (!isset($USER->preference[$name])) {
466 return $default; // Default value (or NULL)
467 }
468 return $USER->preference[$name]; // The single value
469
470 } else {
471 $preference = get_records_menu('user_preferences', 'userid', $userid, 'name', 'name,value');
472
473 if (empty($name)) {
474 return $preference;
475 }
476 if (!isset($preference[$name])) {
477 return $default; // Default value (or NULL)
478 }
479 return $preference[$name]; // The single value
70812e39 480 }
70812e39 481}
482
483
9fa49e22 484/// FUNCTIONS FOR HANDLING TIME ////////////////////////////////////////////
39917a09 485
7cf1c7bd 486/**
c6d15803 487 * Given date parts in user time produce a GMT timestamp.
7cf1c7bd 488 *
c6d15803 489 * @param int $year The year part to create timestamp of.
490 * @param int $month The month part to create timestamp of.
491 * @param int $day The day part to create timestamp of.
492 * @param int $hour The hour part to create timestamp of.
493 * @param int $minute The minute part to create timestamp of.
494 * @param int $second The second part to create timestamp of.
495 * @param int $timezone ?
496 * @return ?
7cf1c7bd 497 * @todo Finish documenting this function
498 */
9f1f6daf 499function make_timestamp($year, $month=1, $day=1, $hour=0, $minute=0, $second=0, $timezone=99, $applydst=true) {
39917a09 500
f30fe8d0 501 $timezone = get_user_timezone($timezone);
94e34118 502
503 if (abs($timezone) > 13) {
9f1f6daf 504 $time = mktime((int)$hour,(int)$minute,(int)$second,(int)$month,(int)$day,(int)$year, 0);
03c17ddf 505 } else {
86f092d2 506 $time = gmmktime((int)$hour,(int)$minute,(int)$second,(int)$month,(int)$day,(int)$year, 0);
9f1f6daf 507 $time = usertime($time, $timezone); // This is GMT
03c17ddf 508 }
9f1f6daf 509
510 if(!$applydst) {
511 return $time;
512 }
513
514 return $time;
515
516 /*
517 // WARNING: BUG: TODO: This is buggy, but it will do for testing purposes
518 if(($dstid = get_user_preferences('calendar_dstpreset')) !== NULL) {
519 $preset = get_record('dst_preset', 'id', $dstid);
520 if($time > $preset->last_change && $time < $preset->next_change) {
521 return $time;
522 }
523
524 // We need to find out what's going on...
525 $nowuserdate = usergetdate($time);
526
527 $changes = calendar_dst_changes_for_year($year, $preset);
528 if($time < $changes['activate'] || $time > $changes['deactivate']) {
529 // DST will be off at that time
530 if($preset->current_offset != 0) {
531 print_object('Uncompensated time was:');
532 print_object(usergetdate($time));
533 $time += $preset->apply_offset * 60;
534 print_object('Compensated time is:');
535 print_object(usergetdate($time));
536 }
537 }
538 else {
539 // DST will be on at that time
540 if($preset->current_offset == 0) {
541 print_object('Uncompensated time was:');
542 print_object(usergetdate($time));
543 $time -= $preset->apply_offset * 60;
544 print_object('Compensated time is:');
545 print_object(usergetdate($time));
546 }
547 }
548
549 return $time;
550 }
551 */
39917a09 552}
553
7cf1c7bd 554/**
555 * Given an amount of time in seconds, returns string
556 * formatted nicely as months, days, hours etc as needed
557 *
2f87145b 558 * @uses MINSECS
559 * @uses HOURSECS
560 * @uses DAYSECS
c6d15803 561 * @param int $totalsecs ?
562 * @param array $str ?
89dcb99d 563 * @return string
7cf1c7bd 564 * @todo Finish documenting this function
565 */
566 function format_time($totalsecs, $str=NULL) {
c7e3ac2a 567
6b174680 568 $totalsecs = abs($totalsecs);
c7e3ac2a 569
8dbed6be 570 if (!$str) { // Create the str structure the slow way
b0ccd3fb 571 $str->day = get_string('day');
572 $str->days = get_string('days');
573 $str->hour = get_string('hour');
574 $str->hours = get_string('hours');
575 $str->min = get_string('min');
576 $str->mins = get_string('mins');
577 $str->sec = get_string('sec');
578 $str->secs = get_string('secs');
8dbed6be 579 }
580
7a5672c9 581 $days = floor($totalsecs/DAYSECS);
582 $remainder = $totalsecs - ($days*DAYSECS);
583 $hours = floor($remainder/HOURSECS);
584 $remainder = $remainder - ($hours*HOURSECS);
585 $mins = floor($remainder/MINSECS);
586 $secs = $remainder - ($mins*MINSECS);
8dbed6be 587
588 $ss = ($secs == 1) ? $str->sec : $str->secs;
589 $sm = ($mins == 1) ? $str->min : $str->mins;
590 $sh = ($hours == 1) ? $str->hour : $str->hours;
591 $sd = ($days == 1) ? $str->day : $str->days;
592
b0ccd3fb 593 $odays = '';
594 $ohours = '';
595 $omins = '';
596 $osecs = '';
9c9f7d77 597
b0ccd3fb 598 if ($days) $odays = $days .' '. $sd;
599 if ($hours) $ohours = $hours .' '. $sh;
600 if ($mins) $omins = $mins .' '. $sm;
601 if ($secs) $osecs = $secs .' '. $ss;
6b174680 602
b0ccd3fb 603 if ($days) return $odays .' '. $ohours;
604 if ($hours) return $ohours .' '. $omins;
605 if ($mins) return $omins .' '. $osecs;
606 if ($secs) return $osecs;
607 return get_string('now');
6b174680 608}
f9903ed0 609
7cf1c7bd 610/**
611 * Returns a formatted string that represents a date in user time
612 * <b>WARNING: note that the format is for strftime(), not date().</b>
613 * Because of a bug in most Windows time libraries, we can't use
614 * the nicer %e, so we have to use %d which has leading zeroes.
615 * A lot of the fuss in the function is just getting rid of these leading
616 * zeroes as efficiently as possible.
361855e6 617 *
8c3dba73 618 * If parameter fixday = true (default), then take off leading
7cf1c7bd 619 * zero from %d, else mantain it.
620 *
2f87145b 621 * @uses HOURSECS
c6d15803 622 * @param int $date ?
623 * @param string $format ?
624 * @param int $timezone ?
625 * @param boolean $fixday If true (default) then the leading
626 * zero from %d is removed. If false then the leading zero is mantained.
627 * @return string
7cf1c7bd 628 * @todo Finish documenting this function
629 */
b0ccd3fb 630function userdate($date, $format='', $timezone=99, $fixday = true) {
7a302afc 631
b0ccd3fb 632 if ($format == '') {
633 $format = get_string('strftimedaydatetime');
5fa51a39 634 }
035cdbff 635
b0ccd3fb 636 $formatnoday = str_replace('%d', 'DD', $format);
61ae5d36 637 if ($fixday) {
638 $fixday = ($formatnoday != $format);
639 }
dcde9f02 640
f30fe8d0 641 $timezone = get_user_timezone($timezone);
90207a06 642
0431bd7c 643 if (abs($timezone) > 13) {
035cdbff 644 if ($fixday) {
645 $datestring = strftime($formatnoday, $date);
b0ccd3fb 646 $daystring = str_replace(' 0', '', strftime(" %d", $date));
647 $datestring = str_replace('DD', $daystring, $datestring);
035cdbff 648 } else {
649 $datestring = strftime($format, $date);
650 }
bea7a51e 651 } else {
7a5672c9 652 $date = $date + (int)($timezone * HOURSECS);
035cdbff 653 if ($fixday) {
70d4cf82 654 $datestring = gmstrftime($formatnoday, $date);
b0ccd3fb 655 $daystring = str_replace(' 0', '', gmstrftime(" %d", $date));
656 $datestring = str_replace('DD', $daystring, $datestring);
035cdbff 657 } else {
70d4cf82 658 $datestring = gmstrftime($format, $date);
035cdbff 659 }
873960de 660 }
bea7a51e 661
035cdbff 662 return $datestring;
873960de 663}
664
7cf1c7bd 665/**
361855e6 666 * Given a $date timestamp in GMT (seconds since epoch),
c6d15803 667 * returns an array that represents the date in user time
7cf1c7bd 668 *
2f87145b 669 * @uses HOURSECS
c6d15803 670 * @param int $date Timestamp in GMT
671 * @param int $timezone ?
672 * @return array An array that represents the date in user time
7cf1c7bd 673 * @todo Finish documenting this function
674 */
5fa51a39 675function usergetdate($date, $timezone=99) {
6b174680 676
f30fe8d0 677 $timezone = get_user_timezone($timezone);
a36166d3 678
0431bd7c 679 if (abs($timezone) > 13) {
873960de 680 return getdate($date);
681 }
d2d6171f 682 //There is no gmgetdate so I have to fake it...
7a5672c9 683 $date = $date + (int)($timezone * HOURSECS);
9f1f6daf 684
685 // This is independent of the server's TZ settings,
686 // unlike gmstrftime. It's also a bit faster this way.
687 list(
688 $getdate['seconds'],
689 $getdate['minutes'],
690 $getdate['hours'],
691 $getdate['mday'],
692 $getdate['mon'],
693 $getdate['year'],
694 $getdate['wday'],
695 $getdate['yday'],
696 $getdate['weekday'],
697 $getdate['month']
698 ) = explode(' ', gmdate('s i H d m Y w z l F', $date));
699
d2d6171f 700 return $getdate;
d552ead0 701}
702
7cf1c7bd 703/**
704 * Given a GMT timestamp (seconds since epoch), offsets it by
705 * the timezone. eg 3pm in India is 3pm GMT - 7 * 3600 seconds
706 *
2f87145b 707 * @uses HOURSECS
c6d15803 708 * @param int $date Timestamp in GMT
709 * @param int $timezone ?
710 * @return int
7cf1c7bd 711 * @todo Finish documenting this function
712 */
d552ead0 713function usertime($date, $timezone=99) {
a36166d3 714
f30fe8d0 715 $timezone = get_user_timezone($timezone);
0431bd7c 716 if (abs($timezone) > 13) {
d552ead0 717 return $date;
718 }
7a5672c9 719 return $date - (int)($timezone * HOURSECS);
d552ead0 720}
721
8c3dba73 722/**
723 * Given a time, return the GMT timestamp of the most recent midnight
724 * for the current user.
725 *
c6d15803 726 * @param int $date Timestamp in GMT
727 * @param int $timezone ?
728 * @return ?
729 * @todo Finish documenting this function. Is timezone an int or float?
8c3dba73 730 */
edf7fe8c 731function usergetmidnight($date, $timezone=99) {
edf7fe8c 732
f30fe8d0 733 $timezone = get_user_timezone($timezone);
edf7fe8c 734 $userdate = usergetdate($date, $timezone);
4606d9bb 735
0431bd7c 736 if (abs($timezone) > 13) {
b0ccd3fb 737 return mktime(0, 0, 0, $userdate['mon'], $userdate['mday'], $userdate['year']);
4606d9bb 738 }
739
b0ccd3fb 740 $timemidnight = gmmktime (0, 0, 0, $userdate['mon'], $userdate['mday'], $userdate['year']);
edf7fe8c 741 return usertime($timemidnight, $timezone); // Time of midnight of this user's day, in GMT
742
743}
744
7cf1c7bd 745/**
746 * Returns a string that prints the user's timezone
747 *
748 * @param float $timezone The user's timezone
749 * @return string
c6d15803 750 * @todo is $timezone an int or a float?
7cf1c7bd 751 */
d552ead0 752function usertimezone($timezone=99) {
d552ead0 753
f30fe8d0 754 $timezone = get_user_timezone($timezone);
755
0431bd7c 756 if (abs($timezone) > 13) {
b0ccd3fb 757 return 'server time';
d552ead0 758 }
759 if (abs($timezone) < 0.5) {
b0ccd3fb 760 return 'GMT';
d552ead0 761 }
762 if ($timezone > 0) {
b0ccd3fb 763 return 'GMT+'. $timezone;
d552ead0 764 } else {
b0ccd3fb 765 return 'GMT'. $timezone;
d552ead0 766 }
f9903ed0 767}
768
7cf1c7bd 769/**
770 * Returns a float which represents the user's timezone difference from GMT in hours
771 * Checks various settings and picks the most dominant of those which have a value
772 *
7cf1c7bd 773 * @uses $CFG
774 * @uses $USER
c6d15803 775 * @param int $tz The user's timezone
776 * @return int
777 * @todo is $tz an int or a float?
7cf1c7bd 778 */
f30fe8d0 779function get_user_timezone($tz = 99) {
f30fe8d0 780
781 // Variables declared explicitly global here so that if we add
782 // something later we won't forget to global it...
783 $timezones = array(
784 isset($GLOBALS['USER']->timezone) ? $GLOBALS['USER']->timezone : 99,
785 isset($GLOBALS['CFG']->timezone) ? $GLOBALS['CFG']->timezone : 99,
786 );
787 while($tz == 99 && $next = each($timezones)) {
788 $tz = (float)$next['value'];
789 }
790
791 return $tz;
792}
f9903ed0 793
9fa49e22 794/// USER AUTHENTICATION AND LOGIN ////////////////////////////////////////
f9903ed0 795
7cf1c7bd 796/**
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.
800 * $autologinguest determines whether visitors should automatically be
89dcb99d 801 * logged in as guests provide {@link $CFG}->autologinguests is set to 1
7cf1c7bd 802 *
7cf1c7bd 803 * @uses $CFG
c6d15803 804 * @uses $SESSION
7cf1c7bd 805 * @uses $USER
806 * @uses $FULLME
c6d15803 807 * @uses SITEID
7cf1c7bd 808 * @uses $MoodleSession
c6d15803 809 * @param int $courseid The course in question
810 * @param boolean $autologinguest ?
7cf1c7bd 811 * @todo Finish documenting this function
812 */
8e8d0524 813function require_login($courseid=0, $autologinguest=true) {
f9903ed0 814
73047f2f 815 global $CFG, $SESSION, $USER, $FULLME, $MoodleSession;
d8ba183c 816
da5c172a 817 // First check that the user is logged in to the site.
c21c671d 818 if (! (isset($USER->loggedin) and $USER->confirmed and ($USER->site == $CFG->wwwroot)) ) { // They're not
f9903ed0 819 $SESSION->wantsurl = $FULLME;
b0ccd3fb 820 if (!empty($_SERVER['HTTP_REFERER'])) {
821 $SESSION->fromurl = $_SERVER['HTTP_REFERER'];
9f44d972 822 }
c21c671d 823 $USER = NULL;
8e8d0524 824 if ($autologinguest and $CFG->autologinguests and $courseid and get_field('course','guest','id',$courseid)) {
825 $loginguest = '?loginguest=true';
826 } else {
827 $loginguest = '';
a2ebe6a5 828 }
8a33e371 829 if (empty($CFG->loginhttps)) {
b0ccd3fb 830 redirect($CFG->wwwroot .'/login/index.php'. $loginguest);
8a33e371 831 } else {
b0ccd3fb 832 $wwwroot = str_replace('http','https', $CFG->wwwroot);
833 redirect($wwwroot .'/login/index.php'. $loginguest);
8a33e371 834 }
f9903ed0 835 die;
f9903ed0 836 }
808a3baa 837
d35757eb 838 // check whether the user should be changing password
027a1604 839 // reload_user_preferences(); // Why is this necessary? Seems wasteful. - MD
a3f1f815 840 if (!empty($USER->preference['auth_forcepasswordchange'])){
d35757eb 841 if (is_internal_auth() || $CFG->{'auth_'.$USER->auth.'_stdchangepassword'}){
b0ccd3fb 842 redirect($CFG->wwwroot .'/login/change_password.php');
d35757eb 843 } elseif($CFG->changepassword) {
844 redirect($CFG->changepassword);
845 } else {
361855e6 846 error('You cannot proceed without changing your password.
d35757eb 847 However there is no available page for changing it.
b0ccd3fb 848 Please contact your Moodle Administrator.');
d35757eb 849 }
850 }
851
808a3baa 852 // Check that the user account is properly set up
853 if (user_not_fully_set_up($USER)) {
b0ccd3fb 854 redirect($CFG->wwwroot .'/user/edit.php?id='. $USER->id .'&amp;course='. SITEID);
808a3baa 855 die;
856 }
d8ba183c 857
366dfa60 858 // Make sure current IP matches the one for this session (if required)
361855e6 859 if (!empty($CFG->tracksessionip)) {
366dfa60 860 if ($USER->sessionIP != md5(getremoteaddr())) {
861 error(get_string('sessionipnomatch', 'error'));
862 }
863 }
6d8f47d6 864
865 // Make sure the USER has a sesskey set up. Used for checking script parameters.
866 if (empty($USER->sesskey)) {
867 $USER->sesskey = random_string(10);
868 }
366dfa60 869
027a1604 870 // Check that the user has agreed to a site policy if there is one
871 if (!empty($CFG->sitepolicy)) {
872 if (!$USER->policyagreed) {
957b5198 873 $SESSION->wantsurl = $FULLME;
027a1604 874 redirect($CFG->wwwroot .'/user/policy.php');
875 die;
876 }
877 }
878
da5c172a 879 // Next, check if the user can be in a particular course
880 if ($courseid) {
361855e6 881 if ($courseid == SITEID) {
e3512050 882 return; // Anyone can be in the site course
883 }
9c9f7d77 884 if (!empty($USER->student[$courseid]) or !empty($USER->teacher[$courseid]) or !empty($USER->admin)) {
cb909d74 885 if (isset($USER->realuser)) { // Make sure the REAL person can also access this course
886 if (!isteacher($courseid, $USER->realuser)) {
887 print_header();
b0ccd3fb 888 notice(get_string('studentnotallowed', '', fullname($USER, true)), $CFG->wwwroot .'/');
cb909d74 889 }
3ce2f1e0 890 }
da5c172a 891 return; // user is a member of this course.
892 }
b0ccd3fb 893 if (! $course = get_record('course', 'id', $courseid)) {
894 error('That course doesn\'t exist');
da5c172a 895 }
1efa27fd 896 if (!$course->visible) {
897 print_header();
b0ccd3fb 898 notice(get_string('studentnotallowed', '', fullname($USER, true)), $CFG->wwwroot .'/');
1efa27fd 899 }
b0ccd3fb 900 if ($USER->username == 'guest') {
7363ff91 901 switch ($course->guest) {
902 case 0: // Guests not allowed
903 print_header();
b0ccd3fb 904 notice(get_string('guestsnotallowed', '', $course->fullname));
7363ff91 905 break;
906 case 1: // Guests allowed
7363ff91 907 return;
908 case 2: // Guests allowed with key (drop through)
909 break;
910 }
da5c172a 911 }
f9903ed0 912
7363ff91 913 // Currently not enrolled in the course, so see if they want to enrol
da5c172a 914 $SESSION->wantsurl = $FULLME;
b0ccd3fb 915 redirect($CFG->wwwroot .'/course/enrol.php?id='. $courseid);
da5c172a 916 die;
917 }
f9903ed0 918}
919
7cf1c7bd 920/**
921 * This is a weaker version of {@link require_login()} which only requires login
922 * when called from within a course rather than the site page, unless
923 * the forcelogin option is turned on.
924 *
925 * @uses $CFG
c6d15803 926 * @param int $courseid The course in question
927 * @param boolean $autologinguest ?
7cf1c7bd 928 * @todo Finish documenting this function
929 */
f950af3c 930function require_course_login($course, $autologinguest=true) {
f950af3c 931 global $CFG;
932 if ($CFG->forcelogin) {
933 require_login();
934 }
935 if ($course->category) {
936 require_login($course->id, $autologinguest);
937 }
938}
939
7cf1c7bd 940/**
941 * Modify the user table by setting the currently logged in user's
942 * last login to now.
943 *
944 * @uses $USER
945 * @return boolean
946 */
1d881d92 947function update_user_login_times() {
948 global $USER;
949
950 $USER->lastlogin = $user->lastlogin = $USER->currentlogin;
2a2f5f11 951 $USER->currentlogin = $user->lastaccess = $user->currentlogin = time();
1d881d92 952
953 $user->id = $USER->id;
954
b0ccd3fb 955 return update_record('user', $user);
1d881d92 956}
957
7cf1c7bd 958/**
959 * Determines if a user has completed setting up their account.
960 *
89dcb99d 961 * @param user $user A {@link $USER} object to test for the existance of a valid name and email
7cf1c7bd 962 * @return boolean
963 */
808a3baa 964function user_not_fully_set_up($user) {
b0ccd3fb 965 return ($user->username != 'guest' and (empty($user->firstname) or empty($user->lastname) or empty($user->email)));
808a3baa 966}
f9903ed0 967
7cf1c7bd 968/**
969 * Keeps track of login attempts
970 *
971 * @uses $SESSION
972 */
f9903ed0 973function update_login_count() {
9fa49e22 974
f9903ed0 975 global $SESSION;
976
977 $max_logins = 10;
978
979 if (empty($SESSION->logincount)) {
980 $SESSION->logincount = 1;
981 } else {
982 $SESSION->logincount++;
983 }
984
985 if ($SESSION->logincount > $max_logins) {
9fa49e22 986 unset($SESSION->wantsurl);
b0ccd3fb 987 error(get_string('errortoomanylogins'));
d578afc8 988 }
989}
990
7cf1c7bd 991/**
992 * Resets login attempts
993 *
994 * @uses $SESSION
995 */
9fa49e22 996function reset_login_count() {
9fa49e22 997 global $SESSION;
d578afc8 998
9fa49e22 999 $SESSION->logincount = 0;
d578afc8 1000}
1001
7cf1c7bd 1002/**
1003 * check_for_restricted_user
1004 *
89dcb99d 1005 * @uses $CFG
1006 * @uses $USER
1007 * @param string $username ?
1008 * @param string $redirect ?
7cf1c7bd 1009 * @todo Finish documenting this function
1010 */
b0ccd3fb 1011function check_for_restricted_user($username=NULL, $redirect='') {
cb98d312 1012 global $CFG, $USER;
1013
1014 if (!$username) {
1015 if (!empty($USER->username)) {
1016 $username = $USER->username;
1017 } else {
1018 return false;
1019 }
1020 }
1021
1022 if (!empty($CFG->restrictusers)) {
1023 $names = explode(',', $CFG->restrictusers);
1024 if (in_array($username, $names)) {
b0ccd3fb 1025 error(get_string('restricteduser', 'error', fullname($USER)), $redirect);
cb98d312 1026 }
1027 }
1028}
1029
7cf1c7bd 1030/**
1031 * Determines if a user an admin
1032 *
1033 * @uses $USER
c6d15803 1034 * @param int $userid The id of the user as is found in the 'user' table
89dcb99d 1035 * @staticvar array $admin ?
1036 * @staticvar array $nonadmins ?
7cf1c7bd 1037 * @return boolean
89dcb99d 1038 * @todo Complete documentation for this function
7cf1c7bd 1039 */
581d7b49 1040function isadmin($userid=0) {
f9903ed0 1041 global $USER;
aa095969 1042 static $admins = array();
1043 static $nonadmins = array();
f9903ed0 1044
581d7b49 1045 if (!$userid){
1046 if (empty($USER->id)) {
1047 return false;
1048 }
1049 $userid = $USER->id;
9bd2c874 1050 }
1051
581d7b49 1052 if (in_array($userid, $admins)) {
aa095969 1053 return true;
581d7b49 1054 } else if (in_array($userid, $nonadmins)) {
aa095969 1055 return false;
b0ccd3fb 1056 } else if (record_exists('user_admins', 'userid', $userid)){
581d7b49 1057 $admins[] = $userid;
aa095969 1058 return true;
1059 } else {
581d7b49 1060 $nonadmins[] = $userid;
aa095969 1061 return false;
f9903ed0 1062 }
f9903ed0 1063}
1064
7cf1c7bd 1065/**
1066 * Determines if a user is a teacher or an admin
1067 *
1068 * @uses $USER
c6d15803 1069 * @param int $courseid The id of the course that is being viewed, if any
1070 * @param int $userid The id of the user that is being tested against. Set this to 0 if you would just like to test against the currently logged in user.
7cf1c7bd 1071 * @param boolean $includeadmin If true this function will return true when it encounters an admin user.
1072 * @return boolean
1073 * @todo Finish documenting this function
1074 */
9d3c795c 1075function isteacher($courseid=0, $userid=0, $includeadmin=true) {
f9903ed0 1076 global $USER;
1077
9788367b 1078 if ($includeadmin and isadmin($userid)) { // admins can do anything the teacher can
d115a57f 1079 return true;
1080 }
1081
f9903ed0 1082 if (!$userid) {
71f9abf9 1083 if ($courseid) {
1084 return !empty($USER->teacher[$courseid]);
1085 }
1086 if (!isset($USER->id)) {
1087 return false;
1088 }
1089 $userid = $USER->id;
f9903ed0 1090 }
1091
9d3c795c 1092 if (!$courseid) {
b0ccd3fb 1093 return record_exists('user_teachers', 'userid', $userid);
9d3c795c 1094 }
1095
b0ccd3fb 1096 return record_exists('user_teachers', 'userid', $userid, 'course', $courseid);
f9903ed0 1097}
1098
7cf1c7bd 1099/**
1100 * Determines if a user is allowed to edit a given course
1101 *
1102 * @uses $USER
c6d15803 1103 * @param int $courseid The id of the course that is being edited
1104 * @param int $userid The id of the user that is being tested against. Set this to 0 if you would just like to test against the currently logged in user.
7cf1c7bd 1105 * @return boolean
1106 */
73047f2f 1107function isteacheredit($courseid, $userid=0) {
73047f2f 1108 global $USER;
1109
d8ba183c 1110 if (isadmin($userid)) { // admins can do anything
73047f2f 1111 return true;
1112 }
1113
1114 if (!$userid) {
1115 return !empty($USER->teacheredit[$courseid]);
1116 }
1117
b0ccd3fb 1118 return get_field('user_teachers', 'editall', 'userid', $userid, 'course', $courseid);
73047f2f 1119}
1120
7cf1c7bd 1121/**
1122 * Determines if a user can create new courses
1123 *
1124 * @uses $USER
361855e6 1125 * @param int $userid The user being tested. You can set this to 0 or leave it blank to test the currently logged in user.
7cf1c7bd 1126 * @return boolean
1127 */
1924074c 1128function iscreator ($userid=0) {
1924074c 1129 global $USER;
8a205861 1130 if (empty($USER->id)) {
1131 return false;
1132 }
1924074c 1133 if (isadmin($userid)) { // admins can do anything
1134 return true;
1135 }
8a205861 1136 if (empty($userid)) {
b0ccd3fb 1137 return record_exists('user_coursecreators', 'userid', $USER->id);
1924074c 1138 }
1139
b0ccd3fb 1140 return record_exists('user_coursecreators', 'userid', $userid);
1924074c 1141}
1142
7cf1c7bd 1143/**
1144 * Determines if a user is a student in the specified course
361855e6 1145 *
7cf1c7bd 1146 * If the course id specifies the site then the function determines
1147 * if the user is a confirmed and valid user of this site.
1148 *
1149 * @uses $USER
1150 * @uses $CFG
c6d15803 1151 * @uses SITEID
1152 * @param int $courseid The id of the course being tested
361855e6 1153 * @param int $userid The user being tested. You can set this to 0 or leave it blank to test the currently logged in user.
7cf1c7bd 1154 * @return boolean
1155 */
8a9e3fd7 1156function isstudent($courseid, $userid=0) {
71f9abf9 1157 global $USER, $CFG;
f9903ed0 1158
2700d113 1159 if (empty($USER->id) and !$userid) {
7064e18f 1160 return false;
1161 }
1162
222ac91b 1163 if ($courseid == SITEID) {
2cc72e84 1164 if (!$userid) {
1165 $userid = $USER->id;
1166 }
1167 if (isguest($userid)) {
1168 return false;
1169 }
71f9abf9 1170 // a site teacher can never be a site student
1171 if (isteacher($courseid, $userid)) {
1172 return false;
1173 }
2700d113 1174 if ($CFG->allusersaresitestudents) {
1175 return record_exists('user', 'id', $userid);
1176 } else {
1177 return (record_exists('user_students', 'userid', $userid)
71f9abf9 1178 or record_exists('user_teachers', 'userid', $userid));
2700d113 1179 }
8f0cd6ef 1180 }
2cc72e84 1181
f9903ed0 1182 if (!$userid) {
346b1a24 1183 return !empty($USER->student[$courseid]);
f9903ed0 1184 }
1185
ebc3bd2b 1186 // $timenow = time(); // todo: add time check below
f9903ed0 1187
b0ccd3fb 1188 return record_exists('user_students', 'userid', $userid, 'course', $courseid);
f9903ed0 1189}
1190
7cf1c7bd 1191/**
1192 * Determines if the specified user is logged in as guest.
1193 *
1194 * @uses $USER
361855e6 1195 * @param int $userid The user being tested. You can set this to 0 or leave it blank to test the currently logged in user.
7cf1c7bd 1196 * @return boolean
1197 */
da5c172a 1198function isguest($userid=0) {
1199 global $USER;
1200
1201 if (!$userid) {
b35e8568 1202 if (empty($USER->username)) {
1203 return false;
1204 }
b0ccd3fb 1205 return ($USER->username == 'guest');
da5c172a 1206 }
1207
b0ccd3fb 1208 return record_exists('user', 'id', $userid, 'username', 'guest');
da5c172a 1209}
1210
7cf1c7bd 1211/**
1212 * Determines if the currently logged in user is in editing mode
1213 *
1214 * @uses $USER
c6d15803 1215 * @param int $courseid The id of the course being tested
89dcb99d 1216 * @param user $user A {@link $USER} object. If null then the currently logged in user is used.
7cf1c7bd 1217 * @return boolean
1218 */
2c309dc2 1219function isediting($courseid, $user=NULL) {
1220 global $USER;
1221 if (!$user){
1222 $user = $USER;
1223 }
9c9f7d77 1224 if (empty($user->editing)) {
1225 return false;
1226 }
2c309dc2 1227 return ($user->editing and isteacher($courseid, $user->id));
1228}
1229
7cf1c7bd 1230/**
1231 * Determines if the logged in user is currently moving an activity
1232 *
1233 * @uses $USER
c6d15803 1234 * @param int $courseid The id of the course being tested
7cf1c7bd 1235 * @return boolean
1236 */
7977cffd 1237function ismoving($courseid) {
7977cffd 1238 global $USER;
1239
1240 if (!empty($USER->activitycopy)) {
1241 return ($USER->activitycopycourse == $courseid);
1242 }
1243 return false;
1244}
1245
7cf1c7bd 1246/**
1247 * Given an object containing firstname and lastname
1248 * values, this function returns a string with the
1249 * full name of the person.
1250 * The result may depend on system settings
1251 * or language. 'override' will force both names
361855e6 1252 * to be used even if system settings specify one.
7cf1c7bd 1253 * @uses $CFG
1254 * @uses $SESSION
1255 * @param type description
1256 * @todo Finish documenting this function
1257 */
e2cd5065 1258function fullname($user, $override=false) {
b5cbb64d 1259
f374fb10 1260 global $CFG, $SESSION;
1261
6527c077 1262 if (!isset($user->firstname) and !isset($user->lastname)) {
1263 return '';
1264 }
1265
f374fb10 1266 if (!empty($SESSION->fullnamedisplay)) {
1267 $CFG->fullnamedisplay = $SESSION->fullnamedisplay;
1268 }
e2cd5065 1269
b5cbb64d 1270 if ($CFG->fullnamedisplay == 'firstname lastname') {
b0ccd3fb 1271 return $user->firstname .' '. $user->lastname;
b5cbb64d 1272
1273 } else if ($CFG->fullnamedisplay == 'lastname firstname') {
b0ccd3fb 1274 return $user->lastname .' '. $user->firstname;
e2cd5065 1275
b5cbb64d 1276 } else if ($CFG->fullnamedisplay == 'firstname') {
1277 if ($override) {
1278 return get_string('fullnamedisplay', '', $user);
1279 } else {
1280 return $user->firstname;
1281 }
1282 }
e2cd5065 1283
b5cbb64d 1284 return get_string('fullnamedisplay', '', $user);
e2cd5065 1285}
1286
7cf1c7bd 1287/**
1288 * Sets a moodle cookie with an encrypted string
1289 *
1290 * @uses $CFG
2f87145b 1291 * @uses DAYSECS
1292 * @uses HOURSECS
7cf1c7bd 1293 * @param string $thing The string to encrypt and place in a cookie
1294 */
f9903ed0 1295function set_moodle_cookie($thing) {
7185e073 1296 global $CFG;
482b6e6e 1297
1298 $cookiename = 'MOODLEID_'.$CFG->sessioncookie;
f9903ed0 1299
1300 $days = 60;
7a5672c9 1301 $seconds = DAYSECS*$days;
f9903ed0 1302
7a5672c9 1303 setCookie($cookiename, '', time() - HOURSECS, '/');
b0ccd3fb 1304 setCookie($cookiename, rc4encrypt($thing), time()+$seconds, '/');
f9903ed0 1305}
1306
7cf1c7bd 1307/**
1308 * Gets a moodle cookie with an encrypted string
1309 *
1310 * @uses $CFG
1311 * @return string
1312 */
f9903ed0 1313function get_moodle_cookie() {
7185e073 1314 global $CFG;
1315
482b6e6e 1316 $cookiename = 'MOODLEID_'.$CFG->sessioncookie;
7185e073 1317
1079c8a8 1318 if (empty($_COOKIE[$cookiename])) {
b0ccd3fb 1319 return '';
1079c8a8 1320 } else {
1321 return rc4decrypt($_COOKIE[$cookiename]);
1322 }
f9903ed0 1323}
1324
7cf1c7bd 1325/**
1326 * Returns true if an internal authentication method is being used.
1327 * if method not specified then, global default is assumed
1328 *
1329 * @uses $CFG
1330 * @param string $auth Form of authentication required
1331 * @return boolean
1332 * @todo Outline auth types and provide code example
1333 */
39a5a35d 1334function is_internal_auth($auth='') {
ba7166c3 1335/// Returns true if an internal authentication method is being used.
a3f1f815 1336/// If auth not specified then global default is assumed
ba7166c3 1337
1338 global $CFG;
1339
a3f1f815 1340 if (empty($auth)) {
1341 $auth = $CFG->auth;
39a5a35d 1342 }
1343
a3f1f815 1344 return ($auth == "email" || $auth == "none" || $auth == "manual");
1345}
1346
8c3dba73 1347/**
1348 * Returns an array of user fields
1349 *
c6d15803 1350 * @uses $CFG
1351 * @uses $db
1352 * @return array User field/column names
8c3dba73 1353 * @todo Finish documenting this function
1354 */
a3f1f815 1355function get_user_fieldnames() {
a3f1f815 1356
1357 global $CFG, $db;
1358
1359 $fieldarray = $db->MetaColumnNames($CFG->prefix.'user');
1360 unset($fieldarray['ID']);
1361
1362 return $fieldarray;
ba7166c3 1363}
f9903ed0 1364
7cf1c7bd 1365/**
1366 * Creates a bare-bones user record
1367 *
1368 * @uses $CFG
7cf1c7bd 1369 * @param string $username New user's username to add to record
1370 * @param string $password New user's password to add to record
1371 * @param string $auth Form of authentication required
89dcb99d 1372 * @return user A {@link $USER} object
7cf1c7bd 1373 * @todo Outline auth types and provide code example
1374 */
71f9abf9 1375function create_user_record($username, $password, $auth='') {
366dfa60 1376 global $CFG;
71f9abf9 1377
1e22bc9c 1378 //just in case check text case
1379 $username = trim(moodle_strtolower($username));
71f9abf9 1380
3271b70f 1381 if (function_exists('auth_get_userinfo')) {
e858f9da 1382 if ($newinfo = auth_get_userinfo($username)) {
b36a8fc4 1383 $newinfo = truncate_userinfo($newinfo);
34daec9b 1384 foreach ($newinfo as $key => $value){
9f44d972 1385 $newuser->$key = addslashes(stripslashes($value)); // Just in case
e858f9da 1386 }
1387 }
1388 }
f9903ed0 1389
85a1d4c9 1390 if (!empty($newuser->email)) {
1391 if (email_is_not_allowed($newuser->email)) {
1392 unset($newuser->email);
1393 }
1394 }
1395
71f9abf9 1396 $newuser->auth = (empty($auth)) ? $CFG->auth : $auth;
faebaf0f 1397 $newuser->username = $username;
1398 $newuser->password = md5($password);
a0bac19d 1399 $newuser->lang = $CFG->lang;
faebaf0f 1400 $newuser->confirmed = 1;
59619427 1401 $newuser->lastIP = getremoteaddr();
faebaf0f 1402 $newuser->timemodified = time();
f9903ed0 1403
b0ccd3fb 1404 if (insert_record('user', $newuser)) {
1405 $user = get_user_info_from_db('username', $newuser->username);
d35757eb 1406 if($CFG->{'auth_'.$newuser->auth.'_forcechangepassword'}){
1407 set_user_preference('auth_forcepasswordchange', 1, $user);
1408 }
1409 return $user;
faebaf0f 1410 }
1411 return false;
1412}
1413
7cf1c7bd 1414/**
1415 * Will update a local user record from an external source
1416 *
1417 * @uses $CFG
1418 * @param string $username New user's username to add to record
89dcb99d 1419 * @return user A {@link $USER} object
7cf1c7bd 1420 */
d35757eb 1421function update_user_record($username) {
d35757eb 1422 global $CFG;
1423
1424 if (function_exists('auth_get_userinfo')) {
1425 $username = trim(moodle_strtolower($username)); /// just in case check text case
1426
1427 if ($newinfo = auth_get_userinfo($username)) {
1428 foreach ($newinfo as $key => $value){
1429 if (!empty($CFG->{'auth_user_' . $key. '_updatelocal'})) {
1430 $value = addslashes(stripslashes($value)); // Just in case
1431 set_field('user', $key, $value, 'username', $username);
1432 }
1433 }
1434 }
1435 }
b0ccd3fb 1436 return get_user_info_from_db('username', $username);
d35757eb 1437}
0609562b 1438
b36a8fc4 1439function truncate_userinfo($info) {
1440/// will truncate userinfo as it comes from auth_get_userinfo (from external auth)
1441/// which may have large fields
1442
1443 // define the limits
1444 $limit = array(
1445 'username' => 100,
1446 'idnumber' => 12,
1447 'firstname' => 20,
1448 'lastname' => 20,
1449 'email' => 100,
1450 'icq' => 15,
1451 'phone1' => 20,
1452 'phone2' => 20,
1453 'institution' => 40,
1454 'department' => 30,
1455 'address' => 70,
1456 'city' => 20,
1457 'country' => 2,
1458 'url' => 255,
1459 );
361855e6 1460
b36a8fc4 1461 // apply where needed
1462 foreach (array_keys($info) as $key) {
1463 if (!empty($limit[$key])) {
1464 $info[$key] = substr($info[$key],0, $limit[$key]);
361855e6 1465 }
b36a8fc4 1466 }
361855e6 1467
b36a8fc4 1468 return $info;
1469}
1470
7cf1c7bd 1471/**
1472 * Retrieve the guest user object
1473 *
1474 * @uses $CFG
89dcb99d 1475 * @return user A {@link $USER} object
7cf1c7bd 1476 */
0609562b 1477function guest_user() {
1478 global $CFG;
1479
b0ccd3fb 1480 if ($newuser = get_record('user', 'username', 'guest')) {
0609562b 1481 $newuser->loggedin = true;
1482 $newuser->confirmed = 1;
1483 $newuser->site = $CFG->wwwroot;
1484 $newuser->lang = $CFG->lang;
366dfa60 1485 $newuser->lastIP = getremoteaddr();
0609562b 1486 }
1487
1488 return $newuser;
1489}
1490
7cf1c7bd 1491/**
1492 * Given a username and password, this function looks them
1493 * up using the currently selected authentication mechanism,
1494 * and if the authentication is successful, it returns a
1495 * valid $user object from the 'user' table.
361855e6 1496 *
7cf1c7bd 1497 * Uses auth_ functions from the currently active auth module
1498 *
1499 * @uses $CFG
361855e6 1500 * @param string $username User's username
1501 * @param string $password User's password
89dcb99d 1502 * @return user|flase A {@link $USER} object or false if error
7cf1c7bd 1503 */
faebaf0f 1504function authenticate_user_login($username, $password) {
faebaf0f 1505
1506 global $CFG;
1507
466558e3 1508 $md5password = md5($password);
1509
27286aeb 1510 // First try to find the user in the database
466558e3 1511
b0ccd3fb 1512 $user = get_user_info_from_db('username', $username);
39a5a35d 1513
27286aeb 1514 // Sort out the authentication method we are using.
39a5a35d 1515
27286aeb 1516 if (empty($CFG->auth)) {
b0ccd3fb 1517 $CFG->auth = 'manual'; // Default authentication module
27286aeb 1518 }
39a5a35d 1519
27286aeb 1520 if (empty($user->auth)) { // For some reason it isn't set yet
1521 if (isadmin($user->id) or isguest($user->id)) {
71f9abf9 1522 $auth = 'manual'; // Always assume these guys are internal
27286aeb 1523 } else {
71f9abf9 1524 $auth = $CFG->auth; // Normal users default to site method
27286aeb 1525 }
d35757eb 1526 // update user record from external DB
1527 if ($user->auth != 'manual' && $user->auth != 'email') {
1528 $user = update_user_record($username);
1529 }
71f9abf9 1530 } else {
1531 $auth = $user->auth;
27286aeb 1532 }
8f0cd6ef 1533
ce791f88 1534 if (detect_munged_arguments($auth, 0)) { // For safety on the next require
1535 return false;
1536 }
1537
b0ccd3fb 1538 if (!file_exists($CFG->dirroot .'/auth/'. $auth .'/lib.php')) {
1539 $auth = 'manual'; // Can't find auth module, default to internal
466558e3 1540 }
1541
b0ccd3fb 1542 require_once($CFG->dirroot .'/auth/'. $auth .'/lib.php');
faebaf0f 1543
1544 if (auth_user_login($username, $password)) { // Successful authentication
71f9abf9 1545 if ($user) { // User already exists in database
1546 if (empty($user->auth)) { // For some reason auth isn't set yet
1547 set_field('user', 'auth', $auth, 'username', $username);
1548 }
92710226 1549 if ($md5password <> $user->password) { // Update local copy of password for reference
71f9abf9 1550 set_field('user', 'password', $md5password, 'username', $username);
faebaf0f 1551 }
366dfa60 1552 if (!is_internal_auth()) { // update user record from external DB
d35757eb 1553 $user = update_user_record($username);
1554 }
faebaf0f 1555 } else {
71f9abf9 1556 $user = create_user_record($username, $password, $auth);
faebaf0f 1557 }
89b54325 1558
e582b65e 1559 if (function_exists('auth_iscreator')) { // Check if the user is a creator
f894a791 1560 $useriscreator = auth_iscreator($username);
1561 if (!is_null($useriscreator)) {
1562 if ($useriscreator) {
1563 if (! record_exists('user_coursecreators', 'userid', $user->id)) {
1564 $cdata->userid = $user->id;
1565 if (! insert_record('user_coursecreators', $cdata)) {
1566 error('Cannot add user to course creators.');
1567 }
39a5a35d 1568 }
f894a791 1569 } else {
1570 if (record_exists('user_coursecreators', 'userid', $user->id)) {
1571 if (! delete_records('user_coursecreators', 'userid', $user->id)) {
1572 error('Cannot remove user from course creators.');
1573 }
39a5a35d 1574 }
1575 }
361855e6 1576 }
39a5a35d 1577 }
366dfa60 1578 $user->sessionIP = md5(getremoteaddr()); // Store the current IP in the session
e582b65e 1579 return $user;
9d3c795c 1580
e582b65e 1581 } else {
b0ccd3fb 1582 add_to_log(0, 'login', 'error', $_SERVER['HTTP_REFERER'], $username);
3af57507 1583 error_log('[client '.$_SERVER['REMOTE_ADDR']."]\t$CFG->wwwroot\tFailed Login:\t$username\t".$_SERVER['HTTP_USER_AGENT']);
e582b65e 1584 return false;
1585 }
f9903ed0 1586}
1587
7cf1c7bd 1588/**
1589 * Enrols (or re-enrols) a student in a given course
1590 *
c6d15803 1591 * @param int $courseid The id of the course that is being viewed
1592 * @param int $userid The id of the user that is being tested against. Set this to 0 if you would just like to test against the currently logged in user.
1593 * @param int $timestart ?
1594 * @param int $timeend ?
7cf1c7bd 1595 * @return boolean
1596 * @todo Finish documenting this function
1597 */
6e8ca983 1598function enrol_student($userid, $courseid, $timestart=0, $timeend=0, $enrol='manual') {
b40bc478 1599
75169b06 1600 global $CFG;
1601
b0ccd3fb 1602 if (!$course = get_record('course', 'id', $courseid)) { // Check course
3041b0f8 1603 return false;
4d312bbe 1604 }
b0ccd3fb 1605 if (!$user = get_record('user', 'id', $userid)) { // Check user
631cf796 1606 return false;
1607 }
b0ccd3fb 1608 if ($student = get_record('user_students', 'userid', $userid, 'course', $courseid)) {
631cf796 1609 $student->timestart = $timestart;
1610 $student->timeend = $timeend;
1611 $student->time = time();
6e8ca983 1612 $student->enrol = $enrol;
b0ccd3fb 1613 return update_record('user_students', $student);
361855e6 1614
631cf796 1615 } else {
75169b06 1616 require_once("$CFG->dirroot/mod/forum/lib.php");
2f3b54ae 1617 forum_add_user($userid, $courseid);
1618
631cf796 1619 $student->userid = $userid;
1620 $student->course = $courseid;
1621 $student->timestart = $timestart;
1622 $student->timeend = $timeend;
1623 $student->time = time();
6e8ca983 1624 $student->enrol = $enrol;
b0ccd3fb 1625 return insert_record('user_students', $student);
631cf796 1626 }
d7facad8 1627}
1628
7cf1c7bd 1629/**
1630 * Unenrols a student from a given course
1631 *
c6d15803 1632 * @param int $courseid The id of the course that is being viewed, if any
1633 * @param int $userid The id of the user that is being tested against.
7cf1c7bd 1634 * @return boolean
1635 */
9fa62805 1636function unenrol_student($userid, $courseid=0) {
d7facad8 1637
9fa62805 1638 if ($courseid) {
9fa49e22 1639 /// First delete any crucial stuff that might still send mail
b0ccd3fb 1640 if ($forums = get_records('forum', 'course', $courseid)) {
9fa49e22 1641 foreach ($forums as $forum) {
b0ccd3fb 1642 delete_records('forum_subscriptions', 'forum', $forum->id, 'userid', $userid);
9fa62805 1643 }
1644 }
1645 if ($groups = get_groups($courseid, $userid)) {
1646 foreach ($groups as $group) {
b0ccd3fb 1647 delete_records('groups_members', 'groupid', $group->id, 'userid', $userid);
bb09fb11 1648 }
f9903ed0 1649 }
b0ccd3fb 1650 return delete_records('user_students', 'userid', $userid, 'course', $courseid);
9fa49e22 1651
f9903ed0 1652 } else {
b0ccd3fb 1653 delete_records('forum_subscriptions', 'userid', $userid);
1654 delete_records('groups_members', 'userid', $userid);
1655 return delete_records('user_students', 'userid', $userid);
f9903ed0 1656 }
1657}
1658
7cf1c7bd 1659/**
1660 * Add a teacher to a given course
1661 *
1662 * @uses $USER
c6d15803 1663 * @param int $courseid The id of the course that is being viewed, if any
1664 * @param int $userid The id of the user that is being tested against. Set this to 0 if you would just like to test against the currently logged in user.
1665 * @param int $editall ?
7cf1c7bd 1666 * @param string $role ?
c6d15803 1667 * @param int $timestart ?
1668 * @param int $timeend ?
7cf1c7bd 1669 * @return boolean
1670 * @todo Finish documenting this function
1671 */
6e8ca983 1672function add_teacher($userid, $courseid, $editall=1, $role='', $timestart=0, $timeend=0, $enrol='manual') {
7b5944cd 1673 global $CFG;
3041b0f8 1674
61451a36 1675 if ($teacher = get_record('user_teachers', 'userid', $userid, 'course', $courseid)) {
b40bc478 1676 $newteacher = NULL;
1677 $newteacher->id = $teacher->id;
1678 $newteacher->editall = $editall;
6e8ca983 1679 $newteacher->enrol = $enrol;
b40bc478 1680 if ($role) {
1681 $newteacher->role = $role;
1682 }
1683 if ($timestart) {
1684 $newteacher->timestart = $timestart;
3041b0f8 1685 }
b40bc478 1686 if ($timeend) {
1687 $newteacher->timeend = $timeend;
1688 }
1689 return update_record('user_teachers', $newteacher);
3041b0f8 1690 }
61451a36 1691
b0ccd3fb 1692 if (!record_exists('user', 'id', $userid)) {
61451a36 1693 return false; // no such user
1694 }
1695
b0ccd3fb 1696 if (!record_exists('course', 'id', $courseid)) {
61451a36 1697 return false; // no such course
1698 }
1699
1700 $teacher = NULL;
1701 $teacher->userid = $userid;
1702 $teacher->course = $courseid;
1703 $teacher->editall = $editall;
1704 $teacher->role = $role;
5a2dea02 1705 $teacher->timemodified = time();
1706 $newteacher->timestart = $timestart;
1707 $newteacher->timeend = $timeend;
b0ccd3fb 1708 if ($student = get_record('user_students', 'userid', $userid, 'course', $courseid)) {
5a2dea02 1709 $teacher->timestart = $student->timestart;
1710 $teacher->timeend = $student->timeend;
1711 $teacher->timeaccess = $student->timeaccess;
1712 }
61451a36 1713
b0ccd3fb 1714 if (record_exists('user_teachers', 'course', $courseid)) {
61451a36 1715 $teacher->authority = 2;
1716 } else {
1717 $teacher->authority = 1;
1718 }
b0ccd3fb 1719 delete_records('user_students', 'userid', $userid, 'course', $courseid); // Unenrol as student
8f0cd6ef 1720
709f0ec8 1721 /// Add forum subscriptions for new users
7b5944cd 1722 require_once('../mod/forum/lib.php');
1723 forum_add_user($userid, $courseid);
61451a36 1724
b0ccd3fb 1725 return insert_record('user_teachers', $teacher);
61451a36 1726
3041b0f8 1727}
1728
7cf1c7bd 1729/**
1730 * Removes a teacher from a given course (or ALL courses)
1731 * Does not delete the user account
1732 *
c6d15803 1733 * @param int $courseid The id of the course that is being viewed, if any
361855e6 1734 * @param int $userid The id of the user that is being tested against.
7cf1c7bd 1735 * @return boolean
1736 */
3041b0f8 1737function remove_teacher($userid, $courseid=0) {
3041b0f8 1738 if ($courseid) {
9fa49e22 1739 /// First delete any crucial stuff that might still send mail
b0ccd3fb 1740 if ($forums = get_records('forum', 'course', $courseid)) {
9fa49e22 1741 foreach ($forums as $forum) {
b0ccd3fb 1742 delete_records('forum_subscriptions', 'forum', $forum->id, 'userid', $userid);
9fa49e22 1743 }
1744 }
b02193e6 1745
1746 /// Next if the teacher is not registered as a student, but is
1747 /// a member of a group, remove them from the group.
1748 if (!isstudent($courseid, $userid)) {
1749 if ($groups = get_groups($courseid, $userid)) {
1750 foreach ($groups as $group) {
b0ccd3fb 1751 delete_records('groups_members', 'groupid', $group->id, 'userid', $userid);
b02193e6 1752 }
1753 }
1754 }
1755
b0ccd3fb 1756 return delete_records('user_teachers', 'userid', $userid, 'course', $courseid);
57507290 1757 } else {
b0ccd3fb 1758 delete_records('forum_subscriptions', 'userid', $userid);
1759 return delete_records('user_teachers', 'userid', $userid);
57507290 1760 }
f9903ed0 1761}
1762
7cf1c7bd 1763/**
1764 * Add a creator to the site
1765 *
361855e6 1766 * @param int $userid The id of the user that is being tested against.
7cf1c7bd 1767 * @return boolean
1768 */
3041b0f8 1769function add_creator($userid) {
3041b0f8 1770
b0ccd3fb 1771 if (!record_exists('user_admins', 'userid', $userid)) {
1772 if (record_exists('user', 'id', $userid)) {
3041b0f8 1773 $creator->userid = $userid;
b0ccd3fb 1774 return insert_record('user_coursecreators', $creator);
3041b0f8 1775 }
1776 return false;
1777 }
1778 return true;
1779}
1780
7cf1c7bd 1781/**
1782 * Remove a creator from a site
1783 *
1784 * @uses $db
c6d15803 1785 * @param int $userid The id of the user that is being tested against.
7cf1c7bd 1786 * @return boolean
1787 */
3041b0f8 1788function remove_creator($userid) {
3041b0f8 1789 global $db;
1790
b0ccd3fb 1791 return delete_records('user_coursecreators', 'userid', $userid);
3041b0f8 1792}
1793
7cf1c7bd 1794/**
1795 * Add an admin to a site
1796 *
1797 * @uses SITEID
c6d15803 1798 * @param int $userid The id of the user that is being tested against.
7cf1c7bd 1799 * @return boolean
1800 */
3041b0f8 1801function add_admin($userid) {
3041b0f8 1802
b0ccd3fb 1803 if (!record_exists('user_admins', 'userid', $userid)) {
1804 if (record_exists('user', 'id', $userid)) {
3041b0f8 1805 $admin->userid = $userid;
361855e6 1806
f950af3c 1807 // any admin is also a teacher on the site course
222ac91b 1808 if (!record_exists('user_teachers', 'course', SITEID, 'userid', $userid)) {
1809 if (!add_teacher($userid, SITEID)) {
f950af3c 1810 return false;
1811 }
1812 }
361855e6 1813
b0ccd3fb 1814 return insert_record('user_admins', $admin);
3041b0f8 1815 }
1816 return false;
1817 }
1818 return true;
1819}
1820
7cf1c7bd 1821/**
1822 * Removes an admin from a site
1823 *
1824 * @uses $db
1825 * @uses SITEID
c6d15803 1826 * @param int $userid The id of the user that is being tested against.
7cf1c7bd 1827 * @return boolean
1828 */
3041b0f8 1829function remove_admin($userid) {
9fa49e22 1830 global $db;
f9903ed0 1831
f950af3c 1832 // remove also from the list of site teachers
222ac91b 1833 remove_teacher($userid, SITEID);
f950af3c 1834
b0ccd3fb 1835 return delete_records('user_admins', 'userid', $userid);
f9903ed0 1836}
1837
7cf1c7bd 1838/**
1839 * Clear a course out completely, deleting all content
1840 * but don't delete the course itself
1841 *
1842 * @uses $USER
1843 * @uses $SESSION
1844 * @uses $CFG
c6d15803 1845 * @param int $courseid The id of the course that is being viewed
7cf1c7bd 1846 * @param boolean $showfeedback Set this to false to suppress notifications from being printed as the functions performs its steps.
1847 * @return boolean
1848 */
07aeb7b0 1849function remove_course_contents($courseid, $showfeedback=true) {
07aeb7b0 1850
ee23f384 1851 global $CFG, $THEME, $USER, $SESSION;
07aeb7b0 1852
1853 $result = true;
1854
b0ccd3fb 1855 if (! $course = get_record('course', 'id', $courseid)) {
1856 error('Course ID was incorrect (can\'t find it)');
07aeb7b0 1857 }
1858
b0ccd3fb 1859 $strdeleted = get_string('deleted');
07aeb7b0 1860
1861 // First delete every instance of every module
d8ba183c 1862
b0ccd3fb 1863 if ($allmods = get_records('modules') ) {
07aeb7b0 1864 foreach ($allmods as $mod) {
1865 $modname = $mod->name;
b0ccd3fb 1866 $modfile = $CFG->dirroot .'/mod/'. $modname .'/lib.php';
1867 $moddelete = $modname .'_delete_instance'; // Delete everything connected to an instance
1868 $moddeletecourse = $modname .'_delete_course'; // Delete other stray stuff (uncommon)
07aeb7b0 1869 $count=0;
1870 if (file_exists($modfile)) {
1871 include_once($modfile);
1872 if (function_exists($moddelete)) {
b0ccd3fb 1873 if ($instances = get_records($modname, 'course', $course->id)) {
07aeb7b0 1874 foreach ($instances as $instance) {
1875 if ($moddelete($instance->id)) {
1876 $count++;
1877 } else {
b0ccd3fb 1878 notify('Could not delete '. $modname .' instance '. $instance->id .' ('. $instance->name .')');
07aeb7b0 1879 $result = false;
1880 }
1881 }
1882 }
1883 } else {
b0ccd3fb 1884 notify('Function '. $moddelete() .'doesn\'t exist!');
07aeb7b0 1885 $result = false;
1886 }
1887
ca952b03 1888 if (function_exists($moddeletecourse)) {
1889 $moddeletecourse($course);
1890 }
07aeb7b0 1891 }
1892 if ($showfeedback) {
b0ccd3fb 1893 notify($strdeleted .' '. $count .' x '. $modname);
07aeb7b0 1894 }
1895 }
1896 } else {
b0ccd3fb 1897 error('No modules are installed!');
07aeb7b0 1898 }
1899
1900 // Delete any user stuff
1901
b0ccd3fb 1902 if (delete_records('user_students', 'course', $course->id)) {
07aeb7b0 1903 if ($showfeedback) {
b0ccd3fb 1904 notify($strdeleted .' user_students');
07aeb7b0 1905 }
1906 } else {
1907 $result = false;
1908 }
1909
b0ccd3fb 1910 if (delete_records('user_teachers', 'course', $course->id)) {
07aeb7b0 1911 if ($showfeedback) {
b0ccd3fb 1912 notify($strdeleted .' user_teachers');
07aeb7b0 1913 }
1914 } else {
1915 $result = false;
1916 }
1917
082e3ebc 1918 // Delete any groups
1919
b0ccd3fb 1920 if ($groups = get_records('groups', 'courseid', $course->id)) {
082e3ebc 1921 foreach ($groups as $group) {
b0ccd3fb 1922 if (delete_records('groups_members', 'groupid', $group->id)) {
082e3ebc 1923 if ($showfeedback) {
b0ccd3fb 1924 notify($strdeleted .' groups_members');
082e3ebc 1925 }
1926 } else {
1927 $result = false;
1928 }
b0ccd3fb 1929 if (delete_records('groups', 'id', $group->id)) {
082e3ebc 1930 if ($showfeedback) {
b0ccd3fb 1931 notify($strdeleted .' groups');
082e3ebc 1932 }
1933 } else {
1934 $result = false;
1935 }
1936 }
1937 }
1938
1939 // Delete events
1940
b0ccd3fb 1941 if (delete_records('event', 'courseid', $course->id)) {
082e3ebc 1942 if ($showfeedback) {
b0ccd3fb 1943 notify($strdeleted .' event');
082e3ebc 1944 }
1945 } else {
1946 $result = false;
1947 }
1948
07aeb7b0 1949 // Delete logs
1950
b0ccd3fb 1951 if (delete_records('log', 'course', $course->id)) {
07aeb7b0 1952 if ($showfeedback) {
b0ccd3fb 1953 notify($strdeleted .' log');
07aeb7b0 1954 }
1955 } else {
1956 $result = false;
1957 }
1958
1959 // Delete any course stuff
1960
b0ccd3fb 1961 if (delete_records('course_sections', 'course', $course->id)) {
07aeb7b0 1962 if ($showfeedback) {
b0ccd3fb 1963 notify($strdeleted .' course_sections');
07aeb7b0 1964 }
1965 } else {
1966 $result = false;
1967 }
1968
b0ccd3fb 1969 if (delete_records('course_modules', 'course', $course->id)) {
07aeb7b0 1970 if ($showfeedback) {
b0ccd3fb 1971 notify($strdeleted .' course_modules');
07aeb7b0 1972 }
1973 } else {
1974 $result = false;
1975 }
1976
1977 return $result;
1978
1979}
1980
7cf1c7bd 1981/**
1982 * This function will empty a course of USER data as much as
1983/// possible. It will retain the activities and the structure
1984/// of the course.
1985 *
1986 * @uses $USER
1987 * @uses $THEME
1988 * @uses $SESSION
1989 * @uses $CFG
c6d15803 1990 * @param int $courseid The id of the course that is being viewed
7cf1c7bd 1991 * @param boolean $showfeedback Set this to false to suppress notifications from being printed as the functions performs its steps.
1992 * @param boolean $removestudents ?
1993 * @param boolean $removeteachers ?
1994 * @param boolean $removegroups ?
1995 * @param boolean $removeevents ?
1996 * @param boolean $removelogs ?
1997 * @return boolean
1998 * @todo Finish documenting this function
1999 */
3831de52 2000function remove_course_userdata($courseid, $showfeedback=true,
2001 $removestudents=true, $removeteachers=false, $removegroups=true,
2002 $removeevents=true, $removelogs=false) {
3831de52 2003
2004 global $CFG, $THEME, $USER, $SESSION;
2005
2006 $result = true;
2007
b0ccd3fb 2008 if (! $course = get_record('course', 'id', $courseid)) {
2009 error('Course ID was incorrect (can\'t find it)');
3831de52 2010 }
2011
b0ccd3fb 2012 $strdeleted = get_string('deleted');
3831de52 2013
2014 // Look in every instance of every module for data to delete
2015
b0ccd3fb 2016 if ($allmods = get_records('modules') ) {
3831de52 2017 foreach ($allmods as $mod) {
2018 $modname = $mod->name;
b0ccd3fb 2019 $modfile = $CFG->dirroot .'/mod/'. $modname .'/lib.php';
2020 $moddeleteuserdata = $modname .'_delete_userdata'; // Function to delete user data
3831de52 2021 $count=0;
2022 if (file_exists($modfile)) {
2023 @include_once($modfile);
2024 if (function_exists($moddeleteuserdata)) {
2025 $moddeleteuserdata($course, $showfeedback);
2026 }
2027 }
2028 }
2029 } else {
b0ccd3fb 2030 error('No modules are installed!');
3831de52 2031 }
2032
2033 // Delete other stuff
2034
2035 if ($removestudents) {
2036 /// Delete student enrolments
b0ccd3fb 2037 if (delete_records('user_students', 'course', $course->id)) {
3831de52 2038 if ($showfeedback) {
b0ccd3fb 2039 notify($strdeleted .' user_students');
3831de52 2040 }
2041 } else {
2042 $result = false;
2043 }
2044 /// Delete group members (but keep the groups)
b0ccd3fb 2045 if ($groups = get_records('groups', 'courseid', $course->id)) {
3831de52 2046 foreach ($groups as $group) {
b0ccd3fb 2047 if (delete_records('groups_members', 'groupid', $group->id)) {
3831de52 2048 if ($showfeedback) {
b0ccd3fb 2049 notify($strdeleted .' groups_members');
3831de52 2050 }
2051 } else {
2052 $result = false;
2053 }
2054 }
2055 }
2056 }
2057
2058 if ($removeteachers) {
b0ccd3fb 2059 if (delete_records('user_teachers', 'course', $course->id)) {
3831de52 2060 if ($showfeedback) {
b0ccd3fb 2061 notify($strdeleted .' user_teachers');
3831de52 2062 }
2063 } else {
2064 $result = false;
2065 }
2066 }
2067
2068 if ($removegroups) {
b0ccd3fb 2069 if ($groups = get_records('groups', 'courseid', $course->id)) {
3831de52 2070 foreach ($groups as $group) {
b0ccd3fb 2071 if (delete_records('groups', 'id', $group->id)) {
3831de52 2072 if ($showfeedback) {
b0ccd3fb 2073 notify($strdeleted .' groups');
3831de52 2074 }
2075 } else {
2076 $result = false;
2077 }
2078 }
2079 }
2080 }
2081
2082 if ($removeevents) {
b0ccd3fb 2083 if (delete_records('event', 'courseid', $course->id)) {
3831de52 2084 if ($showfeedback) {
b0ccd3fb 2085 notify($strdeleted .' event');
3831de52 2086 }
2087 } else {
2088 $result = false;
2089 }
2090 }
2091
2092 if ($removelogs) {
b0ccd3fb 2093 if (delete_records('log', 'course', $course->id)) {
3831de52 2094 if ($showfeedback) {
b0ccd3fb 2095 notify($strdeleted .' log');
3831de52 2096 }
2097 } else {
2098 $result = false;
2099 }
2100 }
2101
2102 return $result;
2103
2104}
2105
2106
f9903ed0 2107
f374fb10 2108/// GROUPS /////////////////////////////////////////////////////////
d8ba183c 2109
f374fb10 2110
2111/**
2112* Returns a boolean: is the user a member of the given group?
d8ba183c 2113*
dcd338ff 2114* @param type description
7cf1c7bd 2115 * @todo Finish documenting this function
f374fb10 2116*/
2117function ismember($groupid, $userid=0) {
2118 global $USER;
2119
8a2c9076 2120 if (!$groupid) { // No point doing further checks
2121 return false;
2122 }
2123
f374fb10 2124 if (!$userid) {
0d67c514 2125 if (empty($USER->groupmember)) {
2126 return false;
2127 }
2128 foreach ($USER->groupmember as $courseid => $mgroupid) {
2129 if ($mgroupid == $groupid) {
2130 return true;
2131 }
2132 }
2133 return false;
f374fb10 2134 }
2135
b0ccd3fb 2136 return record_exists('groups_members', 'groupid', $groupid, 'userid', $userid);
f374fb10 2137}
2138
4ed533df 2139/**
2140 * Add a user to a group, return true upon success or if user already a group member
2141 *
2142 * @param groupid The group id
2143 * @param userid The user id
2144 * @todo Finish documenting this function
2145 */
2146function add_user_to_group ($groupid, $userid) {
2147 if (ismember($groupid, $userid)) return true;
2148 $record->groupid = $groupid;
2149 $record->userid = $userid;
2150 $record->timeadded = time();
2151 return (insert_record('groups_members', $record) !== false);
2152}
2153
2154
0d67c514 2155/**
c6d15803 2156 * Returns the group ID of the current user in the given course
2157 *
2158 * @uses $USER
2159 * @param int $courseid The course being examined - relates to id field in 'course' table.
7cf1c7bd 2160 * @todo Finish documenting this function
c6d15803 2161 */
0d67c514 2162function mygroupid($courseid) {
2163 global $USER;
2164
2165 if (empty($USER->groupmember[$courseid])) {
2166 return 0;
2167 } else {
2168 return $USER->groupmember[$courseid];
2169 }
2170}
2171
f374fb10 2172/**
c6d15803 2173 * For a given course, and possibly course module, determine
2174 * what the current default groupmode is:
2175 * NOGROUPS, SEPARATEGROUPS or VISIBLEGROUPS
2176 *
89dcb99d 2177 * @param course $course A {@link $COURSE} object
2178 * @param array? $cm A course module object
c6d15803 2179 * @return int A group mode (NOGROUPS, SEPARATEGROUPS or VISIBLEGROUPS)
2180 */
f374fb10 2181function groupmode($course, $cm=null) {
2182
2183 if ($cm and !$course->groupmodeforce) {
2184 return $cm->groupmode;
2185 }
2186 return $course->groupmode;
2187}
2188
2189
2190/**
c6d15803 2191 * Sets the current group in the session variable
2192 *
2193 * @uses $SESSION
2194 * @param int $courseid The course being examined - relates to id field in 'course' table.
2195 * @param int $groupid The group being examined.
2196 * @return int Current group id which was set by this function
7cf1c7bd 2197 * @todo Finish documenting this function
c6d15803 2198 */
f374fb10 2199function set_current_group($courseid, $groupid) {
2200 global $SESSION;
2201
2202 return $SESSION->currentgroup[$courseid] = $groupid;
2203}
2204
2205
2206/**
c6d15803 2207 * Gets the current group for the current user as an id or an object
2208 *
2209 * @uses $CFG
2210 * @uses $SESSION
2211 * @param int $courseid The course being examined - relates to id field in 'course' table.
9f1f6daf 2212 * @param boolean $full If true, the return value is a full record object. If false, just the id of the record.
7cf1c7bd 2213 * @todo Finish documenting this function
c6d15803 2214 */
f374fb10 2215function get_current_group($courseid, $full=false) {
2216 global $SESSION, $USER;
2217
ce04df6b 2218 if (!isset($SESSION->currentgroup[$courseid])) {
f374fb10 2219 if (empty($USER->groupmember[$courseid])) {
8a2c9076 2220 return 0;
f374fb10 2221 } else {
2222 $SESSION->currentgroup[$courseid] = $USER->groupmember[$courseid];
2223 }
2224 }
2225
2226 if ($full) {
0da33e07 2227 return get_record('groups', 'id', $SESSION->currentgroup[$courseid]);
f374fb10 2228 } else {
2229 return $SESSION->currentgroup[$courseid];
2230 }
2231}
2232
0d67c514 2233/**
c6d15803 2234 * A combination function to make it easier for modules
2235 * to set up groups.
2236 *
2237 * It will use a given "groupid" parameter and try to use
2238 * that to reset the current group for the user.
2239 *
2240 * @uses VISIBLEGROUPS
89dcb99d 2241 * @param course $course A {@link $COURSE} object
c6d15803 2242 * @param int $groupmode Either NOGROUPS, SEPARATEGROUPS or VISIBLEGROUPS
2243 * @param int $groupid Will try to use this optional parameter to
2244 * reset the current group for the user
89dcb99d 2245 * @return int|false Returns the current group id or false if error.
7cf1c7bd 2246 * @todo Finish documenting this function
c6d15803 2247 */
eb6147a8 2248function get_and_set_current_group($course, $groupmode, $groupid=-1) {
0d67c514 2249
2250 if (!$groupmode) { // Groups don't even apply
d8ba183c 2251 return false;
0d67c514 2252 }
2253
2254 $currentgroupid = get_current_group($course->id);
2255
eb6147a8 2256 if ($groupid < 0) { // No change was specified
2257 return $currentgroupid;
2258 }
2259
2260 if ($groupid) { // Try to change the current group to this groupid
0d67c514 2261 if ($group = get_record('groups', 'id', $groupid, 'courseid', $course->id)) { // Exists
2262 if (isteacheredit($course->id)) { // Sets current default group
2263 $currentgroupid = set_current_group($course->id, $group->id);
2264
2265 } else if ($groupmode == VISIBLEGROUPS) { // All groups are visible
2266 $currentgroupid = $group->id;
2267 }
2268 }
eb6147a8 2269 } else { // When groupid = 0 it means show ALL groups
2270 if (isteacheredit($course->id)) { // Sets current default group
2271 $currentgroupid = set_current_group($course->id, 0);
2272
2273 } else if ($groupmode == VISIBLEGROUPS) { // All groups are visible
2274 $currentgroupid = 0;
2275 }
0d67c514 2276 }
2277
2278 return $currentgroupid;
2279}
2280
2281
c3cbfe7f 2282/**
c6d15803 2283 * A big combination function to make it easier for modules
2284 * to set up groups.
2285 *
2286 * Terminates if the current user shouldn't be looking at this group
2287 * Otherwise returns the current group if there is one
2288 * Otherwise returns false if groups aren't relevant
2289 *
2290 * @uses SEPARATEGROUPS
2291 * @uses VISIBLEGROUPS
89dcb99d 2292 * @param course $course A {@link $COURSE} object
c6d15803 2293 * @param int $groupmode Either NOGROUPS, SEPARATEGROUPS or VISIBLEGROUPS
2294 * @param string $urlroot ?
7cf1c7bd 2295 * @todo Finish documenting this function
c6d15803 2296 */
c3cbfe7f 2297function setup_and_print_groups($course, $groupmode, $urlroot) {
2298
eb6147a8 2299 if (isset($_GET['group'])) {
2300 $changegroup = $_GET['group']; /// 0 or higher
2301 } else {
2302 $changegroup = -1; /// This means no group change was specified
2303 }
2304
2305 $currentgroup = get_and_set_current_group($course, $groupmode, $changegroup);
c3cbfe7f 2306
eb6147a8 2307 if ($currentgroup === false) {
c3cbfe7f 2308 return false;
2309 }
2310
4b6d8dd5 2311 if ($groupmode == SEPARATEGROUPS and !isteacheredit($course->id) and !$currentgroup) {
2312 print_heading(get_string('notingroup'));
c3cbfe7f 2313 print_footer($course);
2314 exit;
2315 }
2316
2317 if ($groupmode == VISIBLEGROUPS or ($groupmode and isteacheredit($course->id))) {
b0ccd3fb 2318 if ($groups = get_records_menu('groups', 'courseid', $course->id, 'name ASC', 'id,name')) {
eb6147a8 2319 echo '<div align="center">';
c3cbfe7f 2320 print_group_menu($groups, $groupmode, $currentgroup, $urlroot);
eb6147a8 2321 echo '</div>';
c3cbfe7f 2322 }
2323 }
2324
2325 return $currentgroup;
2326}
0d67c514 2327
f374fb10 2328
2329
f9903ed0 2330/// CORRESPONDENCE ////////////////////////////////////////////////
2331
7cf1c7bd 2332/**
2333 * Send an email to a specified user
2334 *
7cf1c7bd 2335 * @uses $CFG
2336 * @uses $_SERVER
c6d15803 2337 * @uses SITEID
89dcb99d 2338 * @param user $user A {@link $USER} object
2339 * @param user $from A {@link $USER} object
7cf1c7bd 2340 * @param string $subject plain text subject line of the email
2341 * @param string $messagetext plain text version of the message
2342 * @param string $messagehtml complete html version of the message (optional)
2343 * @param string $attachment a file on the filesystem, relative to $CFG->dataroot
2344 * @param string $attachname the name of the file (extension indicates MIME)
361855e6 2345 * @param boolean $usetrueaddress determines whether $from email address should
c6d15803 2346 * be sent out. Will be overruled by user profile setting for maildisplay
361855e6 2347 * @return boolean|string Returns "true" if mail was sent OK, "emailstop" if email
c6d15803 2348 * was blocked by user and "false" if there was another sort of error.
7cf1c7bd 2349 */
b0ccd3fb 2350function email_to_user($user, $from, $subject, $messagetext, $messagehtml='', $attachment='', $attachname='', $usetrueaddress=true) {
f9903ed0 2351
f9f4d999 2352 global $CFG, $FULLME;
f9903ed0 2353
0cc6fa6a 2354 global $course; // This is a bit of an ugly hack to be gotten rid of later
2355 if (!empty($course->lang)) { // Course language is defined
2356 $CFG->courselang = $course->lang;
2357 }
2358
b0ccd3fb 2359 include_once($CFG->libdir .'/phpmailer/class.phpmailer.php');
f9903ed0 2360
cadb96f2 2361 if (empty($user)) {
2362 return false;
2363 }
2364
2365 if (!empty($user->emailstop)) {
579dcca4 2366 return 'emailstop';
f9903ed0 2367 }
d8ba183c 2368
f9903ed0 2369 $mail = new phpmailer;
2370
b0ccd3fb 2371 $mail->Version = 'Moodle '. $CFG->version; // mailer version
2372 $mail->PluginDir = $CFG->libdir .'/phpmailer/'; // plugin directory (eg smtp plugin)
562bbe90 2373
98c4eae3 2374
b0ccd3fb 2375 if (current_language() != 'en') {
2376 $mail->CharSet = get_string('thischarset');
98c4eae3 2377 }
2378
b0ccd3fb 2379 if ($CFG->smtphosts == 'qmail') {
62740736 2380 $mail->IsQmail(); // use Qmail system
2381
2382 } else if (empty($CFG->smtphosts)) {
2383 $mail->IsMail(); // use PHP mail() = sendmail
2384
2385 } else {
1e411ffc 2386 $mail->IsSMTP(); // use SMTP directly
57ef3480 2387 if ($CFG->debug > 7) {
b0ccd3fb 2388 echo '<pre>' . "\n";
57ef3480 2389 $mail->SMTPDebug = true;
2390 }
b0ccd3fb 2391 $mail->Host = $CFG->smtphosts; // specify main and backup servers
9f58537a 2392
2393 if ($CFG->smtpuser) { // Use SMTP authentication
2394 $mail->SMTPAuth = true;
2395 $mail->Username = $CFG->smtpuser;
2396 $mail->Password = $CFG->smtppass;
2397 }
7f86ce17 2398 }
f9903ed0 2399
2b97bd71 2400 $adminuser = get_admin();
2401
b0ccd3fb 2402 $mail->Sender = $adminuser->email;
2b97bd71 2403
a402bdcb 2404 if (is_string($from)) { // So we can pass whatever we want if there is need
2405 $mail->From = $CFG->noreplyaddress;
0d8a590a 2406 $mail->FromName = $from;
a402bdcb 2407 } else if ($usetrueaddress and $from->maildisplay) {
b0ccd3fb 2408 $mail->From = $from->email;
6e506bf9 2409 $mail->FromName = fullname($from);
2410 } else {
b0ccd3fb 2411 $mail->From = $CFG->noreplyaddress;
0d8a590a 2412 $mail->FromName = fullname($from);
6e506bf9 2413 }
136dabd8 2414 $mail->Subject = stripslashes($subject);
f9903ed0 2415
b0ccd3fb 2416 $mail->AddAddress($user->email, fullname($user) );
f9903ed0 2417
58d24720 2418 $mail->WordWrap = 79; // set word wrap
f9903ed0 2419
857b798b 2420 if (!empty($from->customheaders)) { // Add custom headers
2421 if (is_array($from->customheaders)) {
2422 foreach ($from->customheaders as $customheader) {
2423 $mail->AddCustomHeader($customheader);
2424 }
2425 } else {
2426 $mail->AddCustomHeader($from->customheaders);
2427 }
b68dca19 2428 }
8f0cd6ef 2429
136dabd8 2430 if ($messagehtml) {
2431 $mail->IsHTML(true);
b0ccd3fb 2432 $mail->Encoding = 'quoted-printable'; // Encoding to use
136dabd8 2433 $mail->Body = $messagehtml;
78681899 2434 $mail->AltBody = "\n$messagetext\n";
136dabd8 2435 } else {
2436 $mail->IsHTML(false);
78681899 2437 $mail->Body = "\n$messagetext\n";
f9903ed0 2438 }
2439
136dabd8 2440 if ($attachment && $attachname) {
2441 if (ereg( "\\.\\." ,$attachment )) { // Security check for ".." in dir path
b0ccd3fb 2442 $mail->AddAddress($adminuser->email, fullname($adminuser) );
2443 $mail->AddStringAttachment('Error in attachment. User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain');
136dabd8 2444 } else {
b0ccd3fb 2445 include_once($CFG->dirroot .'/files/mimetypes.php');
2446 $mimetype = mimeinfo('type', $attachname);
2447 $mail->AddAttachment($CFG->dataroot .'/'. $attachment, $attachname, 'base64', $mimetype);
136dabd8 2448 }
f9903ed0 2449 }
2450
136dabd8 2451 if ($mail->Send()) {
2452 return true;
2453 } else {
b0ccd3fb 2454 mtrace('ERROR: '. $mail->ErrorInfo);
f9f4d999 2455 add_to_log(SITEID, 'library', 'mailer', $FULLME, 'ERROR: '. $mail->ErrorInfo);
f9903ed0 2456 return false;
2457 }
f9903ed0 2458}
2459
7cf1c7bd 2460/**
2461 * Resets specified user's password and send the new password to the user via email.
2462 *
2463 * @uses $CFG
89dcb99d 2464 * @param user $user A {@link $USER} object
361855e6 2465 * @return boolean|string Returns "true" if mail was sent OK, "emailstop" if email
c6d15803 2466 * was blocked by user and "false" if there was another sort of error.
7cf1c7bd 2467 */
1d881d92 2468function reset_password_and_mail($user) {
2469
2470 global $CFG;
2471
2472 $site = get_site();
2473 $from = get_admin();
2474
2475 $newpassword = generate_password();
2476
b0ccd3fb 2477 if (! set_field('user', 'password', md5($newpassword), 'id', $user->id) ) {
2478 error('Could not set user password!');
1d881d92 2479 }
2480
2481 $a->firstname = $user->firstname;
2482 $a->sitename = $site->fullname;
2483 $a->username = $user->username;
2484 $a->newpassword = $newpassword;
b0ccd3fb 2485 $a->link = $CFG->wwwroot .'/login/change_password.php';
2486 $a->signoff = fullname($from, true).' ('. $from->email .')';
1d881d92 2487
b0ccd3fb 2488 $message = get_string('newpasswordtext', '', $a);
1d881d92 2489
b0ccd3fb 2490 $subject = $site->fullname .': '. get_string('changedpassword');
1d881d92 2491
2492 return email_to_user($user, $from, $subject, $message);
2493
2494}
2495
7cf1c7bd 2496/**
2497 * Send email to specified user with confirmation text and activation link.
2498 *
2499 * @uses $CFG
89dcb99d 2500 * @param user $user A {@link $USER} object
361855e6 2501 * @return boolean|string Returns "true" if mail was sent OK, "emailstop" if email
c6d15803 2502 * was blocked by user and "false" if there was another sort of error.
7cf1c7bd 2503 */
2504 function send_confirmation_email($user) {
1d881d92 2505
2506 global $CFG;
2507
2508 $site = get_site();
2509 $from = get_admin();
2510
2511 $data->firstname = $user->firstname;
2512 $data->sitename = $site->fullname;
b0ccd3fb 2513 $data->link = $CFG->wwwroot .'/login/confirm.php?p='. $user->secret .'&amp;s='. $user->username;
2514 $data->admin = fullname($from) .' ('. $from->email .')';
1d881d92 2515
b0ccd3fb 2516 $message = get_string('emailconfirmation', '', $data);
2517 $subject = get_string('emailconfirmationsubject', '', $site->fullname);
1d881d92 2518
58d24720 2519 $messagehtml = text_to_html($message, false, false, true);
2520
2521 return email_to_user($user, $from, $subject, $message, $messagehtml);
1d881d92 2522
2523}
2524
7cf1c7bd 2525/**
2526 * send_password_change_confirmation_email.
2527 *
c6d15803 2528 * @uses $CFG
89dcb99d 2529 * @param user $user A {@link $USER} object
361855e6 2530 * @return boolean|string Returns "true" if mail was sent OK, "emailstop" if email
c6d15803 2531 * was blocked by user and "false" if there was another sort of error.
7cf1c7bd 2532 * @todo Finish documenting this function
2533 */
eb347b6b 2534function send_password_change_confirmation_email($user) {
2535
2536 global $CFG;
2537
2538 $site = get_site();
2539 $from = get_admin();
2540
2541 $data->firstname = $user->firstname;
2542 $data->sitename = $site->fullname;
b0ccd3fb 2543 $data->link = $CFG->wwwroot .'/login/forgot_password.php?p='. $user->secret .'&amp;s='. $user->username;
2544 $data->admin = fullname($from).' ('. $from->email .')';
eb347b6b 2545
b0ccd3fb 2546 $message = get_string('emailpasswordconfirmation', '', $data);
2547 $subject = get_string('emailpasswordconfirmationsubject', '', $site->fullname);
eb347b6b 2548
2549 return email_to_user($user, $from, $subject, $message);
2550
2551}
2552
7cf1c7bd 2553/**
2554 * Check that an email is allowed. It returns an error message if there
2555 * was a problem.
2556 *
2557 * @param type description
2558 * @todo Finish documenting this function
2559 */
85a1d4c9 2560function email_is_not_allowed($email) {
85a1d4c9 2561
2562 global $CFG;
2563
2564 if (!empty($CFG->allowemailaddresses)) {
2565 $allowed = explode(' ', $CFG->allowemailaddresses);
2566 foreach ($allowed as $allowedpattern) {
2567 $allowedpattern = trim($allowedpattern);
2568 if (!$allowedpattern) {
2569 continue;
2570 }
2571 if (strpos($email, $allowedpattern) !== false) { // Match!
2572 return false;
2573 }
2574 }
b0ccd3fb 2575 return get_string('emailonlyallowed', '', $CFG->allowemailaddresses);
85a1d4c9 2576
2577 } else if (!empty($CFG->denyemailaddresses)) {
2578 $denied = explode(' ', $CFG->denyemailaddresses);
2579 foreach ($denied as $deniedpattern) {
2580 $deniedpattern = trim($deniedpattern);
2581 if (!$deniedpattern) {
2582 continue;
2583 }
2584 if (strpos($email, $deniedpattern) !== false) { // Match!
b0ccd3fb 2585 return get_string('emailnotallowed', '', $CFG->denyemailaddresses);
85a1d4c9 2586 }
2587 }
2588 }
2589
2590 return false;
2591}
1d881d92 2592
136dabd8 2593
f9903ed0 2594/// FILE HANDLING /////////////////////////////////////////////
2595
7cf1c7bd 2596/**
c6d15803 2597 * Create a directory.
7cf1c7bd 2598 *
2599 * @uses $CFG
8c3dba73 2600 * @param string $directory a string of directory names under $CFG->dataroot eg stuff/assignment/1
c6d15803 2601 * param boolean $shownotices If true then notification messages will be printed out on error.
2602 * @return string|false Returns full path to directory if successful, false if not
7cf1c7bd 2603 */
66f9a82c 2604function make_upload_directory($directory, $shownotices=true) {
6b174680 2605
2606 global $CFG;
2607
2608 $currdir = $CFG->dataroot;
fe287429 2609
2e6d4273 2610 umask(0000);
2611
6b174680 2612 if (!file_exists($currdir)) {
2e6d4273 2613 if (! mkdir($currdir, $CFG->directorypermissions)) {
66f9a82c 2614 if ($shownotices) {
b0ccd3fb 2615 notify('ERROR: You need to create the directory '. $currdir .' with web server write access');
66f9a82c 2616 }
6b174680 2617 return false;
2618 }
2765411a 2619 if ($handle = fopen($currdir.'/.htaccess', 'w')) { // For safety
2620 @fwrite($handle, "deny from all\r\n");
2621 @fclose($handle);
2622 }
6b174680 2623 }
2624
b0ccd3fb 2625 $dirarray = explode('/', $directory);
6b174680 2626
2627 foreach ($dirarray as $dir) {
b0ccd3fb 2628 $currdir = $currdir .'/'. $dir;
6b174680 2629 if (! file_exists($currdir)) {
2e6d4273 2630 if (! mkdir($currdir, $CFG->directorypermissions)) {
66f9a82c 2631 if ($shownotices) {
b0ccd3fb 2632 notify('ERROR: Could not find or create a directory ('. $currdir .')');
66f9a82c 2633 }
6b174680 2634 return false;
2635 }
d99bab2d 2636 //@chmod($currdir, $CFG->directorypermissions); // Just in case mkdir didn't do it
6b174680 2637 }
2638 }
2639
2640 return $currdir;
2641}
1e03c552 2642
7cf1c7bd 2643/**
2644 * Makes an upload directory for a particular module.
2645 *
2646 * @uses $CFG
c6d15803 2647 * @param int $courseid The id of the course in question - maps to id field of 'course' table.
2648 * @return string|false Returns full path to directory if successful, false if not
7cf1c7bd 2649 * @todo Finish documenting this function
2650 */
ca4f8eb8 2651function make_mod_upload_directory($courseid) {
2652 global $CFG;
2653
b0ccd3fb 2654 if (! $moddata = make_upload_directory($courseid .'/'. $CFG->moddata)) {
ca4f8eb8 2655 return false;
2656 }
2657
b0ccd3fb 2658 $strreadme = get_string('readme');
ca4f8eb8 2659
b0ccd3fb 2660 if (file_exists($CFG->dirroot .'/lang/'. $CFG->lang .'/docs/module_files.txt')) {
2661 copy($CFG->dirroot .'/lang/'. $CFG->lang .'/docs/module_files.txt', $moddata .'/'. $strreadme .'.txt');
ca4f8eb8 2662 } else {
b0ccd3fb 2663 copy($CFG->dirroot .'/lang/en/docs/module_files.txt', $moddata .'/'. $strreadme .'.txt');
ca4f8eb8 2664 }
2665 return $moddata;
2666}
2667
7cf1c7bd 2668/**
c6d15803 2669 * Returns current name of file on disk if it exists.
7cf1c7bd 2670 *
c6d15803 2671 * @param string $newfile File to be verified
2672 * @return string Current name of file on disk if true
7cf1c7bd 2673 * @todo Finish documenting this function
2674 */
44e2d2bb 2675function valid_uploaded_file($newfile) {
9c9f7d77 2676 if (empty($newfile)) {
b0ccd3fb 2677 return '';
9c9f7d77 2678 }
44e2d2bb 2679 if (is_uploaded_file($newfile['tmp_name']) and $newfile['size'] > 0) {
2680 return $newfile['tmp_name'];
2681 } else {
b0ccd3fb 2682 return '';
44e2d2bb 2683 }
2684}
2685
7cf1c7bd 2686/**
2687 * Returns the maximum size for uploading files.
2688 *
2689 * There are seven possible upload limits:
2690 * 1. in Apache using LimitRequestBody (no way of checking or changing this)
2691 * 2. in php.ini for 'upload_max_filesize' (can not be changed inside PHP)
2692 * 3. in .htaccess for 'upload_max_filesize' (can not be changed inside PHP)
2693 * 4. in php.ini for 'post_max_size' (can not be changed inside PHP)
2694 * 5. by the Moodle admin in $CFG->maxbytes
2695 * 6. by the teacher in the current course $course->maxbytes
2696 * 7. by the teacher for the current module, eg $assignment->maxbytes
2697 *
2698 * These last two are passed to this function as arguments (in bytes).
2699 * Anything defined as 0 is ignored.
2700 * The smallest of all the non-zero numbers is returned.
2701 *
c6d15803 2702 * @param int $sizebytes ?
2703 * @param int $coursebytes Current course $course->maxbytes (in bytes)
2704 * @param int $modulebytes Current module ->maxbytes (in bytes)
2705 * @return int The maximum size for uploading files.
7cf1c7bd 2706 * @todo Finish documenting this function
2707 */
4909e176 2708function get_max_upload_file_size($sitebytes=0, $coursebytes=0, $modulebytes=0) {
4909e176 2709
b0ccd3fb 2710 if (! $filesize = ini_get('upload_max_filesize')) {
2711 $filesize = '5M';
44e2d2bb 2712 }
4909e176 2713 $minimumsize = get_real_size($filesize);
2714
b0ccd3fb 2715 if ($postsize = ini_get('post_max_size')) {
316ebf78 2716 $postsize = get_real_size($postsize);
2717 if ($postsize < $minimumsize) {
2718 $minimumsize = $postsize;
2719 }
2720 }
2721
4909e176 2722 if ($sitebytes and $sitebytes < $minimumsize) {
2723 $minimumsize = $sitebytes;
2724 }
2725
2726 if ($coursebytes and $coursebytes < $minimumsize) {
2727 $minimumsize = $coursebytes;
2728 }
2729
2730 if ($modulebytes and $modulebytes < $minimumsize) {
2731 $minimumsize = $modulebytes;
2732 }
2733
2734 return $minimumsize;
2735}
2736
7cf1c7bd 2737/**
2738 * Related to the above function - this function returns an
2739 * array of possible sizes in an array, translated to the
2740 * local language.
2741 *
c6d15803 2742 * @uses SORT_NUMERIC
2743 * @param int $sizebytes ?
2744 * @param int $coursebytes Current course $course->maxbytes (in bytes)
2745 * @param int $modulebytes Current module ->maxbytes (in bytes)
2746 * @return int
7cf1c7bd 2747 * @todo Finish documenting this function
2748 */
4909e176 2749function get_max_upload_sizes($sitebytes=0, $coursebytes=0, $modulebytes=0) {
4909e176 2750
2751 if (!$maxsize = get_max_upload_file_size($sitebytes, $coursebytes, $modulebytes)) {
2752 return array();
2753 }
2754
2755 $filesize[$maxsize] = display_size($maxsize);
2756
d8ba183c 2757 $sizelist = array(10240, 51200, 102400, 512000, 1048576, 2097152,
4909e176 2758 5242880, 10485760, 20971520, 52428800, 104857600);
2759
2760 foreach ($sizelist as $sizebytes) {
2761 if ($sizebytes < $maxsize) {
2762 $filesize[$sizebytes] = display_size($sizebytes);
2763 }
2764 }
2765
2766 krsort($filesize, SORT_NUMERIC);
2767
2768 return $filesize;
44e2d2bb 2769}
2770
7cf1c7bd 2771/**
2772 * If there has been an error uploading a file, print the appropriate error message
2773 * Numerical constants used as constant definitions not added until PHP version 4.2.0
2774 *
c6d15803 2775 * $filearray is a 1-dimensional sub-array of the $_FILES array
7cf1c7bd 2776 * eg $filearray = $_FILES['userfile1']
361855e6 2777 * If left empty then the first element of the $_FILES array will be used
8c3dba73 2778 *
c6d15803 2779 * @uses $_FILES
2780 * @param array $filearray A 1-dimensional sub-array of the $_FILES array
2781 * @param boolean $returnerror ?
7cf1c7bd 2782 * @return boolean
2783 * @todo Finish documenting this function
2784 */
ebd52396 2785function print_file_upload_error($filearray = '', $returnerror = false) {
ebd52396 2786
2787 if ($filearray == '' or !isset($filearray['error'])) {
2788
2789 if (empty($_FILES)) return false;
2790
2791 $files = $_FILES; /// so we don't mess up the _FILES array for subsequent code
2792 $filearray = array_shift($files); /// use first element of array
2793 }
2794
2795 switch ($filearray['error']) {
2796
2797 case 0: // UPLOAD_ERR_OK
2798 if ($filearray['size'] > 0) {
2799 $errmessage = get_string('uploadproblem', $filearray['name']);
2800 } else {
2801 $errmessage = get_string('uploadnofilefound'); /// probably a dud file name
2802 }
2803 break;
2804
2805 case 1: // UPLOAD_ERR_INI_SIZE
2806 $errmessage = get_string('uploadserverlimit');
2807 break;
2808
2809 case 2: // UPLOAD_ERR_FORM_SIZE
2810 $errmessage = get_string('uploadformlimit');
2811 break;
2812
2813 case 3: // UPLOAD_ERR_PARTIAL
2814 $errmessage = get_string('uploadpartialfile');
2815 break;
2816
2817 case 4: // UPLOAD_ERR_NO_FILE
2818 $errmessage = get_string('uploadnofilefound');
2819 break;
2820
2821 default:
2822 $errmessage = get_string('uploadproblem', $filearray['name']);
2823 }
2824
2825 if ($returnerror) {
2826 return $errmessage;
2827 } else {
2828 notify($errmessage);
2829 return true;
2830 }
2831
2832}
2833
7cf1c7bd 2834/**
2835 * Returns an array with all the filenames in
2836 * all subdirectories, relative to the given rootdir.
2837 * If excludefile is defined, then that file/directory is ignored
2838 * If getdirs is true, then (sub)directories are included in the output
2839 * If getfiles is true, then files are included in the output
2840 * (at least one of these must be true!)
2841 *
c6d15803 2842 * @param string $rootdir ?
2843 * @param string $excludefile If defined then the specified file/directory is ignored
2844 * @param boolean $descend ?
2845 * @param boolean $getdirs If true then (sub)directories are included in the output
2846 * @param boolean $getfiles If true then files are included in the output
2847 * @return array An array with all the filenames in
2848 * all subdirectories, relative to the given rootdir
2849 * @todo Finish documenting this function. Add examples of $excludefile usage.
7cf1c7bd 2850 */
b0ccd3fb 2851function get_directory_list($rootdir, $excludefile='', $descend=true, $getdirs=false, $getfiles=true) {
f9903ed0 2852
2853 $dirs = array();
f9903ed0 2854
16a5602c 2855 if (!$getdirs and !$getfiles) { // Nothing to show
12407705 2856 return $dirs;
2857 }
2858
16a5602c 2859 if (!is_dir($rootdir)) { // Must be a directory
2860 return $dirs;
2861 }
2862
2863 if (!$dir = opendir($rootdir)) { // Can't open it for some reason
d897cae4 2864 return $dirs;
2865 }
2866
81fcd0f0 2867 while (false !== ($file = readdir($dir))) {
b35e8568 2868 $firstchar = substr($file, 0, 1);
b0ccd3fb 2869 if ($firstchar == '.' or $file == 'CVS' or $file == $excludefile) {
b35e8568 2870 continue;
2871 }
b0ccd3fb 2872 $fullfile = $rootdir .'/'. $file;
2873 if (filetype($fullfile) == 'dir') {
16a5602c 2874 if ($getdirs) {
55fd8177 2875 $dirs[] = $file;
2876 }
bf5c2e84 2877 if ($descend) {
16a5602c 2878 $subdirs = get_directory_list($fullfile, $excludefile, $descend, $getdirs, $getfiles);
bf5c2e84 2879 foreach ($subdirs as $subdir) {
b0ccd3fb 2880 $dirs[] = $file .'/'. $subdir;
bf5c2e84 2881 }
f9903ed0 2882 }
16a5602c 2883 } else if ($getfiles) {
b35e8568 2884 $dirs[] = $file;
f9903ed0 2885 }
2886 }
44e2d2bb 2887 closedir($dir);
f9903ed0 2888
774ab660 2889 asort($dirs);
2890
f9903ed0 2891 return $dirs;
2892}
2893
7cf1c7bd 2894/**
2895 * Adds up all the files in a directory and works out the size.
2896 *
2897 * @param string $rootdir ?
2898 * @param string $excludefile ?
c6d15803 2899 * @return array
7cf1c7bd 2900 * @todo Finish documenting this function
2901 */
b0ccd3fb 2902function get_directory_size($rootdir, $excludefile='') {
16a5602c 2903
2904 $size = 0;
2905
2906 if (!is_dir($rootdir)) { // Must be a directory
2907 return $dirs;
2908 }
2909
b5b90f26 2910 if (!$dir = @opendir($rootdir)) { // Can't open it for some reason
16a5602c 2911 return $dirs;
2912 }
2913
2914 while (false !== ($file = readdir($dir))) {
2915 $firstchar = substr($file, 0, 1);
b0ccd3fb 2916 if ($firstchar == '.' or $file == 'CVS' or $file == $excludefile) {
16a5602c 2917 continue;
2918 }
b0ccd3fb 2919 $fullfile = $rootdir .'/'. $file;
2920 if (filetype($fullfile) == 'dir') {
16a5602c 2921 $size += get_directory_size($fullfile, $excludefile);
2922 } else {
2923 $size += filesize($fullfile);
2924 }
2925 }
2926 closedir($dir);
2927
2928 return $size;
2929}
2930
7cf1c7bd 2931/**
2932 * Converts numbers like 10M into bytes.
2933 *
7cf1c7bd 2934 * @param mixed $size The size to be converted
2935 * @return mixed
2936 */
989bfa9d 2937function get_real_size($size=0) {
989bfa9d 2938 if (!$size) {
d8ba183c 2939 return 0;
989bfa9d 2940 }
2941 $scan['MB'] = 1048576;
64efda84 2942 $scan['Mb'] = 1048576;
989bfa9d 2943 $scan['M'] = 1048576;
266a416e 2944 $scan['m'] = 1048576;
989bfa9d 2945 $scan['KB'] = 1024;
64efda84 2946 $scan['Kb'] = 1024;
989bfa9d 2947 $scan['K'] = 1024;
266a416e 2948 $scan['k'] = 1024;
989bfa9d 2949
2950 while (list($key) = each($scan)) {
2951 if ((strlen($size)>strlen($key))&&(substr($size, strlen($size) - strlen($key))==$key)) {
2952 $size = substr($size, 0, strlen($size) - strlen($key)) * $scan[$key];
2953 break;
2954 }
2955 }
2956 return $size;
2957}
2958
7cf1c7bd 2959/**
2960 * Converts bytes into display form
2961 *
c6d15803 2962 * @param string $size ?
2963 * @return string
89dcb99d 2964 * @staticvar string $gb Localized string for size in gigabytes
2965 * @staticvar string $mb Localized string for size in megabytes
2966 * @staticvar string $kb Localized string for size in kilobytes
2967 * @staticvar string $b Localized string for size in bytes
c6d15803 2968 * @todo Finish documenting this function. Verify return type.
7cf1c7bd 2969 */
44e2d2bb 2970function display_size($size) {
4909e176 2971
7cf1c7bd 2972 static $gb, $mb, $kb, $b;
4909e176 2973
2974 if (empty($gb)) {
2975 $gb = get_string('sizegb');
2976 $mb = get_string('sizemb');
2977 $kb = get_string('sizekb');
2978 $b = get_string('sizeb');
2979 }
2980
44e2d2bb 2981 if ($size >= 1073741824) {
4909e176 2982 $size = round($size / 1073741824 * 10) / 10 . $gb;
44e2d2bb 2983 } else if ($size >= 1048576) {
4909e176 2984 $size = round($size / 1048576 * 10) / 10 . $mb;
44e2d2bb 2985 } else if ($size >= 1024) {
4909e176 2986 $size = round($size / 1024 * 10) / 10 . $kb;
d8ba183c 2987 } else {
b0ccd3fb 2988 $size = $size .' '. $b;
44e2d2bb 2989 }
2990 return $size;
2991}
2992
7cf1c7bd 2993/**
8c3dba73 2994 * Cleans a given filename by removing suspicious or troublesome characters
2995 * Only these are allowed:
2996 * alphanumeric _ - .
7cf1c7bd 2997 *
c6d15803 2998 * @param string $string ?
2999 * @return string
7cf1c7bd 3000 * @todo Finish documenting this function
3001 */
6b174680 3002function clean_filename($string) {
b0ccd3fb 3003 $string = eregi_replace("\.\.+", '', $string);
8644437d 3004 $string = preg_replace('/[^\.a-zA-Z\d\_-]/','_', $string ); // only allowed chars
b0ccd3fb 3005 $string = eregi_replace("_+", '_', $string);
c6d15803 3006 return $string;
6b174680 3007}
3008
3009
1180c6dc 3010/// STRING TRANSLATION ////////////////////////////////////////
3011
8c3dba73 3012/**
3013 * Returns the code for the current language
3014 *
3015 * @uses $CFG
3016 * @param $USER
3017 * @param $SESSION
3018 * @return string
3019 */
4bfa92e7 3020function current_language() {
3db3acfb 3021 global $CFG, $USER, $SESSION;
4bfa92e7 3022
e5415d58 3023 if (!empty($CFG->courselang)) { // Course language can override all other settings for this page
b3153e4b 3024 return $CFG->courselang;
3025
e5415d58 3026 } else if (!empty($SESSION->lang)) { // Session language can override other settings
3db3acfb 3027 return $SESSION->lang;
3028
e5415d58 3029 } else if (!empty($USER->lang)) { // User language can override site language
4bfa92e7 3030 return $USER->lang;
3db3acfb 3031
4bfa92e7 3032 } else {
3033 return $CFG->lang;
3034 }
3035}
bcc83c41 3036
8c3dba73 3037/**
76115562 3038 * Prints out a translated string.
3039 *
3040 * Prints out a translated string using the return value from the {@link get_string()} function.
3041 *
3042 * Example usage of this function when the string is in the moodle.php file:<br>
3043 * <code>
3044 * echo '<strong>';
3045 * print_string('wordforstudent');
3046 * echo '</strong>';
3047 * </code>
3048 *
3049 * Example usage of this function when the string is not in the moodle.php file:<br>
3050 * <code>
3051 * echo '<h1>';
3052 * print_string('typecourse', 'calendar');
3053 * echo '</h1>';
3054 * </code>
3055 *
3056 * @param string $identifier The key identifier for the localized string
3057 * @param string $module The module where the key identifier is stored. If none is specified then moodle.php is used.
3058 * @param mixed $a An object, string or number that can be used
3059 * within translation strings
361855e6 3060 */
b0ccd3fb 3061function print_string($identifier, $module='', $a=NULL) {
9fa49e22 3062 echo get_string($identifier, $module, $a);
3063}
3064
8c3dba73 3065/**
76115562 3066 * Returns a localized string.
3067 *
3068 * Returns the translated string specified by $identifier as
8c3dba73 3069 * for $module. Uses the same format files as STphp.
3070 * $a is an object, string or number that can be used
3071 * within translation strings
3072 *
3073 * eg "hello \$a->firstname \$a->lastname"
3074 * or "hello \$a"
3075 *
76115562 3076 * If you would like to directly echo the localized string use
3077 * the function {@link print_string()}
3078 *
3079 * Example usage of this function involves finding the string you would
3080 * like a local equivalent of and using its identifier and module information
3081 * to retrive it.<br>
3082 * If you open moodle/lang/en/moodle.php and look near line 1031
3083 * you will find a string to prompt a user for their word for student
3084 * <code>
3085 * $string['wordforstudent'] = 'Your word for Student';
3086 * </code>
361855e6 3087 * So if you want to display the string 'Your word for student'
3088 * in any language that supports it on your site
76115562 3089 * you just need to use the identifier 'wordforstudent'
3090 * <code>
3091 * $mystring = '<strong>'. get_string('wordforstudent') .'</strong>';
3092or
3093 * </code>
361855e6 3094 * If the string you want is in another file you'd take a slightly
3095 * different approach. Looking in moodle/lang/en/calendar.php you find
76115562 3096 * around line 75:
3097 * <code>
3098 * $string['typecourse'] = 'Course event';
3099 * </code>
361855e6 3100 * If you want to display the string "Course event" in any language
3101 * supported you would use the identifier 'typecourse' and the module 'calendar'
76115562 3102 * (because it is in the file calendar.php):
3103 * <code>
3104 * $mystring = '<h1>'. get_string('typecourse', 'calendar') .'</h1>';
3105 * </code>
3106 *
3107 * As a last resort, should the identifier fail to map to a string
3108 * the returned string will be [[ $identifier ]]
3109 *
8c3dba73 3110 * @uses $CFG
76115562 3111 * @param string $identifier The key identifier for the localized string
3112 * @param string $module The module where the key identifier is stored. If none is specified then moodle.php is used.
3113 * @param mixed $a An object, string or number that can be used
3114 * within translation strings
3115 * @return string The localized string.
8c3dba73 3116 */
361855e6 3117function get_string($identifier, $module='', $a=NULL) {
1180c6dc 3118
4bfa92e7 3119 global $CFG;
1180c6dc 3120
e11dc9b6 3121 global $course; /// Not a nice hack, but quick
ac8abb5f 3122 if (empty($CFG->courselang)) {
3123 if (!empty($course->lang)) {
3124 $CFG->courselang = $course->lang;
3125 }
e11dc9b6 3126 }
3127
4bfa92e7 3128 $lang = current_language();
1180c6dc 3129
b0ccd3fb 3130 if ($module == '') {
3131 $module = 'moodle';
1180c6dc 3132 }
3133
d0dc2b98 3134/// Define the two or three major locations of language strings for this module
1180c6dc 3135
d0dc2b98 3136 $locations = array( $CFG->dataroot.'/lang/', $CFG->dirroot.'/lang/' );
3137 if ($module != 'moodle') {
3138 $locations[] = $CFG->dirroot .'/mod/'.$module.'/lang/';
1180c6dc 3139 }
3140
d0dc2b98 3141/// First check all the normal locations for the string in the current language
cdac797c 3142
d0dc2b98 3143 foreach ($locations as $location) {
dc0426bd 3144 $langfile = $location.$lang.'/'.$module.'.php';
cdac797c 3145 if (file_exists($langfile)) {
3146 if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
3147 eval($result);
3148 return $resultstring;
3149 }
3150 }
3151 }
1180c6dc 3152
d0dc2b98 3153/// If the preferred language was English we can abort now
b0ccd3fb 3154 if ($lang == 'en') {
3155 return '[['. $identifier .']]';
b947c69a 3156 }
1180c6dc 3157
d0dc2b98 3158/// Is a parent language defined? If so, try to find this string in a parent language file
d8ba183c 3159
d0dc2b98 3160 foreach ($locations as $location) {
dc0426bd 3161 $langfile = $location.$lang.'/moodle.php';
3162 if (file_exists($langfile)) {
3163 if ($result = get_string_from_file('parentlanguage', $langfile, "\$parentlang")) {
3164 eval($result);
3165 if (!empty($parentlang)) { // found it!
3166 $langfile = $location.$parentlang.'/'.$module.'.php';
3167 if (file_exists($langfile)) {
3168 if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
3169 eval($result);
3170 return $resultstring;
3171 }
d0dc2b98 3172 }
b947c69a 3173 }
1180c6dc 3174 }
3175 }
3176 }
b947c69a 3177
d0dc2b98 3178/// Our only remaining option is to try English
b947c69a 3179
d0dc2b98 3180 foreach ($locations as $location) {
dc0426bd 3181 $langfile = $location.'en/'.$module.'.php';
b947c69a 3182
cdac797c 3183 if (file_exists($langfile)) {
3184 if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
3185 eval($result);
3186 return $resultstring;
3187 }
3188 }
3189 }
3190
d0dc2b98 3191 return '[['.$identifier.']]'; // Last resort
1180c6dc 3192}
3193
8c3dba73 3194/**
c6d15803 3195 * This function is only used from {@link get_string()}.
8c3dba73 3196 *
da72d76d 3197 * @internal Only used from get_string, not meant to be public API
c6d15803 3198 * @param string $identifier ?
3199 * @param string $langfile ?
3200 * @param string $destination ?
3201 * @return string|false ?
89dcb99d 3202 * @staticvar array $strings Localized strings
da72d76d 3203 * @access private
c6d15803 3204 * @todo Finish documenting this function.
8c3dba73 3205 */
1180c6dc 3206function get_string_from_file($identifier, $langfile, $destination) {
2b32bddd 3207
3208 static $strings; // Keep the strings cached in memory.
3209
3210 if (empty($strings[$langfile])) {
a32c99e2 3211 $string = array();
2b32bddd 3212 include ($langfile);
3213 $strings[$langfile] = $string;
3214 } else {
3215 $string = &$strings[$langfile];
3216 }
1180c6dc 3217
3218 if (!isset ($string[$identifier])) {
3219 return false;
3220 }
3221
b0ccd3fb 3222 return $destination .'= sprintf("'. $string[$identifier] .'");';
1180c6dc 3223}
f9903ed0 3224
8c3dba73 3225/**
3226 * Converts an array of strings to their localized value.
3227 *
3228 * @param array $array An array of strings
3229 * @param string $module The language module that these strings can be found in.
3230 * @return string
3231 */
9d3c795c 3232function get_strings($array, $module='') {
9d3c795c 3233
3234 $string = NULL;
3235 foreach ($array as $item) {
3236 $string->$item = get_string($item, $module);
3237 }
3238 return $string;
3239}
f9903ed0 3240
8c3dba73 3241/**
3242 * Returns a list of language codes and their full names
3243 *
c6d15803 3244 * @uses $CFG
3245 * @return array An associative array with contents in the form of LanguageCode => LanguageName
8c3dba73 3246 * @todo Finish documenting this function
3247 */
1a72314d 3248function get_list_of_languages() {
1a72314d 3249 global $CFG;
3250
984a8bf3 3251 $languages = array();
3252
3253 if (!empty($CFG->langlist)) { // use admin's list of languages
3254 $langlist = explode(',', $CFG->langlist);
3255 foreach ($langlist as $lang) {
b0ccd3fb 3256 if (file_exists($CFG->dirroot .'/lang/'. $lang .'/moodle.php')) {
3257 include($CFG->dirroot .'/lang/'. $lang .'/moodle.php');
3258 $languages[$lang] = $string['thislanguage'].' ('. $lang .')';
984a8bf3 3259 unset($string);
3260 }
3261 }
3262 } else {
b0ccd3fb 3263 if (!$langdirs = get_list_of_plugins('lang')) {
984a8bf3 3264 return false;
3265 }
3266 foreach ($langdirs as $lang) {
40869b2e