2009-05-26 03:57:03 +00:00
< ? php
2006-01-05 07:08:10 +00:00
2009-05-26 03:57:03 +00:00
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* These functions are required very early in the Moodle
* setup process , before any of the main libraries are
* loaded .
2009-10-31 14:17:44 +00:00
*
2009-05-26 03:57:03 +00:00
* @ package moodlecore
* @ copyright 1999 onwards Martin Dougiamas { @ link http :// moodle . com }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
*/
2006-01-05 07:08:10 +00:00
2009-06-29 05:00:45 +00:00
/// Debug levels ///
/** no warnings at all */
define ( 'DEBUG_NONE' , 0 );
/** E_ERROR | E_PARSE */
define ( 'DEBUG_MINIMAL' , 5 );
/** E_ERROR | E_PARSE | E_WARNING | E_NOTICE */
define ( 'DEBUG_NORMAL' , 15 );
/** E_ALL without E_STRICT for now, do show recoverable fatal errors */
define ( 'DEBUG_ALL' , 6143 );
/** DEBUG_ALL with extra Moodle debug messages - (DEBUG_ALL | 32768) */
define ( 'DEBUG_DEVELOPER' , 38911 );
2008-01-20 17:59:26 +00:00
/**
2009-09-08 07:09:01 +00:00
* Simple class . It is usually used instead of stdClass because it looks
2009-11-01 10:05:07 +00:00
* more familiar to Java developers ; - ) Do not use for type checking of
2009-09-08 07:09:01 +00:00
* function parameters .
2009-05-26 03:57:03 +00:00
*
* @ package moodlecore
* @ copyright 1999 onwards Martin Dougiamas { @ link http :// moodle . com }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2008-01-20 17:59:26 +00:00
*/
2009-09-08 07:09:01 +00:00
class object extends stdClass {};
2008-01-20 17:59:26 +00:00
2008-06-13 17:51:34 +00:00
/**
* Base Moodle Exception class
2009-05-26 03:57:03 +00:00
*
2009-06-29 05:00:45 +00:00
* Although this class is defined here , you cannot throw a moodle_exception until
* after moodlelib . php has been included ( which will happen very soon ) .
*
2009-05-26 03:57:03 +00:00
* @ package moodlecore
* @ copyright 1999 onwards Martin Dougiamas { @ link http :// moodle . com }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2008-06-13 17:51:34 +00:00
*/
class moodle_exception extends Exception {
public $errorcode ;
public $module ;
public $a ;
public $link ;
2008-06-22 16:51:55 +00:00
public $debuginfo ;
2008-06-13 17:51:34 +00:00
/**
* Constructor
* @ param string $errorcode The name of the string from error . php to print
* @ param string $module name of module
* @ param string $link The url where the user will be prompted to continue . If no url is provided the user will be directed to the site index page .
* @ param object $a Extra words and phrases that might be required in the error string
2008-06-22 16:51:55 +00:00
* @ param string $debuginfo optional debugging information
2008-06-13 17:51:34 +00:00
*/
2008-09-02 06:03:37 +00:00
function __construct ( $errorcode , $module = '' , $link = '' , $a = NULL , $debuginfo = null ) {
if ( empty ( $module ) || $module == 'moodle' || $module == 'core' ) {
2008-06-13 17:51:34 +00:00
$module = 'error' ;
}
2008-09-02 06:03:37 +00:00
$this -> errorcode = $errorcode ;
$this -> module = $module ;
$this -> link = $link ;
$this -> a = $a ;
$this -> debuginfo = $debuginfo ;
2008-06-13 17:51:34 +00:00
2010-05-18 11:58:53 +00:00
if ( get_string_manager () -> string_exists ( $errorcode , $module )) {
$message = get_string ( $errorcode , $module , $a );
} else {
$message = $module . '/' . $errorcode ;
}
2008-06-13 17:51:34 +00:00
parent :: __construct ( $message , 0 );
}
}
2010-02-05 04:10:36 +00:00
/**
* Web service parameter exception class
*
* This exception must be thrown to the web service client when a web service parameter is invalid
* The error string is gotten from webservice . php
*/
class webservice_parameter_exception extends moodle_exception {
/**
* Constructor
* @ param string $errorcode The name of the string from webservice . php to print
* @ param string $a The name of the parameter
*/
function __construct ( $errorcode = null , $a = '' ) {
parent :: __construct ( $errorcode , 'webservice' , '' , $a , null );
}
}
2009-09-14 23:52:08 +00:00
/**
* Exceptions indicating user does not have permissions to do something
* and the execution can not continue .
*/
class required_capability_exception extends moodle_exception {
function __construct ( $context , $capability , $errormessage , $stringfile ) {
$capabilityname = get_capability_string ( $capability );
parent :: __construct ( $errormessage , $stringfile , get_context_url ( $context ), $capabilityname );
}
}
2008-10-28 15:11:10 +00:00
/**
2009-05-08 07:47:02 +00:00
* Exception indicating programming error , must be fixed by a programer . For example
* a core API might throw this type of exception if a plugin calls it incorrectly .
2009-05-26 03:57:03 +00:00
*
* @ package moodlecore
* @ copyright 1999 onwards Martin Dougiamas { @ link http :// moodle . com }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2008-10-28 15:11:10 +00:00
*/
class coding_exception extends moodle_exception {
/**
* Constructor
* @ param string $hint short description of problem
* @ param string $debuginfo detailed information how to fix problem
*/
function __construct ( $hint , $debuginfo = null ) {
parent :: __construct ( 'codingerror' , 'debug' , '' , $hint , $debuginfo );
2009-09-15 20:08:47 +00:00
}
}
/**
* Exception indicating malformed parameter problem .
* This exception is not supposed to be thrown when processing
* user submitted data in forms . It is more suitable
* for WS and other low level stuff .
*/
class invalid_parameter_exception extends moodle_exception {
/**
* Constructor
* @ param string $debuginfo some detailed information
*/
function __construct ( $debuginfo = null ) {
parent :: __construct ( 'invalidparameter' , 'debug' , '' , null , $debuginfo );
2008-10-28 15:11:10 +00:00
}
}
2010-02-22 07:07:44 +00:00
/**
* Exception indicating malformed response problem .
* This exception is not supposed to be thrown when processing
* user submitted data in forms . It is more suitable
* for WS and other low level stuff .
*/
class invalid_response_exception extends moodle_exception {
/**
* Constructor
* @ param string $debuginfo some detailed information
*/
function __construct ( $debuginfo = null ) {
parent :: __construct ( 'invalidresponse' , 'debug' , '' , null , $debuginfo );
}
}
2009-05-08 07:47:02 +00:00
/**
2009-11-01 10:05:07 +00:00
* An exception that indicates something really weird happened . For example ,
2009-05-08 07:47:02 +00:00
* if you do switch ( $context -> contextlevel ), and have one case for each
* CONTEXT_ ... constant . You might throw an invalid_state_exception in the
2009-05-11 17:13:45 +00:00
* default case , to just in case something really weird is going on , and
2009-05-11 17:11:29 +00:00
* $context -> contextlevel is invalid - rather than ignoring this possibility .
2009-05-26 03:57:03 +00:00
*
* @ package moodlecore
* @ copyright 1999 onwards Martin Dougiamas { @ link http :// moodle . com }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2009-05-08 07:47:02 +00:00
*/
class invalid_state_exception extends moodle_exception {
/**
* Constructor
* @ param string $hint short description of problem
* @ param string $debuginfo optional more detailed information
*/
function __construct ( $hint , $debuginfo = null ) {
parent :: __construct ( 'invalidstatedetected' , 'debug' , '' , $hint , $debuginfo );
}
}
2008-06-13 17:51:34 +00:00
/**
2009-11-01 10:05:07 +00:00
* Default exception handler , uncaught exceptions are equivalent to error () in 1.9 and earlier
2009-06-29 00:34:49 +00:00
*
2009-10-31 14:17:44 +00:00
* @ param Exception $ex
2009-10-31 13:52:39 +00:00
* @ return void - does not return . Terminates execution !
2008-06-13 17:51:34 +00:00
*/
2009-10-31 13:52:39 +00:00
function default_exception_handler ( $ex ) {
2009-11-01 09:58:04 +00:00
global $DB , $OUTPUT ;
2009-06-12 10:59:28 +00:00
// detect active db transactions, rollback and log as error
2009-11-01 09:58:04 +00:00
abort_all_db_transactions ();
2008-10-28 15:21:01 +00:00
2009-10-31 13:52:39 +00:00
$info = get_exception_info ( $ex );
2009-06-26 09:06:16 +00:00
2009-10-31 13:52:39 +00:00
if ( debugging ( '' , DEBUG_MINIMAL )) {
2009-10-31 22:02:05 +00:00
$logerrmsg = " Default exception handler: " . $info -> message . ' Debug: ' . $info -> debuginfo . " \n " . format_backtrace ( $info -> backtrace , true );
2009-11-01 09:58:04 +00:00
error_log ( $logerrmsg );
2009-06-29 00:34:49 +00:00
}
2009-10-31 13:52:39 +00:00
if ( is_early_init ( $info -> backtrace )) {
echo bootstrap_renderer :: early_error ( $info -> message , $info -> moreinfourl , $info -> link , $info -> backtrace , $info -> debuginfo );
2009-07-01 05:54:26 +00:00
} else {
2009-10-31 15:01:25 +00:00
try {
2009-11-01 10:00:30 +00:00
if ( $DB ) {
// If you enable db debugging and exception is thrown, the print footer prints a lot of rubbish
$DB -> set_debug ( 0 );
}
2009-10-31 15:01:25 +00:00
echo $OUTPUT -> fatal_error ( $info -> message , $info -> moreinfourl , $info -> link , $info -> backtrace , $info -> debuginfo );
} catch ( Exception $out_ex ) {
// default exception handler MUST not throw any exceptions!!
2009-10-31 22:02:05 +00:00
// the problem here is we do not know if page already started or not, we only know that somebody messed up in outputlib or theme
2009-10-31 15:01:25 +00:00
// so we just print at least something instead of "Exception thrown without a stack frame in Unknown on line 0":-(
2010-03-28 09:05:47 +00:00
if ( CLI_SCRIPT or AJAX_SCRIPT ) {
// just ignore the error and send something back using the safest method
echo bootstrap_renderer :: early_error ( $info -> message , $info -> moreinfourl , $info -> link , $info -> backtrace , $info -> debuginfo );
} else {
echo bootstrap_renderer :: early_error_content ( $info -> message , $info -> moreinfourl , $info -> link , $info -> backtrace , $info -> debuginfo );
$outinfo = get_exception_info ( $out_ex );
echo bootstrap_renderer :: early_error_content ( $outinfo -> message , $outinfo -> moreinfourl , $outinfo -> link , $outinfo -> backtrace , $outinfo -> debuginfo );
}
2009-10-31 15:01:25 +00:00
}
2009-06-30 05:34:50 +00:00
}
2009-06-26 09:06:16 +00:00
exit ( 1 ); // General error code
}
2009-11-01 09:58:04 +00:00
/**
* Unconditionally abort all database transactions , this function
* should be called from exception handlers only .
* @ return void
*/
function abort_all_db_transactions () {
global $CFG , $DB , $SCRIPT ;
2009-11-07 08:52:56 +00:00
// default exception handler MUST not throw any exceptions!!
2009-11-09 11:33:14 +00:00
2009-11-01 09:58:04 +00:00
if ( $DB && $DB -> is_transaction_started ()) {
error_log ( 'Database transaction aborted automatically in ' . $CFG -> dirroot . $SCRIPT );
2009-11-07 08:52:56 +00:00
// note: transaction blocks should never change current $_SESSION
$DB -> force_transaction_rollback ();
2009-11-01 09:58:04 +00:00
}
}
2009-07-01 05:54:26 +00:00
/**
2009-10-30 13:44:07 +00:00
* This function encapsulates the tests for whether an exception was thrown in
* early init -- either during setup . php or during init of $OUTPUT .
2009-07-01 05:54:26 +00:00
*
* If another exception is thrown then , and if we do not take special measures ,
* we would just get a very cryptic message " Exception thrown without a stack
* frame in Unknown on line 0 " . That makes debugging very hard, so we do take
* special measures in default_exception_handler , with the help of this function .
*
* @ param array $backtrace the stack trace to analyse .
* @ return boolean whether the stack trace is somewhere in output initialisation .
*/
2009-10-30 13:44:07 +00:00
function is_early_init ( $backtrace ) {
2009-07-01 05:54:26 +00:00
$dangerouscode = array (
array ( 'function' => 'header' , 'type' => '->' ),
array ( 'class' => 'bootstrap_renderer' ),
2009-10-30 13:44:07 +00:00
array ( 'file' => dirname ( __FILE__ ) . '/setup.php' ),
2009-07-01 05:54:26 +00:00
);
foreach ( $backtrace as $stackframe ) {
foreach ( $dangerouscode as $pattern ) {
$matches = true ;
foreach ( $pattern as $property => $value ) {
if ( ! isset ( $stackframe [ $property ]) || $stackframe [ $property ] != $value ) {
$matches = false ;
}
}
if ( $matches ) {
return true ;
}
}
}
return false ;
}
2009-06-26 09:06:16 +00:00
/**
2009-10-31 13:23:29 +00:00
* Abort execution by throwing of a general exception ,
* default exception handler displays the error message in most cases .
2009-06-26 09:06:16 +00:00
*
* @ param string $errorcode The name of the language string containing the error message .
* Normally this should be in the error . php lang file .
* @ param string $module The language file to get the error message from .
* @ param string $link The url where the user will be prompted to continue .
* If no url is provided the user will be directed to the site index page .
* @ param object $a Extra words and phrases that might be required in the error string
2009-10-31 13:23:29 +00:00
* @ param string $debuginfo optional debugging information
* @ return void , always throws exception !
2009-06-26 09:06:16 +00:00
*/
2009-10-31 13:23:29 +00:00
function print_error ( $errorcode , $module = 'error' , $link = '' , $a = null , $debuginfo = null ) {
throw new moodle_exception ( $errorcode , $module , $link , $a , $debuginfo );
2009-06-26 09:06:16 +00:00
}
/**
2009-10-31 13:52:39 +00:00
* Returns detailed information about specified exception .
* @ param exception $ex
* @ return object
2009-06-26 09:06:16 +00:00
*/
2009-10-31 13:52:39 +00:00
function get_exception_info ( $ex ) {
2009-06-26 09:06:16 +00:00
global $CFG , $DB , $SESSION ;
2009-10-31 13:52:39 +00:00
if ( $ex instanceof moodle_exception ) {
$errorcode = $ex -> errorcode ;
$module = $ex -> module ;
$a = $ex -> a ;
$link = $ex -> link ;
$debuginfo = $ex -> debuginfo ;
} else {
$errorcode = 'generalexceptionmessage' ;
$module = 'error' ;
$a = $ex -> getMessage ();
$link = '' ;
$debuginfo = null ;
2009-06-26 09:06:16 +00:00
}
2009-10-31 13:52:39 +00:00
$backtrace = $ex -> getTrace ();
$place = array ( 'file' => $ex -> getFile (), 'line' => $ex -> getLine (), 'exception' => get_class ( $ex ));
array_unshift ( $backtrace , $place );
2009-06-29 05:00:45 +00:00
// Be careful, no guarantee moodlelib.php is loaded.
2009-06-26 09:06:16 +00:00
if ( empty ( $module ) || $module == 'moodle' || $module == 'core' ) {
$module = 'error' ;
}
2010-05-18 11:58:53 +00:00
if ( function_exists ( 'get_string_manager' )) {
if ( get_string_manager () -> string_exists ( $errorcode , $module )) {
$message = get_string ( $errorcode , $module , $a );
} elseif ( $module == 'error' && get_string_manager () -> string_exists ( $errorcode , 'moodle' )) {
2009-06-29 05:00:45 +00:00
// Search in moodle file if error specified - needed for backwards compatibility
$message = get_string ( $errorcode , 'moodle' , $a );
2010-05-18 11:58:53 +00:00
} else {
$message = $module . '/' . $errorcode ;
2009-06-29 05:00:45 +00:00
}
} else {
$message = $module . '/' . $errorcode ;
}
// Be careful, no guarantee weblib.php is loaded.
if ( function_exists ( 'clean_text' )) {
$message = clean_text ( $message );
} else {
$message = htmlspecialchars ( $message );
2009-06-26 09:06:16 +00:00
}
if ( ! empty ( $CFG -> errordocroot )) {
$errordocroot = $CFG -> errordocroot ;
} else if ( ! empty ( $CFG -> docroot )) {
$errordocroot = $CFG -> docroot ;
} else {
$errordocroot = 'http://docs.moodle.org' ;
}
if ( $module === 'error' ) {
$modulelink = 'moodle' ;
2009-05-07 05:38:35 +00:00
} else {
2009-06-26 09:06:16 +00:00
$modulelink = $module ;
2008-06-13 17:51:34 +00:00
}
2009-06-26 09:06:16 +00:00
$moreinfourl = $errordocroot . '/en/error/' . $modulelink . '/' . $errorcode ;
2009-07-09 07:35:03 +00:00
if ( empty ( $link )) {
2009-06-26 09:06:16 +00:00
if ( ! empty ( $SESSION -> fromurl )) {
$link = $SESSION -> fromurl ;
unset ( $SESSION -> fromurl );
} else {
$link = $CFG -> wwwroot . '/' ;
}
}
2009-10-31 13:52:39 +00:00
$info = new object ();
$info -> message = $message ;
$info -> errorcode = $errorcode ;
$info -> backtrace = $backtrace ;
$info -> link = $link ;
$info -> moreinfourl = $moreinfourl ;
$info -> a = $a ;
$info -> debuginfo = $debuginfo ;
2009-10-31 14:17:44 +00:00
2009-10-31 13:52:39 +00:00
return $info ;
2009-06-26 09:06:16 +00:00
}
/**
* Formats a backtrace ready for output .
*
* @ param array $callers backtrace array , as returned by debug_backtrace () .
* @ param boolean $plaintext if false , generates HTML , if true generates plain text .
* @ return string formatted backtrace , ready for output .
*/
function format_backtrace ( $callers , $plaintext = false ) {
2009-10-15 22:34:34 +00:00
// do not use $CFG->dirroot because it might not be available in destructors
2009-06-26 09:06:16 +00:00
$dirroot = dirname ( dirname ( __FILE__ ));
2009-10-31 14:17:44 +00:00
2009-06-26 09:06:16 +00:00
if ( empty ( $callers )) {
return '' ;
}
$from = $plaintext ? '' : '<ul style="text-align: left">' ;
foreach ( $callers as $caller ) {
if ( ! isset ( $caller [ 'line' ])) {
$caller [ 'line' ] = '?' ; // probably call_user_func()
}
if ( ! isset ( $caller [ 'file' ])) {
$caller [ 'file' ] = 'unknownfile' ; // probably call_user_func()
}
$from .= $plaintext ? '* ' : '<li>' ;
$from .= 'line ' . $caller [ 'line' ] . ' of ' . str_replace ( $dirroot , '' , $caller [ 'file' ]);
if ( isset ( $caller [ 'function' ])) {
$from .= ': call to ' ;
if ( isset ( $caller [ 'class' ])) {
$from .= $caller [ 'class' ] . $caller [ 'type' ];
}
$from .= $caller [ 'function' ] . '()' ;
} else if ( isset ( $caller [ 'exception' ])) {
$from .= ': ' . $caller [ 'exception' ] . ' thrown' ;
}
$from .= $plaintext ? " \n " : '</li>' ;
}
$from .= $plaintext ? '' : '</ul>' ;
return $from ;
2008-06-13 17:51:34 +00:00
}
2008-01-20 17:59:26 +00:00
2009-02-01 13:37:42 +00:00
/**
* This function verifies the sanity of PHP configuration
* and stops execution if anything critical found .
*/
function setup_validate_php_configuration () {
// this must be very fast - no slow checks here!!!
if ( ini_get_bool ( 'register_globals' )) {
print_error ( 'globalswarning' , 'admin' );
}
if ( ini_get_bool ( 'session.auto_start' )) {
print_error ( 'sessionautostartwarning' , 'admin' );
}
if ( ini_get_bool ( 'magic_quotes_runtime' )) {
print_error ( 'fatalmagicquotesruntime' , 'admin' );
}
}
2010-05-19 13:30:13 +00:00
/**
* Initialise global $CFG variable
* @ return void
*/
function initialise_cfg () {
global $CFG , $DB ;
try {
if ( $DB ) {
$localcfg = $DB -> get_records_menu ( 'config' , array (), '' , 'name,value' );
foreach ( $localcfg as $name => $value ) {
if ( property_exists ( $CFG , $name )) {
// config.php settings always take precedence
continue ;
}
$CFG -> { $name } = $value ;
}
}
} catch ( dml_read_exception $e ) {
// most probably empty db, going to install soon
}
}
2009-01-05 21:37:20 +00:00
/**
2009-05-06 08:50:32 +00:00
* Initialises $FULLME and friends . Private function . Should only be called from
* setup . php .
2009-01-05 21:37:20 +00:00
*/
function initialise_fullme () {
global $CFG , $FULLME , $ME , $SCRIPT , $FULLSCRIPT ;
2009-05-06 08:50:32 +00:00
// Detect common config error.
2009-01-07 15:31:54 +00:00
if ( substr ( $CFG -> wwwroot , - 1 ) == '/' ) {
print_error ( 'wwwrootslash' , 'error' );
}
2009-05-06 08:50:32 +00:00
if ( CLI_SCRIPT ) {
initialise_fullme_cli ();
return ;
2009-01-07 09:54:09 +00:00
}
2009-01-05 21:37:20 +00:00
2009-05-06 08:50:32 +00:00
$wwwroot = parse_url ( $CFG -> wwwroot );
if ( ! isset ( $wwwroot [ 'path' ])) {
$wwwroot [ 'path' ] = '' ;
}
$wwwroot [ 'path' ] .= '/' ;
$rurl = setup_get_remote_url ();
2009-01-05 21:37:20 +00:00
2009-05-06 08:50:32 +00:00
// Check that URL is under $CFG->wwwroot.
if ( strpos ( $rurl [ 'path' ], $wwwroot [ 'path' ]) === 0 ) {
$SCRIPT = substr ( $rurl [ 'path' ], strlen ( $wwwroot [ 'path' ]) - 1 );
} else {
// Probably some weird external script
$SCRIPT = $FULLSCRIPT = $FULLME = $ME = null ;
2009-01-05 21:37:20 +00:00
return ;
}
2009-05-06 08:50:32 +00:00
// $CFG->sslproxy specifies if external SSL appliance is used
// (That is, the Moodle server uses http, with an external box translating everything to https).
if ( empty ( $CFG -> sslproxy )) {
if ( $rurl [ 'scheme' ] == 'http' and $wwwroot [ 'scheme' ] == 'https' ) {
print_error ( 'sslonlyaccess' , 'error' );
}
}
// $CFG->reverseproxy specifies if reverse proxy server used.
// Used in load balancing scenarios.
// Do not abuse this to try to solve lan/wan access problems!!!!!
if ( empty ( $CFG -> reverseproxy )) {
if (( $rurl [ 'host' ] != $wwwroot [ 'host' ]) or
( ! empty ( $wwwroot [ 'port' ]) and $rurl [ 'port' ] != $wwwroot [ 'port' ])) {
print_error ( 'wwwrootmismatch' , 'error' , '' , $CFG -> wwwroot );
}
}
// hopefully this will stop all those "clever" admins trying to set up moodle
// with two different addresses in intranet and Internet
if ( ! empty ( $CFG -> reverseproxy ) && $rurl [ 'host' ] == $wwwroot [ 'host' ]) {
print_error ( 'reverseproxyabused' , 'error' );
}
$hostandport = $rurl [ 'scheme' ] . '://' . $wwwroot [ 'host' ];
if ( ! empty ( $wwwroot [ 'port' ])) {
$hostandport .= ':' . $wwwroot [ 'port' ];
}
$FULLSCRIPT = $hostandport . $rurl [ 'path' ];
$FULLME = $hostandport . $rurl [ 'fullpath' ];
$ME = $rurl [ 'fullpath' ];
$rurl [ 'path' ] = $rurl [ 'fullpath' ];
}
/**
* Initialises $FULLME and friends for command line scripts .
* This is a private method for use by initialise_fullme .
*/
function initialise_fullme_cli () {
2009-05-17 17:07:54 +00:00
global $CFG , $FULLME , $ME , $SCRIPT , $FULLSCRIPT ;
2009-05-06 08:50:32 +00:00
// Urls do not make much sense in CLI scripts
$backtrace = debug_backtrace ();
$topfile = array_pop ( $backtrace );
$topfile = realpath ( $topfile [ 'file' ]);
$dirroot = realpath ( $CFG -> dirroot );
if ( strpos ( $topfile , $dirroot ) !== 0 ) {
// Probably some weird external script
$SCRIPT = $FULLSCRIPT = $FULLME = $ME = null ;
} else {
$relativefile = substr ( $topfile , strlen ( $dirroot ));
$relativefile = str_replace ( '\\' , '/' , $relativefile ); // Win fix
$SCRIPT = $FULLSCRIPT = $relativefile ;
$FULLME = $ME = null ;
}
}
/**
* Get the URL that PHP / the web server thinks it is serving . Private function
* used by initialise_fullme . In your code , use $PAGE -> url , $SCRIPT , etc .
* @ return array in the same format that parse_url returns , with the addition of
* a 'fullpath' element , which includes any slasharguments path .
*/
function setup_get_remote_url () {
2009-01-05 21:37:20 +00:00
$rurl = array ();
2009-05-06 08:50:32 +00:00
list ( $rurl [ 'host' ]) = explode ( ':' , $_SERVER [ 'HTTP_HOST' ]);
2009-01-05 21:37:20 +00:00
$rurl [ 'port' ] = $_SERVER [ 'SERVER_PORT' ];
2009-05-06 08:50:32 +00:00
$rurl [ 'path' ] = $_SERVER [ 'SCRIPT_NAME' ]; // Script path without slash arguments
2009-01-05 21:37:20 +00:00
if ( stripos ( $_SERVER [ 'SERVER_SOFTWARE' ], 'apache' ) !== false ) {
//Apache server
$rurl [ 'scheme' ] = empty ( $_SERVER [ 'HTTPS' ]) ? 'http' : 'https' ;
$rurl [ 'fullpath' ] = $_SERVER [ 'REQUEST_URI' ]; // TODO: verify this is always properly encoded
} else if ( stripos ( $_SERVER [ 'SERVER_SOFTWARE' ], 'lighttpd' ) !== false ) {
2010-04-06 19:23:47 +00:00
//lighttpd - not officially supported
2009-01-05 21:37:20 +00:00
$rurl [ 'scheme' ] = empty ( $_SERVER [ 'HTTPS' ]) ? 'http' : 'https' ;
$rurl [ 'fullpath' ] = $_SERVER [ 'REQUEST_URI' ]; // TODO: verify this is always properly encoded
2009-08-27 07:52:11 +00:00
} else if ( stripos ( $_SERVER [ 'SERVER_SOFTWARE' ], 'nginx' ) !== false ) {
2010-04-06 19:23:47 +00:00
//nginx - not officially supported
2009-08-27 07:52:11 +00:00
$rurl [ 'scheme' ] = empty ( $_SERVER [ 'HTTPS' ]) ? 'http' : 'https' ;
$rurl [ 'fullpath' ] = $_SERVER [ 'REQUEST_URI' ]; // TODO: verify this is always properly encoded
2009-01-05 21:37:20 +00:00
} else if ( stripos ( $_SERVER [ 'SERVER_SOFTWARE' ], 'iis' ) !== false ) {
2010-04-06 19:23:47 +00:00
//IIS - needs a lot of tweaking to make it work
2009-01-05 21:37:20 +00:00
$rurl [ 'scheme' ] = ( $_SERVER [ 'HTTPS' ] == 'off' ) ? 'http' : 'https' ;
$rurl [ 'fullpath' ] = $_SERVER [ 'SCRIPT_NAME' ];
// NOTE: ignore PATH_INFO because it is incorrectly encoded using 8bit filesystem legacy encoding in IIS
// since 2.0 we rely on iis rewrite extenssion like Helicon ISAPI_rewrite
2009-01-05 22:32:15 +00:00
// example rule: RewriteRule ^([^\?]+?\.php)(\/.+)$ $1\?file=$2 [QSA]
2009-01-05 21:37:20 +00:00
if ( $_SERVER [ 'QUERY_STRING' ] != '' ) {
2009-01-06 12:33:32 +00:00
$rurl [ 'fullpath' ] .= '?' . $_SERVER [ 'QUERY_STRING' ];
2009-01-05 21:37:20 +00:00
}
$_SERVER [ 'REQUEST_URI' ] = $rurl [ 'fullpath' ]; // extra IIS compatibility
2010-04-06 19:23:47 +00:00
} else if ( stripos ( $_SERVER [ 'SERVER_SOFTWARE' ], 'cherokee' ) !== false ) {
//cherokee - not officially supported
$rurl [ 'scheme' ] = ( $_SERVER [ 'HTTPS' ] == 'off' ) ? 'http' : 'https' ;
$rurl [ 'fullpath' ] = $_SERVER [ 'REQUEST_URI' ]; // TODO: verify this is always properly encoded
2009-01-05 21:37:20 +00:00
} else {
2009-05-06 08:50:32 +00:00
throw new moodle_exception ( 'unsupportedwebserver' , 'error' , '' , $_SERVER [ 'SERVER_SOFTWARE' ]);
2009-01-05 21:37:20 +00:00
}
2009-05-06 08:50:32 +00:00
return $rurl ;
2009-01-05 21:37:20 +00:00
}
2006-01-05 07:08:10 +00:00
/**
* Initializes our performance info early .
*
* Pairs up with get_performance_info () which is actually
2008-06-13 17:51:34 +00:00
* in moodlelib . php . This function is here so that we can
* call it before all the libs are pulled in .
2006-01-05 07:08:10 +00:00
*
* @ uses $PERF
*/
function init_performance_info () {
2007-03-20 02:59:34 +00:00
global $PERF , $CFG , $USER ;
2008-06-13 17:51:34 +00:00
2008-06-16 21:01:54 +00:00
$PERF = new object ();
2006-01-05 07:08:10 +00:00
$PERF -> logwrites = 0 ;
if ( function_exists ( 'microtime' )) {
$PERF -> starttime = microtime ();
2009-06-29 05:00:45 +00:00
}
2006-01-05 07:08:10 +00:00
if ( function_exists ( 'memory_get_usage' )) {
$PERF -> startmemory = memory_get_usage ();
}
if ( function_exists ( 'posix_times' )) {
2008-06-13 17:51:34 +00:00
$PERF -> startposixtimes = posix_times ();
2006-01-05 07:08:10 +00:00
}
2007-03-20 00:34:05 +00:00
if ( function_exists ( 'apd_set_pprof_trace' )) {
// APD profiling
2007-03-20 02:59:34 +00:00
if ( $USER -> id > 0 && $CFG -> perfdebug >= 15 ) {
2008-06-13 17:51:34 +00:00
$tempdir = $CFG -> dataroot . '/temp/profile/' . $USER -> id ;
2007-03-20 02:59:34 +00:00
mkdir ( $tempdir );
apd_set_pprof_trace ( $tempdir );
$PERF -> profiling = true ;
}
2007-03-20 00:34:05 +00:00
}
2006-01-05 07:08:10 +00:00
}
2009-06-24 09:17:56 +00:00
/**
* Indicates whether we are in the middle of the initial Moodle install .
*
* Very occasionally it is necessary avoid running certain bits of code before the
* Moodle installation has completed . The installed flag is set in admin / index . php
* after Moodle core and all the plugins have been installed , but just before
* the person doing the initial install is asked to choose the admin password .
*
* @ return boolean true if the initial install is not complete .
*/
function during_initial_install () {
global $CFG ;
return empty ( $CFG -> rolesactive );
}
2006-12-26 22:48:36 +00:00
/**
* Function to raise the memory limit to a new value .
* Will respect the memory limit if it is higher , thus allowing
* settings in php . ini , apache conf or command line switches
* to override it
*
* The memory limit should be expressed with a string ( eg : '64M' )
*
* @ param string $newlimit the new memory limit
* @ return bool
*/
2009-01-05 21:37:20 +00:00
function raise_memory_limit ( $newlimit ) {
2006-12-26 22:48:36 +00:00
if ( empty ( $newlimit )) {
return false ;
}
$cur = @ ini_get ( 'memory_limit' );
if ( empty ( $cur )) {
// if php is compiled without --enable-memory-limits
// apparently memory_limit is set to ''
$cur = 0 ;
} else {
if ( $cur == - 1 ){
return true ; // unlimited mem!
}
$cur = get_real_size ( $cur );
}
$new = get_real_size ( $newlimit );
if ( $new > $cur ) {
ini_set ( 'memory_limit' , $newlimit );
2009-03-26 02:09:28 +00:00
return true ;
}
return false ;
}
/**
* Function to reduce the memory limit to a new value .
* Will respect the memory limit if it is lower , thus allowing
* settings in php . ini , apache conf or command line switches
* to override it
*
* The memory limit should be expressed with a string ( eg : '64M' )
*
* @ param string $newlimit the new memory limit
* @ return bool
*/
2009-05-11 17:13:45 +00:00
function reduce_memory_limit ( $newlimit ) {
2009-03-26 02:09:28 +00:00
if ( empty ( $newlimit )) {
return false ;
}
$cur = @ ini_get ( 'memory_limit' );
if ( empty ( $cur )) {
// if php is compiled without --enable-memory-limits
// apparently memory_limit is set to ''
$cur = 0 ;
} else {
if ( $cur == - 1 ){
return true ; // unlimited mem!
}
$cur = get_real_size ( $cur );
}
$new = get_real_size ( $newlimit );
// -1 is smaller, but it means unlimited
if ( $new < $cur && $new != - 1 ) {
ini_set ( 'memory_limit' , $newlimit );
2006-12-26 22:48:36 +00:00
return true ;
}
return false ;
}
/**
* Converts numbers like 10 M into bytes .
*
* @ param mixed $size The size to be converted
* @ return mixed
*/
function get_real_size ( $size = 0 ) {
if ( ! $size ) {
return 0 ;
}
2009-01-05 21:37:20 +00:00
$scan = array ();
2006-12-26 22:48:36 +00:00
$scan [ 'MB' ] = 1048576 ;
$scan [ 'Mb' ] = 1048576 ;
$scan [ 'M' ] = 1048576 ;
$scan [ 'm' ] = 1048576 ;
$scan [ 'KB' ] = 1024 ;
$scan [ 'Kb' ] = 1024 ;
$scan [ 'K' ] = 1024 ;
$scan [ 'k' ] = 1024 ;
while ( list ( $key ) = each ( $scan )) {
if (( strlen ( $size ) > strlen ( $key )) && ( substr ( $size , strlen ( $size ) - strlen ( $key )) == $key )) {
$size = substr ( $size , 0 , strlen ( $size ) - strlen ( $key )) * $scan [ $key ];
break ;
}
}
return $size ;
}
2009-07-10 08:44:01 +00:00
/**
* Check whether a major upgrade is needed . That is defined as an upgrade that
* changes something really fundamental in the database , so nothing can possibly
* work until the database has been updated , and that is defined by the hard - coded
* version number in this function .
*/
function redirect_if_major_upgrade_required () {
global $CFG ;
2010-05-06 06:55:59 +00:00
$lastmajordbchanges = 2010050404 ;
2009-07-10 08:44:01 +00:00
if ( empty ( $CFG -> version ) or ( int ) $CFG -> version < $lastmajordbchanges or
during_initial_install () or ! empty ( $CFG -> adminsetuppending )) {
try {
@ session_get_instance () -> terminate_current ();
} catch ( Exception $e ) {
// Ignore any errors, redirect to upgrade anyway.
}
2009-11-08 22:10:45 +00:00
$url = $CFG -> wwwroot . '/' . $CFG -> admin . '/index.php' ;
2009-07-10 08:44:01 +00:00
@ header ( $_SERVER [ 'SERVER_PROTOCOL' ] . ' 303 See Other' );
2009-11-08 22:10:45 +00:00
@ header ( 'Location: ' . $url );
echo bootstrap_renderer :: plain_redirect_message ( htmlspecialchars ( $url ));
2009-07-10 08:44:01 +00:00
exit ;
}
}
2006-01-05 07:08:10 +00:00
/**
* Create a directory .
*
* @ uses $CFG
* @ param string $directory a string of directory names under $CFG -> dataroot eg stuff / assignment / 1
* param bool $shownotices If true then notification messages will be printed out on error .
* @ return string | false Returns full path to directory if successful , false if not
*/
function make_upload_directory ( $directory , $shownotices = true ) {
global $CFG ;
$currdir = $CFG -> dataroot ;
umask ( 0000 );
if ( ! file_exists ( $currdir )) {
2010-05-10 15:59:21 +00:00
if ( ! mkdir ( $currdir , $CFG -> directorypermissions , true ) or ! is_writable ( $currdir )) {
2006-01-05 07:08:10 +00:00
if ( $shownotices ) {
2008-06-13 17:51:34 +00:00
echo '<div class="notifyproblem" align="center">ERROR: You need to create the directory ' .
2006-01-05 07:08:10 +00:00
$currdir . ' with web server write access</div>' . " <br /> \n " ;
}
return false ;
}
2006-08-18 09:54:09 +00:00
}
// Make sure a .htaccess file is here, JUST IN CASE the files area is in the open
if ( ! file_exists ( $currdir . '/.htaccess' )) {
2006-01-05 07:08:10 +00:00
if ( $handle = fopen ( $currdir . '/.htaccess' , 'w' )) { // For safety
2009-05-08 21:30:56 +00:00
@ fwrite ( $handle , " deny from all \r \n AllowOverride None \r \n Note: this file is broken intentionally, we do not want anybody to undo it in subdirectory! \r \n " );
2006-01-05 07:08:10 +00:00
@ fclose ( $handle );
}
}
$dirarray = explode ( '/' , $directory );
foreach ( $dirarray as $dir ) {
$currdir = $currdir . '/' . $dir ;
if ( ! file_exists ( $currdir )) {
if ( ! mkdir ( $currdir , $CFG -> directorypermissions )) {
if ( $shownotices ) {
2008-06-13 17:51:34 +00:00
echo '<div class="notifyproblem" align="center">ERROR: Could not find or create a directory (' .
2006-01-05 07:08:10 +00:00
$currdir . ')</div>' . " <br /> \n " ;
}
return false ;
}
//@chmod($currdir, $CFG->directorypermissions); // Just in case mkdir didn't do it
}
}
return $currdir ;
}
2006-12-27 22:44:39 +00:00
function init_memcached () {
global $CFG , $MCACHE ;
2006-12-27 22:47:51 +00:00
include_once ( $CFG -> libdir . '/memcached.class.php' );
$MCACHE = new memcached ;
if ( $MCACHE -> status ()) {
return true ;
2008-06-13 17:51:34 +00:00
}
2006-12-27 22:47:51 +00:00
unset ( $MCACHE );
2008-06-13 17:51:34 +00:00
return false ;
2006-12-27 22:44:39 +00:00
}
2006-12-27 22:47:14 +00:00
function init_eaccelerator () {
global $CFG , $MCACHE ;
include_once ( $CFG -> libdir . '/eaccelerator.class.php' );
$MCACHE = new eaccelerator ;
2006-12-27 22:47:51 +00:00
if ( $MCACHE -> status ()) {
2006-12-27 22:47:14 +00:00
return true ;
2008-06-13 17:51:34 +00:00
}
2006-12-27 22:47:14 +00:00
unset ( $MCACHE );
return false ;
}
2009-06-29 05:00:45 +00:00
/**
* This class solves the problem of how to initialise $OUTPUT .
*
* The problem is caused be two factors
* < ol >
* < li > On the one hand , we cannot be sure when output will start . In particular ,
2009-10-31 14:17:44 +00:00
* an error , which needs to be displayed , could be thrown at any time .</ li >
2009-06-29 05:00:45 +00:00
* < li > On the other hand , we cannot be sure when we will have all the information
* necessary to correctly initialise $OUTPUT . $OUTPUT depends on the theme , which
* ( potentially ) depends on the current course , course categories , and logged in user .
* It also depends on whether the current page requires HTTPS .</ li >
* </ ol >
*
* So , it is hard to find a single natural place during Moodle script execution ,
* which we can guarantee is the right time to initialise $OUTPUT . Instead we
* adopt the following strategy
* < ol >
* < li > We will initialise $OUTPUT the first time it is used .</ li >
* < li > If , after $OUTPUT has been initialised , the script tries to change something
2009-08-06 14:21:34 +00:00
* that $OUTPUT depends on , we throw an exception making it clear that the script
2009-06-29 05:00:45 +00:00
* did something wrong .
* </ ol >
*
* The only problem with that is , how do we initialise $OUTPUT on first use if ,
* it is going to be used like $OUTPUT -> somthing ( ... ) ? Well that is where this
* class comes in . Initially , we set up $OUTPUT = new bootstrap_renderer () . Then ,
* when any method is called on that object , we initialise $OUTPUT , and pass the call on .
*
* Note that this class is used before lib / outputlib . php has been loaded , so we
2009-11-01 10:05:07 +00:00
* must be careful referring to classes / functions from there , they may not be
2009-06-29 05:00:45 +00:00
* defined yet , and we must avoid fatal errors .
*
* @ copyright 2009 Tim Hunt
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
* @ since Moodle 2.0
*/
class bootstrap_renderer {
/**
* Handles re - entrancy . Without this , errors or debugging output that occur
* during the initialisation of $OUTPUT , cause infinite recursion .
* @ var boolean
*/
protected $initialising = false ;
2009-07-01 05:54:26 +00:00
/**
* Have we started output yet ?
* @ return boolean true if the header has been printed .
*/
public function has_started () {
return false ;
}
2009-06-29 05:00:45 +00:00
public function __call ( $method , $arguments ) {
2009-07-01 05:54:26 +00:00
global $OUTPUT , $PAGE ;
2009-06-29 05:00:45 +00:00
2009-07-07 04:37:12 +00:00
$recursing = false ;
if ( $method == 'notification' ) {
2009-11-01 10:05:07 +00:00
// Catch infinite recursion caused by debugging output during print_header.
2009-07-07 04:37:12 +00:00
$backtrace = debug_backtrace ();
array_shift ( $backtrace );
array_shift ( $backtrace );
2009-10-30 13:44:07 +00:00
$recursing = is_early_init ( $backtrace );
2009-07-07 04:37:12 +00:00
}
2009-06-29 05:00:45 +00:00
// If lib/outputlib.php has been loaded, call it.
2009-07-07 04:37:12 +00:00
if ( ! empty ( $PAGE ) && ! $recursing ) {
2009-07-01 05:54:26 +00:00
$PAGE -> initialise_theme_and_output ();
return call_user_func_array ( array ( $OUTPUT , $method ), $arguments );
2009-06-29 05:00:45 +00:00
}
2006-12-27 22:47:14 +00:00
2009-06-29 05:00:45 +00:00
$this -> initialising = true ;
// Too soon to initialise $OUTPUT, provide a couple of key methods.
$earlymethods = array (
'fatal_error' => 'early_error' ,
'notification' => 'early_notification' ,
);
if ( array_key_exists ( $method , $earlymethods )) {
return call_user_func_array ( array ( 'bootstrap_renderer' , $earlymethods [ $method ]), $arguments );
}
throw new coding_exception ( 'Attempt to start output before enough information is known to initialise the theme.' );
}
/**
2009-11-01 10:05:07 +00:00
* Returns nicely formatted error message in a div box .
2009-10-31 14:17:44 +00:00
* @ return string
2009-06-29 05:00:45 +00:00
*/
2009-10-31 15:01:25 +00:00
public static function early_error_content ( $message , $moreinfourl , $link , $backtrace , $debuginfo = null ) {
2009-07-01 05:54:26 +00:00
global $CFG ;
2009-10-31 15:01:25 +00:00
$content = ' < div style = " margin-top: 6em; margin-left:auto; margin-right:auto; color:#990000; text-align:center; font-size:large; border-width:1px;
border - color : black ; background - color : #ffffee; border-style:solid; border-radius: 20px; border-collapse: collapse;
width : 80 % ; - moz - border - radius : 20 px ; padding : 15 px " >
' . $message . '
</ div > ' ;
if ( ! empty ( $CFG -> debug ) && $CFG -> debug >= DEBUG_DEVELOPER ) {
if ( ! empty ( $debuginfo )) {
2010-03-20 13:46:15 +00:00
$debuginfo = s ( $debuginfo ); // removes all nasty JS
$debuginfo = str_replace ( " \n " , '<br />' , $debuginfo ); // keep newlines
$content .= '<div class="notifytiny">Debug info: ' . $debuginfo . '</div>' ;
2009-10-31 15:01:25 +00:00
}
if ( ! empty ( $backtrace )) {
$content .= '<div class="notifytiny">Stack trace: ' . format_backtrace ( $backtrace , false ) . '</div>' ;
}
}
return $content ;
}
/**
* This function should only be called by this class , or from exception handlers
* @ return string
*/
public static function early_error ( $message , $moreinfourl , $link , $backtrace , $debuginfo = null ) {
2010-03-28 09:05:47 +00:00
global $CFG ;
if ( CLI_SCRIPT ) {
echo " !!! $message !!! \n " ;
if ( ! empty ( $CFG -> debug ) and $CFG -> debug >= DEBUG_DEVELOPER ) {
if ( ! empty ( $debuginfo )) {
echo " \n Debug info: $debuginfo " ;
}
if ( ! empty ( $backtrace )) {
echo " \n Stack trace: " . format_backtrace ( $backtrace , true );
}
}
return ;
} else if ( AJAX_SCRIPT ) {
$e = new stdClass ();
$e -> error = $message ;
$e -> stacktrace = NULL ;
$e -> debuginfo = NULL ;
if ( ! empty ( $CFG -> debug ) and $CFG -> debug >= DEBUG_DEVELOPER ) {
if ( ! empty ( $debuginfo )) {
$e -> debuginfo = $debuginfo ;
}
if ( ! empty ( $backtrace )) {
$e -> stacktrace = format_backtrace ( $backtrace , true );
}
}
echo json_encode ( $e );
return ;
}
2009-06-29 05:00:45 +00:00
// In the name of protocol correctness, monitoring and performance
2009-11-01 10:05:07 +00:00
// profiling, set the appropriate error headers for machine consumption
2009-06-29 05:00:45 +00:00
if ( isset ( $_SERVER [ 'SERVER_PROTOCOL' ])) {
// Avoid it with cron.php. Note that we assume it's HTTP/1.x
2009-11-01 10:05:07 +00:00
// The 503 ode here means our Moodle does not work at all, the error happened too early
2009-06-29 05:00:45 +00:00
@ header ( $_SERVER [ 'SERVER_PROTOCOL' ] . ' 503 Service Unavailable' );
}
// better disable any caching
@ header ( 'Content-Type: text/html; charset=utf-8' );
@ header ( 'Cache-Control: no-store, no-cache, must-revalidate' );
@ header ( 'Cache-Control: post-check=0, pre-check=0' , false );
@ header ( 'Pragma: no-cache' );
@ header ( 'Expires: Mon, 20 Aug 1969 09:23:00 GMT' );
@ header ( 'Last-Modified: ' . gmdate ( 'D, d M Y H:i:s' ) . ' GMT' );
2009-07-10 08:44:01 +00:00
if ( function_exists ( 'get_string' )) {
2009-06-29 05:00:45 +00:00
$strerror = get_string ( 'error' );
} else {
$strerror = 'Error' ;
}
2009-10-31 15:01:25 +00:00
$content = self :: early_error_content ( $message , $moreinfourl , $link , $backtrace , $debuginfo );
2009-07-10 08:44:01 +00:00
return self :: plain_page ( $strerror , $content );
2009-06-29 05:00:45 +00:00
}
public static function early_notification ( $message , $classes = 'notifyproblem' ) {
return '<div class="' . $classes . '">' . $message . '</div>' ;
}
2009-07-10 08:44:01 +00:00
public static function plain_redirect_message ( $encodedurl ) {
$message = '<p>' . get_string ( 'pageshouldredirect' ) . '</p><p><a href="' .
$encodedurl . '">' . get_string ( 'continue' ) . '</a></p>' ;
2009-08-31 07:13:41 +00:00
return self :: plain_page ( get_string ( 'redirect' ), $message );
2009-07-10 08:44:01 +00:00
}
protected static function plain_page ( $title , $content ) {
if ( function_exists ( 'get_string' ) && function_exists ( 'get_html_lang' )) {
$htmllang = get_html_lang ();
} else {
$htmllang = '' ;
}
return ' <! DOCTYPE html PUBLIC " -//W3C//DTD XHTML 1.0 Strict//EN " " http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd " >
< html xmlns = " http://www.w3.org/1999/xhtml " ' . $htmllang . ' >
< head >
< meta http - equiv = " Content-Type " content = " text/html; charset=utf-8 " />
< title > ' . $title . ' </ title >
</ head >< body > ' . $content . ' </ body ></ html > ' ;
}
2009-06-29 05:00:45 +00:00
}