Source for file _main.inc.php
Documentation is available at _main.inc.php
* This file initializes everything BUT the blog!
* It is useful when you want to do very customized templates!
* It is also called by more complete initializers.
* This file is part of the evoCore framework - {@link http://evocore.net/}
* See also {@link http://sourceforge.net/projects/evocms/}.
* @copyright (c)2003-2006 by Francois PLANQUE - {@link http://fplanque.net/}
* Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
* Parts of this file are copyright (c)2005-2006 by PROGIDISTRI - {@link http://progidistri.com/}.
* {@internal License choice
* - If you have received this file as part of a package, please find the license.txt file in
* the same folder or the closest folder above for complete license terms.
* - If you have received this file individually (e-g: from http://cvs.sourceforge.net/viewcvs.py/evocms/)
* then you must choose one of the following licenses before using the file:
* - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
* - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
* {@internal Open Source relicensing agreement:
* Daniel HAHLER grants Francois PLANQUE the right to license
* Daniel HAHLER's contributions to this file and the b2evolution project
* under any OSI approved OSS license (http://www.opensource.org/licenses/).
* PROGIDISTRI S.A.S. grants Francois PLANQUE the right to license
* PROGIDISTRI S.A.S.'s contributions to this file and the b2evolution project
* under any OSI approved OSS license (http://www.opensource.org/licenses/).
* Matt FOLLETT grants Francois PLANQUE the right to license
* Matt FOLLETT's contributions to this file and the b2evolution project
* under any OSI approved OSS license (http://www.opensource.org/licenses/).
* {@internal Below is a list of authors who have contributed to design/coding of this file: }}
* @author fplanque: Francois PLANQUE
* @author blueyed: Daniel HAHLER
* @author mfollett: Matt FOLLETT.
* @author mbruneau: Marc BRUNEAU / PROGIDISTRI
* {@internal Below is a list of former authors whose contributions to this file have been
* either removed or redesigned and rewritten anew:
* @version $Id: _main.inc.php,v 1.22.2.10 2006/12/02 02:41:27 fplanque Exp $
if( !defined('EVO_CONFIG_LOADED') ) die( 'Please, do not access this page directly.' );
header('HTTP/1.0 503 Service Unavailable');
echo
'<h1>503 Service Unavailable</h1>';
die( 'The site is temporarily down for maintenance.' );
* Prevent double loading since require_once won't work in all situations
* on windows when some subfolders have caps :(
* (Check it out on static page generation)
define( 'EVO_MAIN_INIT', true );
* Security check for older PHP versions
* Contributed by counterpoint / MAMBO team
$protects =
array( '_REQUEST', '_GET', '_POST', '_COOKIE', '_FILES', '_SERVER', '_ENV', 'GLOBALS', '_SESSION' );
foreach( $protects as $protect )
* fp> Alternatively we might want to kill all auto registered globals this way:
* dh> "Alternatively"? AFAICS the above does not protect us against register_globals!
$superglobals = array($_SERVER, $_ENV, $_FILES, $_COOKIE, $_POST, $_GET);
if (isset( $_SESSION )) array_unshift ( $superglobals , $_SESSION );
if (ini_get('register_globals') && !$this->mosConfig_register_globals)
foreach ( $superglobals as $superglobal )
foreach ( $superglobal as $key => $value)
require_once dirname(__FILE__
).
'/_misc/_log.class.php';
* Debug message log for debugging only (initialized here).
* If {@link $debug} is off, it will be re-instantiated of class {@link Log_noop} after loading config
* and perform no operations.
* @global Log|Log_noop$Debuglog
$Debuglog =
& new Log( 'note' );
* Info & error message log for end user (initialized here)
$Messages =
& new Log( 'error' );
require_once dirname(__FILE__
).
'/_misc/_timer.class.php';
$Timer =
& new Timer('total');
$Timer->start( 'main.inc' );
* Load base + advanced configuration:
// Note: this should have been done before coming here...
// require_once dirname(__FILE__).'/_config.php';
* Sets various arrays and vars, also $app_name!
* Needed before the error messages.
require_once dirname(__FILE__
).
'/_vars.inc.php';
{ // base config is not done!
$error_message =
'Base configuration is not done! (see /conf/_basic_config.php)';
elseif( !isset
( $locales[$default_locale] ) )
$error_message =
'The default locale '.
var_export( $default_locale, true ).
' does not exist! (see /conf/_locales.php)';
if( isset
( $error_message ) )
require
dirname(__FILE__
).
'/_conf_error.inc.php';
* Miscellaneous functions
require_once dirname(__FILE__
).
'/_misc/_misc.funcs.php';
require_once dirname(__FILE__
).
'/_connect_db.inc.php';
require_once $model_path.
'settings/_generalsettings.class.php';
require_once $model_path.
'users/_usersettings.class.php';
* Interface to general settings
* Keep this below the creation of the {@link $DB DB object}, because it checks for the
* correct db_version and catches "table does not exist" errors, providing a link to the
* @global GeneralSettings $Settings
* Interface to user settings
* @global UserSettings $UserSettings
* Absolute Unix timestamp for server
* @global int $servertimenow
$time_difference =
$Settings->get('time_difference') *
3600;
* Corrected Unix timestamp to match server timezone
* @global int $localtimenow
$localtimenow =
$servertimenow +
$time_difference;
require_once $model_path.
'sessions/_hit.class.php';
* @global Hit The Hit object
* It has to be instantiated before the "SessionLoaded" hook.
require_once $model_path.
'sessions/_session.class.php';
* @global Session The Session object
* This is done quite early here to give an early hook ("SessionLoaded") to plugins (though it might also be moved just after $DB init when there is reason for a hook there).
* The {@link dnsbl_antispam_plugin} is an example that uses this to check the user's IP against a list of DNS blacklists.
require_once dirname(__FILE__
).
'/_misc/_plugins.class.php';
* @global Plugins The Plugin management object
// NOTE: it might be faster (though more bandwidth intensive) to spit cached pages (CachePageContent event) than to look into blocking the request (SessionLoaded event).
$Plugins->trigger_event( 'SessionLoaded' );
// Trigger a page content caching plugin. This would either return the cached content here or start output buffering
if( empty($generating_static) )
if( $Session->get( 'core.no_CachePageContent' ) )
{ // The event is disabled for this request:
$Session->delete('core.no_CachePageContent');
$Debuglog->add( 'Skipping CachePageContent event, because of core.no_CachePageContent setting.', 'plugins' );
elseif( ( $get_return =
$Plugins->trigger_event_first_true( 'CachePageContent' ) ) // Plugin responded to the event
&&
( isset
($get_return['data']) ) ) // cached content returned
echo
$get_return['data'];
// Note: we should not use debug_info() here, because the plugin has probably sent a Content-Length header.
require_once dirname(__FILE__
).
'/_misc/_request.class.php';
* Debug message log for debugging only (initialized here)
* @global Request $Request
$Request =
& new Request( $Messages );
if( !isset
( $use_html_checker ) ) { $use_html_checker =
1; }
require_once $model_path.
'dataobjects/_dataobjectcache.class.php';
require_once $model_path.
'generic/_genericelement.class.php';
require_once $model_path.
'generic/_genericcache.class.php';
require_once $model_path.
'collections/_blog.class.php';
require_once $model_path.
'collections/_blog.funcs.php';
require_once $model_path.
'collections/_category.funcs.php';
require_once $model_path.
'items/_item.funcs.php';
require_once $model_path.
'users/_user.funcs.php';
require_once $inc_path.
'_misc/_resultsel.class.php';
require_once $inc_path.
'_misc/_template.funcs.php'; // function to be called from templates
require_once $model_path.
'files/_filecache.class.php';
require_once $model_path.
'files/_file.class.php';
require_once $model_path.
'files/_filerootcache.class.php';
require_once $model_path.
'files/_filetype.class.php';
require_once $model_path.
'files/_filetypecache.class.php';
require_once $model_path.
'items/_itemcache.class.php';
require_once $model_path.
'items/_itemtype.class.php';
require_once $model_path.
'items/_itemtypecache.class.php';
require_once $model_path.
'items/_link.class.php';
require_once $model_path.
'items/_linkcache.class.php';
require_once $model_path.
'users/_usercache.class.php';
require_once $model_path.
'comments/_comment.funcs.php';
if( $use_html_checker ) { require_once $inc_path.
'_misc/_htmlchecker.class.php'; }
require_once $model_path.
'items/_item.funcs.php';
require_once $inc_path.
'_misc/_pingback.funcs.php';
require_once $inc_path.
'_misc/_ping.funcs.php';
require_once $model_path.
'skins/_skin.funcs.php';
require_once $inc_path.
'_misc/_trackback.funcs.php';
require_once $inc_path.
'_misc/ext/_xmlrpc.php';
require_once $inc_path.
'_misc/ext/_xmlrpcs.php';
require_once $model_path.
'comments/_commentlist.class.php';
require_once $model_path.
'items/_itemlist.class.php';
* Optionally include obsolete functions
include_once $inc_path.
'_misc/_obsolete092.php';
// Object caches init (we're asking plugins that provide the "CacheObjects" event here first):
$Plugins->get_object_from_cacheplugin_or_create( 'FileRootCache' );
$Plugins->get_object_from_cacheplugin_or_create( 'FiletypeCache' );
$Plugins->get_object_from_cacheplugin_or_create( 'GroupCache', '& new DataObjectCache( \'Group\', true, \'T_groups\', \'grp_\', \'grp_ID\', \'grp_name\' )' );
$Plugins->get_object_from_cacheplugin_or_create( 'ItemTypeCache', '& new ItemTypeCache( \'ptyp_\', \'ptyp_ID\' )' );
$Plugins->get_object_from_cacheplugin_or_create( 'ItemStatusCache', '& new GenericCache( \'GenericElement\', true, \'T_itemstatuses\', \'pst_\', \'pst_ID\' )' );
// Caches that are not meant to be loaded in total:
require_once $model_path.
'sessions/_hitlog.funcs.php'; // referer logging
require_once dirname(__FILE__
).
'/_misc/_form.funcs.php';
require_once dirname(__FILE__
).
'/_misc/_form.class.php';
require_once $model_path.
'items/_itemquery.class.php';
require_once dirname(__FILE__
).
'/_misc/ext/_swfcharts.php';
require_once dirname(__FILE__
).
'/_misc/_iconlegend.class.php';
$Debuglog->add( 'default_locale from conf: '.
$default_locale, 'locale' );
$Debuglog->add( 'default_locale from DB: '.
$default_locale, 'locale' );
$Debuglog->add( 'default_locale from HTTP_ACCEPT: '.
$default_locale, 'locale' );
if( ($locale_from_get =
param( 'locale', 'string', NULL, true ))
&&
$locale_from_get !=
$default_locale
&& isset
( $locales[$locale_from_get] ) )
$default_locale =
$locale_from_get;
$Debuglog->add( 'Overriding locale from REQUEST: '.
$default_locale, 'locale' );
* Activate default locale:
if( !isset
($login_required) )
if( isset
($_POST['login'] ) && isset
($_POST['pwd'] ) )
{ // Trying to log in with a POST
$login =
$_POST['login'];
unset
($_POST['pwd']); // password will be hashed below
elseif( isset
($_GET['login'] ) )
{ // Trying to log in with a GET; we might only provide a user here.
$pass = isset
($_GET['pwd']) ?
$_GET['pwd'] :
'';
unset
($_GET['pwd']); // password will be hashed below
$Debuglog->add( 'login: '.
var_export($login, true), 'login' );
$Debuglog->add( 'pass: '.
( empty($pass) ?
'' :
'not' ).
' empty', 'login' );
// either 'login' (normal) or 'redirect_to_backoffice' may be set here. This also helps to display the login form again, if either login or pass were empty.
$login_action =
$Request->param_arrayindex( 'login_action' );
if( ! empty($login_action) ||
(! empty($login) &&
! empty($pass)) )
{ // User is trying to login right now
$Debuglog->add( 'User is trying to log in.', 'login' );
$pass_md5 =
md5( $pass );
// echo 'Trying to log in right now...';
$Plugins->trigger_event( 'LoginAttempt', array( 'login' =>
$login, 'pass' =>
$pass, 'pass_md5' =>
$pass_md5 ) );
if( $Messages->count('login_error') )
{ // A plugin has thrown a login error..
// Do nothing, the error will get displayed in the login form..
// Check login and password
$Debuglog->add( 'user_pass_ok() returned false!', 'login' );
// This will cause the login screen to "popup" (again)
$Messages->add( T_('Wrong login/password.'), 'login_error' );
{ // Login succeeded, set cookies
$Debuglog->add( 'User successfully logged in with username and password...', 'login');
// set the user from the login that succeeded
$current_User =
& $UserCache->get_by_login($login);
// save the user for later hits
$Session->set_User( $current_User );
// Remove deprecated cookies:
// We do not use $cookie_user / $cookie_pass (would be set in _obsolete092.php), because it
// does not harm really (cookies time out) and would allow to set arbitrary cookies through
setcookie( 'cookie'.
$instance_name.
'user', '', 200000000, $cookie_path, $cookie_domain );
setcookie( 'cookie'.
$instance_name.
'pass', '', 200000000, $cookie_path, $cookie_domain );
elseif( $Session->has_User() /* logged in */
&&
/* No login param given or the same as current user: */
( empty($login) ||
( ( $tmp_User =
& $UserCache->get_by_ID($Session->user_ID) ) &&
$login ==
$tmp_User->login ) ) )
{ /* if the session has a user assigned to it:
* User was not trying to log in, but he was already logged in:
// get the user ID from the session and set up the user again
$current_User =
& $UserCache->get_by_ID( $Session->user_ID );
$Debuglog->add( 'Was already logged in... ['.
$current_User->get('login').
']', 'login' );
{ // The Session has no user or $login is given (and differs from current user), allow alternate authentication through Plugin:
if( ($event_return =
$Plugins->trigger_event_first_true( 'AlternateAuthentication' ))
&&
$Session->has_User() # the plugin should have attached the user to $Session
$Debuglog->add( 'User has been authenticated through plugin #'.
$event_return['plugin_ID'].
' (AlternateAuthentication)', 'login' );
$current_User =
& $UserCache->get_by_ID( $Session->user_ID );
elseif( $login_required )
* ---------------------------------------------------------
* User was not logged in at all, but login is required
* ---------------------------------------------------------
// echo ' NOT logged in...';
$Debuglog->add( 'NOT logged in... (did not try)', 'login' );
$Messages->add( T_('You must log in!'), 'login_error' );
// Check if the user needs to be validated, but is not yet:
if( ! empty($current_User)
&&
! $current_User->validated
&&
$Settings->get('newusers_mustvalidate')
&&
$Request->param('action', 'string', '') !=
'logout' )
if( $action !=
'req_validatemail' &&
$action !=
'validatemail' )
{ // we're not in that action already:
$action =
'req_validatemail'; // for login.php
$Messages->add( sprintf( /* TRANS: %s gets replaced by the user's email address */ T_('You must validate your email address (%s) before you can log in.'), $current_User->dget('email') ), 'login_error' );
{ // Trigger plugin event that allows the plugins to re-act on the login event:
if( empty($current_User) )
$Plugins->trigger_event( 'AfterLoginAnonymousUser', array() );
$Plugins->trigger_event( 'AfterLoginRegisteredUser', array() );
if( ! empty($login_action) )
{ // We're coming from the Login form and need to redirect to the requested page:
param( 'redirect_to', 'string', $baseurl );
if( $login_action ==
'redirect_to_backoffice' )
{ // user pressed the "Log into backoffice!" button
$redirect_to =
$admin_url;
// If there are "login_error" messages, they trigger the login form at the end of this file.
/* Login procedure }}} */
require_once $model_path.
'sessions/_sessions.class.php';
* @global Sessions The Sessions object
if( is_logged_in() &&
$current_User->get('locale') !=
$current_locale
{ // change locale to users preference
* TODO: this should get done before instantiating $current_User, because we already use T_() there...
if( $current_locale ==
$current_User->get('locale') )
$default_locale =
$current_locale;
$Debuglog->add( 'default_locale from user profile: '.
$default_locale, 'locale' );
$Debuglog->add( 'locale from user profile could not be activated: '.
$current_User->get('locale'), 'locale' );
* @global string The INPUT/OUTPUT charset (from the locale MESSAGES). MAY be overriden in _blog_main.inc.php.
// Check and adjust $evo_charset if needed:
if( empty($evo_charset) )
{ // Internal encoding follows INPUT/OUTPUT encoding:
$evo_charset =
$io_charset;
elseif( $evo_charset !=
$io_charset )
{ // we have to convert for I/O, which requires mbstrings extension
$Debuglog->add( '$evo_charset differs from $io_charset, but mbstrings does not seem to be installed.', array('errors','locale') );
$evo_charset =
$io_charset; // we cannot convert I/O to internal charset
{ // check if the encodings are supported:
$mb_encodings =
mb_list_encodings();
$Debuglog->add( 'Cannot I/O convert because I/O charset ['.
$io_charset.
'] is not in mb_list_encodings()!', array('errors','locale') );
$evo_charset =
$io_charset;
$Debuglog->add( 'Cannot I/O convert because $evo_charset='.
$evo_charset.
' is not in mb_list_encodings()!', array('errors','locale') );
$evo_charset =
$io_charset;
mb_http_output( $io_charset );
ob_start( 'mb_output_handler' ); // NOTE: this will send a Content-Type header by itself for "text/..."
$mb_output_handler_started =
true; // remember it for _blog_main.inc.php
// Tell mbstrings what the internal encoding is:
mb_internal_encoding( $evo_charset );
if( empty($db_config['connection_charset']) )
{ // Set encoding for MySQL connection (not overriding explicitely set one):
$DB->set_connection_charset( $evo_charset, true );
$Debuglog->add( 'evo_charset (_main.inc.php): '.
$evo_charset, 'locale' );
$Debuglog->add( 'io_charset (_main.inc.php): '.
$io_charset, 'locale' );
* Note: we can't do this earlier because need the users locale set there ({@link T_()})
require_once $conf_path.
'_icons.php';
// Display login errors (and form). This uses $io_charset, so it's at the end.
if( $Messages->count( 'login_error' ) )
require
$htsrv_path.
'login.php';
$Timer->pause( 'main.inc');
* Load hacks file if it exists
$Timer->resume( 'hacks.php' );
include_once $conf_path.
'hacks.php';
$Timer->pause( 'hacks.php' );