removed $SESSION->encoding now replaced by current_charset() and $CFG->unicodedb...
[moodle.git] / lib / setup.php
1 <?php
2 /**
3  * setup.php - Sets up sessions, connects to databases and so on
4  *
5  * Normally this is only called by the main config.php file
6  * Normally this file does not need to be edited.
7  * @author Martin Dougiamas
8  * @version $Id$
9  * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
10  * @package moodlecore
11  */
13 ////// DOCUMENTATION IN PHPDOC FORMAT FOR MOODLE GLOBALS AND COMMON OBJECT TYPES /////////////
14 /**
15  * $USER is a global instance of a typical $user record.
16  *
17  * Items found in the user record:
18  *  - $USER->emailstop - Does the user want email sent to them?
19  *  - $USER->email - The user's email address.
20  *  - $USER->id - The unique integer identified of this user in the 'user' table.
21  *  - $USER->email - The user's email address.
22  *  - $USER->firstname - The user's first name.
23  *  - $USER->lastname - The user's last name.
24  *  - $USER->username - The user's login username.
25  *  - $USER->secret - The user's ?.
26  *  - $USER->lang - The user's language choice.
27  *
28  * @global object(user) $USER
29  */
30 global $USER;
31 /**
32  * This global variable is read in from the 'config' table.
33  *
34  * Some typical settings in the $CFG global:
35  *  - $CFG->wwwroot - Path to moodle index directory in url format.
36  *  - $CFG->dataroot - Path to moodle index directory on server's filesystem.
37  *  - $CFG->libroot  - Path to moodle's library folder on server's filesystem.
38  *
39  * @global object(cfg) $CFG
40  */
41 global $CFG;
42 /**
43  * Definition of session type
44  * @global object(session) $SESSION
45  */
46 global $SESSION;
47 /**
48  * Definition of course type
49  * @global object(course) $COURSE
50  */
51 global $COURSE;
52 /**
53  * Definition of db type
54  * @global object(db) $db
55  */
56 global $db;
57 /**
58  * $THEME is a global that defines the site theme.
59  *
60  * Items found in the theme record:
61  *  - $THEME->cellheading - Cell colors.
62  *  - $THEME->cellheading2 - Alternate cell colors.
63  *
64  * @global object(theme) $THEME
65  */
66 global $THEME;
68 /**
69  * HTTPSPAGEREQUIRED is a global to define if the page being displayed must run under HTTPS. 
70  * 
71  * It's primary goal is to allow 100% HTTPS pages when $CFG->loginhttps is enabled. Default to false.
72  * It's enabled only by the httpsrequired() function and used in some pages to update some URLs
73 */
74 global $HTTPSPAGEREQUIRED;
77 /// First try to detect some attacks on older buggy PHP versions
78     if (isset($_REQUEST['GLOBALS']) || isset($_COOKIE['GLOBALS']) || isset($_FILES['GLOBALS'])) {
79         die('Fatal: Illegal GLOBALS overwrite attempt detected!');
80     }
83     if (!isset($CFG->wwwroot)) {
84         trigger_error('Fatal: $CFG->wwwroot is not configured! Exiting.');
85         die;
86     }
88 /// Set httpswwwroot default value (this variable will replace $CFG->wwwroot
89 /// inside some URLs used in HTTPSPAGEREQUIRED pages.
90     $CFG->httpswwwroot = $CFG->wwwroot;
92     $CFG->libdir   = $CFG->dirroot .'/lib';
94     require_once($CFG->libdir .'/setuplib.php');        // Functions that MUST be loaded first
96 /// Time to start counting    
97     init_performance_info();        
98     
100 /// If there are any errors in the standard libraries we want to know!
101     error_reporting(E_ALL);
103 /// Just say no to link prefetching (Moz prefetching, Google Web Accelerator, others)
104 /// http://www.google.com/webmasters/faq.html#prefetchblock
105     if (!empty($_SERVER['HTTP_X_moz']) && $_SERVER['HTTP_X_moz'] === 'prefetch'){
106         header($_SERVER['SERVER_PROTOCOL'] . ' 404 Prefetch Forbidden');        
107         trigger_error('Prefetch request forbidden.');
108         exit;
109     }
111 /// Connect to the database using adodb
114     require_once($CFG->libdir .'/adodb/adodb.inc.php'); // Database access functions
116     $db = &ADONewConnection($CFG->dbtype);
118     error_reporting(0);  // Hide errors
120     if (!isset($CFG->dbpersist) or !empty($CFG->dbpersist)) {    // Use persistent connection (default)
121         $dbconnected = $db->PConnect($CFG->dbhost,$CFG->dbuser,$CFG->dbpass,$CFG->dbname);
122     } else {                                                     // Use single connection
123         $dbconnected = $db->Connect($CFG->dbhost,$CFG->dbuser,$CFG->dbpass,$CFG->dbname);
124     }
125     if (! $dbconnected) {
126         // In the name of protocol correctness, monitoring and performance
127         // profiling, set the appropriate error headers for machine comsumption
128         if (isset($_SERVER['SERVER_PROTOCOL'])) { 
129             // Avoid it with cron.php. Note that we assume it's HTTP/1.x
130             header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');        
131         }
132         // and then for human consumption...
133         echo '<html><body>';
134         echo '<table align="center"><tr>';
135         echo '<td style="color:#990000; text-align:center; font-size:large; border-width:1px; '.
136              '    border-color:#000000; border-style:solid; border-radius: 20px; border-collapse: collapse; '.
137              '    -moz-border-radius: 20px; padding: 15px">';
138         echo '<p>Error: Database connection failed.</p>';
139         echo '<p>It is possible that the database is overloaded or otherwise not running properly.</p>';
140         echo '<p>The site administrator should also check that the database details have been correctly specified in config.php</p>';
141         echo '</td></tr></table>';
142         echo '</body></html>';
144         if (!empty($CFG->emailconnectionerrorsto)) {
145             mail($CFG->emailconnectionerrorsto, 
146                  'WARNING: Database connection error: '.$CFG->wwwroot, 
147                  'Connection error: '.$CFG->wwwroot);
148         }
149         die;
150     }
152     /// Set the client/server and connection to utf8 if necessary
153     if ($dbconnected && $CFG->unicodedb) {
154         if ($db->databaseType == 'mysql') {
155             $db->Execute("SET NAMES 'utf8'");
156         } else if ($db->databaseType == 'postgres7') {
157             $db->Execute("SET NAMES 'utf8'");
158         }
159     }
161     error_reporting(E_ALL);       // Show errors from now on.
163     if (!isset($CFG->prefix)) {   // Just in case it isn't defined in config.php
164         $CFG->prefix = '';
165     }
168 /// Define admin directory
170     if (!isset($CFG->admin)) {   // Just in case it isn't defined in config.php
171         $CFG->admin = 'admin';   // This is relative to the wwwroot and dirroot
172     }
175 /// Load up standard libraries
176     
177     require_once($CFG->libdir .'/textlib.class.php');   // Functions to handle multibyte strings
178     require_once($CFG->libdir .'/weblib.php');          // Functions for producing HTML
179     require_once($CFG->libdir .'/datalib.php');         // Functions for accessing databases
180     require_once($CFG->libdir .'/moodlelib.php');       // Other general-purpose functions
183 /// Increase memory limits if possible
185     raise_memory_limit('64M');    // We should never NEED this much but just in case...
188 /// Load up any configuration from the config table
189     $CFG = get_config();
191 /// Turn on SQL logging if required
192     if (!empty($CFG->logsql)) {
193         $db->LogSQL();
194     }
197 /// Set error reporting back to normal
198     if (empty($CFG->debug)) {
199         $CFG->debug = 7;
200     }
201     error_reporting($CFG->debug);
204 /// Set a default enrolment configuration (see bug 1598)
205     if (!isset($CFG->enrol)) {
206         $CFG->enrol = 'manual';
207     }
209 /// Set default enabled enrolment plugins
210     if (!isset($CFG->enrol_plugins_enabled)) {
211         $CFG->enrol_plugins_enabled = 'manual';
212     }
214 /// File permissions on created directories in the $CFG->dataroot
216     if (empty($CFG->directorypermissions)) {
217         $CFG->directorypermissions = 0777;      // Must be octal (that's why it's here)
218     }
220 /// Setup cache dir for Smarty and others
221     if (!file_exists($CFG->dataroot .'/cache')) {
222         make_upload_directory('cache');
223     }
225 /// Set up smarty template system
226     //require_once($CFG->libdir .'/smarty/Smarty.class.php');
227     //$smarty = new Smarty;
228     //$smarty->template_dir = $CFG->dirroot .'/templates/'. $CFG->template;
229     //if (!file_exists($CFG->dataroot .'/cache/smarty')) {
230     //    make_upload_directory('cache/smarty');
231     //}
232     //$smarty->compile_dir = $CFG->dataroot .'/cache/smarty';
234 /// Set up session handling
235     if(empty($CFG->respectsessionsettings)) {
236         if (empty($CFG->dbsessions)) {   /// File-based sessions
238             // Some distros disable GC by setting probability to 0
239             // overriding the PHP default of 1
240             // (gc_probability is divided by gc_divisor, which defaults to 1000)
241             if (ini_get('session.gc_probability') == 0) {
242                 ini_set('session.gc_probability', 1);
243             }
245             if (!empty($CFG->sessiontimeout)) {
246                 ini_set('session.gc_maxlifetime', $CFG->sessiontimeout);
247             }
249             if (!file_exists($CFG->dataroot .'/sessions')) {
250                 make_upload_directory('sessions');
251             }
252             ini_set('session.save_path', $CFG->dataroot .'/sessions');
254         } else {                         /// Database sessions
255             ini_set('session.save_handler', 'user');
257             $ADODB_SESSION_DRIVER  = $CFG->dbtype;
258             $ADODB_SESSION_CONNECT = $CFG->dbhost;
259             $ADODB_SESSION_USER    = $CFG->dbuser;
260             $ADODB_SESSION_PWD     = $CFG->dbpass;
261             $ADODB_SESSION_DB      = $CFG->dbname;
262             $ADODB_SESSION_TBL     = $CFG->prefix.'sessions';
264             require_once($CFG->libdir. '/adodb/session/adodb-session.php');
265         }
266     }
267 /// Set sessioncookie variable if it isn't already
268     if (!isset($CFG->sessioncookie)) {
269         $CFG->sessioncookie = '';
270     }
272 /// Configure ampersands in URLs
274     @ini_set('arg_separator.output', '&amp;');
276 /// Location of standard files
278     $CFG->wordlist    = $CFG->libdir .'/wordlist.txt';
279     $CFG->javascript  = $CFG->libdir .'/javascript.php';
280     $CFG->moddata     = 'moddata';
283 /// A hack to get around magic_quotes_gpc being turned off
284 /// It is strongly recommended to enable "magic_quotes_gpc"!
286     if (!ini_get_bool('magic_quotes_gpc') ) {
287         function addslashes_deep($value) {
288             $value = is_array($value) ?
289                     array_map('addslashes_deep', $value) :
290                     addslashes($value);
291             return $value;
292         }
293         $_POST = array_map('addslashes_deep', $_POST);
294         $_GET = array_map('addslashes_deep', $_GET);
295         $_COOKIE = array_map('addslashes_deep', $_COOKIE);
296         $_REQUEST = array_map('addslashes_deep', $_REQUEST);
297         if (!empty($_SERVER['REQUEST_URI'])) {
298             $_SERVER['REQUEST_URI'] = addslashes($_SERVER['REQUEST_URI']);
299         }
300         if (!empty($_SERVER['QUERY_STRING'])) {
301             $_SERVER['QUERY_STRING'] = addslashes($_SERVER['QUERY_STRING']);
302         }
303         if (!empty($_SERVER['HTTP_REFERER'])) {
304             $_SERVER['HTTP_REFERER'] = addslashes($_SERVER['HTTP_REFERER']);
305         }
306        if (!empty($_SERVER['PATH_INFO'])) {
307             $_SERVER['PATH_INFO'] = addslashes($_SERVER['PATH_INFO']);
308         }
309         if (!empty($_SERVER['PHP_SELF'])) {
310             $_SERVER['PHP_SELF'] = addslashes($_SERVER['PHP_SELF']);
311         }
312         if (!empty($_SERVER['PATH_TRANSLATED'])) {
313             $_SERVER['PATH_TRANSLATED'] = addslashes($_SERVER['PATH_TRANSLATED']);
314         }
315     }
318 /// The following is a hack to get around the problem of PHP installations
319 /// that have "register_globals" turned off (default since PHP 4.1.0).
320 /// This hack will be removed in 1.6.
321 /// It is strongly recommended to disable "register_globals"!
322 /// $CFG->disableglobalshack=true in config.php will override this (for dev testing)
324     if (empty($CFG->disableglobalshack)) {
325         if (!empty($CFG->detect_unchecked_vars)) {
326             global $UNCHECKED_VARS;
327             $UNCHECKED_VARS->url = $_SERVER['PHP_SELF'];
328             $UNCHECKED_VARS->vars = array();
329         }
330     
331         if (isset($_GET)) {
332             extract($_GET, EXTR_SKIP);    // Skip existing variables, ie CFG
333             if (!empty($CFG->detect_unchecked_vars)) {
334                 foreach ($_GET as $key => $val) {
335                     $UNCHECKED_VARS->vars[$key]=$val;
336                 }
337             }
338         }
339         if (isset($_POST)) {
340             extract($_POST, EXTR_SKIP);   // Skip existing variables, ie CFG
341             if (!empty($CFG->detect_unchecked_vars)) {
342                 foreach ($_POST as $key => $val) {
343                     $UNCHECKED_VARS->vars[$key]=$val;
344                 }
345             }
346         }
347         if (isset($_SERVER)) {
348             extract($_SERVER);
349         }
350     }
353 /// Load up global environment variables
355     class object {};
357     //discard session ID from POST, GET and globals to tighten security,
358     //this session fixation prevention can not be used in cookieless mode
359     if (empty($CFG->usesid)) {
360         unset(${'MoodleSession'.$CFG->sessioncookie});
361         unset($_GET['MoodleSession'.$CFG->sessioncookie]);
362         unset($_POST['MoodleSession'.$CFG->sessioncookie]);
363     }
364     //compatibility hack for Moodle Cron, cookies not deleted, but set to "deleted"
365     if (!empty($_COOKIE['MoodleSession'.$CFG->sessioncookie]) && $_COOKIE['MoodleSession'.$CFG->sessioncookie] == "deleted") {
366         unset($_COOKIE['MoodleSession'.$CFG->sessioncookie]);
367     }
368     if (!empty($_COOKIE['MoodleSessionTest'.$CFG->sessioncookie]) && $_COOKIE['MoodleSessionTest'.$CFG->sessioncookie] == "deleted") {
369         unset($_COOKIE['MoodleSessionTest'.$CFG->sessioncookie]);
370     }
371     if (!empty($CFG->usesid) && empty($_COOKIE['MoodleSession'.$CFG->sessioncookie])) {
372         require_once("$CFG->dirroot/lib/cookieless.php");
373         sid_start_ob();
374     }
376     if (!isset($nomoodlecookie)) {
377         session_name('MoodleSession'.$CFG->sessioncookie);
378         @session_start();
379         if (! isset($_SESSION['SESSION'])) {
380             $_SESSION['SESSION'] = new object;
381             $_SESSION['SESSION']->session_test = random_string(10);
382             if (!empty($_COOKIE['MoodleSessionTest'.$CFG->sessioncookie])) {
383                 $_SESSION['SESSION']->has_timed_out = true;
384             }
385             setcookie('MoodleSessionTest'.$CFG->sessioncookie, $_SESSION['SESSION']->session_test, 0, '/');
386             $_COOKIE['MoodleSessionTest'.$CFG->sessioncookie] = $_SESSION['SESSION']->session_test;
387         }
388         if (! isset($_SESSION['USER']))    {
389             $_SESSION['USER']    = new object;
390         }
392         $SESSION = &$_SESSION['SESSION'];   // Makes them easier to reference
393         $USER    = &$_SESSION['USER'];
394     }
395     else {
396         $SESSION = NULL;
397         $USER    = NULL;
398     }
400     if (defined('FULLME')) {     // Usually in command-line scripts like admin/cron.php
401         $FULLME = FULLME;
402         $ME = FULLME;
403     } else {
404         $FULLME = qualified_me();
405         $ME = strip_querystring($FULLME);
406     }
408 /// In VERY rare cases old PHP server bugs (it has been found on PHP 4.1.2 running
409 /// as a CGI under IIS on Windows) may require that you uncomment the following:
410 //  session_register("USER");
411 //  session_register("SESSION");
415 /// Load up theme variables (colours etc)
417     if (!isset($CFG->themedir)) {
418         $CFG->themedir = $CFG->dirroot.'/theme/';
419         $CFG->themewww = $CFG->wwwroot.'/theme/';
420     }
422     if (isset($_GET['theme'])) {
423         if ($CFG->allowthemechangeonurl || confirm_sesskey()) {
424             if (!detect_munged_arguments($_GET['theme'], 0) and file_exists($CFG->themedir. $_GET['theme'])) {
425                 $SESSION->theme = $_GET['theme'];
426             }
427         }
428     }
430     if (!isset($CFG->theme)) {
431         $CFG->theme = 'standardwhite';
432     }
434     theme_setup();  // Sets up theme global variables
436 /// now do a session test to prevent random user switching - observed on some PHP/Apache combinations,
437 /// disable checks when working in cookieless mode
438     if (empty($CFG->usesid) || !empty($_COOKIE['MoodleSession'.$CFG->sessioncookie])) {
439         if ($SESSION != NULL) {
440             if (empty($_COOKIE['MoodleSessionTest'.$CFG->sessioncookie])) {
441                 report_session_error();
442             } else if (isset($SESSION->session_test) && $_COOKIE['MoodleSessionTest'.$CFG->sessioncookie] != $SESSION->session_test) {
443                 report_session_error();
444             }
445         }
446     }
450 /// Set language/locale of printed times.  If user has chosen a language that
451 /// that is different from the site language, then use the locale specified
452 /// in the language file.  Otherwise, if the admin hasn't specified a locale
453 /// then use the one from the default language.  Otherwise (and this is the
454 /// majority of cases), use the stored locale specified by admin.
456     if (isset($_GET['lang'])) {
457         if (!detect_munged_arguments($lang, 0) and (file_exists($CFG->dataroot .'/lang/'. $lang) or 
458                                                     file_exists($CFG->dirroot .'/lang/'. $lang))) {
459             $SESSION->lang = $lang;
460         }
461     }
462     if (empty($CFG->lang)) {
463         $CFG->lang = !empty($CFG->unicodedb) ? 'en_utf8' : 'en';
464     }
466     moodle_setlocale();
468     if (!empty($CFG->opentogoogle)) {
469         if (empty($_SESSION['USER'])) {
470             if (!empty($_SERVER['HTTP_USER_AGENT'])) {
471                 if (strpos($_SERVER['HTTP_USER_AGENT'], 'Googlebot') !== false ) {
472                     $USER = guest_user();
473                 }
474                 if (strpos($_SERVER['HTTP_USER_AGENT'], 'google.com') !== false ) {
475                     $USER = guest_user();
476                 }
477             }
478             if (empty($_SESSION['USER']) and !empty($_SERVER['HTTP_REFERER'])) {
479                 if (strpos($_SERVER['HTTP_REFERER'], 'google') !== false ) {
480                     $USER = guest_user();
481                 } else if (strpos($_SERVER['HTTP_REFERER'], 'altavista') !== false ) {
482                     $USER = guest_user();
483                 }
484             }
485         }
486     }
488     if ($CFG->theme == 'standard' or $CFG->theme == 'standardwhite') {    // Temporary measure to help with XHTML validation
489         if (empty($_SESSION['USER']->id)) {      // Allow W3CValidator in as user called w3cvalidator (or guest)
490             if ((strpos($_SERVER['HTTP_USER_AGENT'], 'W3C_Validator') !== false) or
491                 (strpos($_SERVER['HTTP_USER_AGENT'], 'Cynthia') !== false )) {
492                 if ($USER = get_complete_user_data("username", "w3cvalidator")) {
493                     $USER->ignoresesskey = true;
494                 } else {
495                     $USER = guest_user();
496                 }
497             }
498         }
499     }
501 /// Apache log intergration. In apache conf file one can use ${MOODULEUSER}n in
502 /// LogFormat to get the current logged in username in moodle.
503     if ($USER && function_exists('apache_note') && !empty($CFG->apacheloguser)) {
504         $apachelog_username = clean_filename($USER->username);
505         $apachelog_name = clean_filename($USER->firstname. " ".$USER->lastname);
506         $apachelog_userid = $USER->id;
507         if (isset($USER->realuser)) {
508             if ($realuser = get_record('user', 'id', $USER->realuser)) {
509                 $apachelog_username = clean_filename($realuser->username." as ".$apachelog_username);
510                 $apachelog_name = clean_filename($realuser->firstname." ".$realuser->lastname ." as ".$apachelog_name);
511                 $apachelog_userid = clean_filename($realuser->id." as ".$apachelog_userid);
512             }
513         }
514         switch ($CFG->apacheloguser) {
515             case 3:
516                 $logname = $apachelog_username;
517                 break;
518             case 2:
519                 $logname = $apachelog_name;
520                 break;
521             case 1:
522             default:
523                 $logname = $apachelog_userid;
524                 break;
525         }
526         apache_note('MOODLEUSER', $logname);
527     }
529 /// Adjust ALLOWED_TAGS
530     adjust_allowed_tags();
533 /// Use a custom script replacement if one exists
534     if (!empty($CFG->customscripts)) {
535         if (($customscript = custom_script_path()) !== false) {
536             require ($customscript);
537         }
538     }
541 ?>