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