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