* @copyright 2004 by http://wombat.exit0.net * @package wombatSite * @subpackage controller */ /** * Site controller * * @version 1.3.1 * @package wombatSite * @subpackage controller */ class wbSite { /** * patTemplate object * @var object $_tmpl */ var $_tmpl = null; /** * patSession object * @var object $_sess */ var $_sess = null; /** * visit id - session id for each visit * * Used by logging mechanism to track useers even if their session-id has changed (e.g. during log in) * * @var string $_visitId */ var $_visitId = ''; /** * request variables * @var array $_request */ var $_request = array(); /** * current page * @var array $_page */ var $_page = array(); /** * store main config array * @var array $_config */ var $_config = null; /** * constructor * * @access public */ function __construct() { // we actually need UTF-8 header( 'Content-Type: text/html; charset=utf-8;' ); $this->_config =& wbFactory::getParam( 'config' ); $request =& wbFactory::singleton( 'wbRequest' ); $this->_request =& $request->export(); $this->_tmpl =& wbFactory::singleton( 'patTemplate' ); $this->_sess =& wbFactory::singleton( 'patSession' ); if( !$this->_sess->has( 'wbSite:visitId' ) ) { $this->_sess->set( 'wbSite:visitId', $this->_sess->getId() ); } $this->_visitId = $this->_sess->get( 'wbSite:visitId' ); wbFactory::includeClass( 'wbLog' ); wbFactory::includeClass( 'wbEvent' ); wbFactory::includeClass( 'wbJSTools' ); } /** * get configuration of current page * * @access public * @return array $page */ function getPageInfo() { return $this->_page; } /** * main processing function * make world :-) * * @access public * @return boolean $result true on success */ function process() { // in which page we are now? $page = $this->_selectPage(); // require login-failed-template in case of failed login $this->_tmpl->readTemplatesFromInput( $this->_page['layout'] . '.tmpl' ); // find user and check permissions - this may affect the session-id! $this->_authenticate(); $this->_localize( $this->_config['locale_domain'] ); $this->_authorize(); $this->_addGlobalContent(); // process content parts $debugMsg = array( 'Parts:' ); foreach( $this->_config['content'] as $part => $default ) { // overwrite default content $conf = $default; if( isset( $this->_page['content'][$part] ) && is_array( $this->_page['content'][$part] ) ) { $conf = $this->_page['content'][$part]; } // check configuration value: action if( !isset( $conf['action'] ) || empty( $conf['action'] ) ) { $this->_insertErrorContent( $part ); wbLog::err( 'error', array( $this->_visitId, 'configuration', $page, $part, 'Parameter "action" required!' ) ); patErrorManager::raiseWarning( 'wbSite:4', 'Configuration error', 'The parameter "action" is empty or not set in part "'. $part.'"!' ); continue; } // check configuration value: href if( !isset( $conf['href'] ) || empty( $conf['href'] ) ) { $this->_insertErrorContent( $part ); wbLog::err( 'error', array( $this->_visitId, 'configuration', $page, $part, 'Parameter "href" required!' ) ); patErrorManager::raiseWarning( 'wbSite:1', 'Configuration error', 'The parameter "href is empty or not set in part "'. $part.'"!' ); continue; } // call specified method to collect content $function = 'getContent' . ucfirst( $conf['action'] ); if( !method_exists( $this, $function ) ) { $this->_insertErrorContent( $part ); wbLog::err( 'error', array( $this->_visitId, 'configuration', $page, $part, 'Action "'. $conf['action'] .'" undefined' ) ); patErrorManager::raiseWarning( 'wbSite:5', 'Configuration error', 'The parameter "action" contains an undefined value in part "'. $part.'"!' ); continue; } // recieve content $timeStart = wbDebugger::getUTime(); $content = $this->$function( $conf, $part, $page ); if( patErrorManager::isError( $content ) ) { $this->_insertErrorContent( $part ); wbLog::err( 'error', array( $this->_visitId, 'content', $page, $part, 'Failed to recieve content' ) ); continue; } array_push( $debugMsg, ' - ' . $part . ': ('.$conf['action'].'->'. $conf['href'].'): '. wbDebugger::getUTime( $timeStart, 1000, 6 ) .' ms' ); $this->_tmpl->addVar( 'page', $part, $content ); } // finally add Javascript code to HTML and display the whole page $this->_insertJavascript(); $this->_tmpl->displayParsedTemplate( 'page' ); /* * At this point all processing is done * * The rest is just to support debugger and logger */ $logTime = wbDebugger::getUtime( 'genesis', 1000, 2 ) . 'ms'; $logVersion = phpversion(); $logMemory = ''; if( function_exists('memory_get_usage' ) ) { $logMemory = ceil( memory_get_usage() / 1024 ). 'kb'; } $sessTimer = $this->_sess->getTimer(); wbLog::info( 'site', array( $this->_visitId, 'session', 'count: '. $this->_sess->getCounter(), 'start: ' . date( 'Y-m-d H:i:s', $sessTimer['start'] ), 'elapsed: ' . $sessTimer['elapsed_start'], 'last: ' . $sessTimer['elapsed_last'] ) ); wbLog::info( 'site', array( $this->_visitId, 'process', 'time: ' . $logTime, 'memory: ' . $logMemory, 'php: ' . $logVersion ) ); // debug output if( wbDebugger::isActive() ) { if( $this->_sess->isNew() ) { wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'New session started', 'Session' ); } else { wbDebugger::addMsg( WBSITE_DEBUG_SECTION, $this->_sess->getCounter() . ' requests', 'Session' ); } array_unshift( $debugMsg, 'Total processing time: ' . $logTime ); $msg = implode( "\n", $debugMsg ); wbDebugger::addMsg( WBSITE_DEBUG_SECTION, wbDebugger::sprint( $msg ), 'Stopwatch' ); wbDebugger::printMsg(); } // log some more stuff for each new session if( $this->_sess->isNew() ) { if( isset( $_SERVER['HTTP_USER_AGENT'] ) ) { wbLog::info( 'site', array( $this->_visitId, 'client', 'browser', $_SERVER['HTTP_USER_AGENT'] ) ); } if( isset($_SERVER['HTTP_REFERER'] ) ) { wbLog::info( 'site', array( $this->_visitId, 'client', 'httpreferer', $_SERVER['HTTP_REFERER'] ) ); } $client = $_SERVER['REMOTE_ADDR']; if( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { wbLog::info( 'site', array( $this->_visitId, 'client', 'proxyip', $client ) ); $client = $_SERVER['HTTP_X_FORWARDED_FOR']; } wbLog::info( 'site', array( $this->_visitId, 'client', 'ip', $client ) ); } return true; } /** * get content for action null * * @access public * @param array $conf confiuration for this part * @param string $part named content part * @param string $page named page * @return string $html which is empty */ function getContentNull( $conf, $part, $page ) { return ''; } /** * get content for action staticString * * @access public * @param array $conf confiuration for this part * @param string $part named content part * @param string $page named page * @return string $html */ function getContentStaticString( $conf, $part, $page ) { return $conf['href']; } /** * get content for action staticTemplate * * @access public * @param array $conf confiuration for this part * @param string $part named content part * @param string $page named page * @return string $html */ function getContentStaticTemplate( $conf, $part, $page ) { $tmpl = 'static/' . $conf['href'] . '.tmpl'; // load failed? if( !$this->_tmpl->readTemplatesFromInput( $tmpl ) ) { wbLog::debug( 'error', array( $this->_visitId, 'staticTemplate', $page, $part, $conf['href'], 'Could not load template' ) ); return patErrorManager::raiseWarning( 'wbSite:2', 'Could not insert static content template', 'Loading template: "'. $conf['href'] .'" in part "'. $part.'"!' ); } // NLS $tmplName= $part; if( $this->_lang['lang'] != $this->_config['locale'] ) { $tmplName .= '.' . $this->_lang['lang']; if( !$this->_tmpl->exists( $tmplName ) ) { $tmplName = $part; } } return $this->_tmpl->getParsedTemplate( $tmplName ); } /** * get content for action loadModule * * @access public * @param array $conf confiuration for this part * @param string $part named content part * @param string $page named page * @return string $html or patError */ function getContentLoadModule( $conf, $part, $page ) { if( !isset( $conf['params'] ) ) { $conf['params'] = array(); } $mod =& wbFactory::getModule( $conf['href'], $page, $part, $conf['params'], $this->_request ); if( patErrorManager::isError( $mod ) ) { wbLog::debug( 'error', array( $this->_visitId, 'loadModule', $page, $part, $conf['href'], 'Could not load module' ) ); return $mod; } return $mod->getHtml(); } /** * get content for action loadExtension * * @access protected * @param array $conf confiuration for this part * @param string $part named content part * @param string $page named page * @return string $html */ function getContentLoadExtension( $conf, $part, $page ) { if( !isset( $conf['params'] ) ) { $conf['params'] = array(); } // load extension $ext =& wbFactory::getExtension( $conf['href'], $page, $conf['params'], $this->_request ); if( patErrorManager::isError( $ext ) ) { wbLog::debug( 'error', array( $this->_visitId, 'loadModule', $page, $part, $conf['href'], 'Could not load extension' ) ); return $ext; } // function not available $function = 'get' . $part; if( !is_callable( array( $ext, $function ) ) ) { wbLog::debug( 'error', array( $this->_visitId, 'loadModule', $page, $part, $conf['href'], 'Extension does not provide content for this part' ) ); return patErrorManager::raiseWarning( 'wbSite:3', 'Could not recieve content from extension', 'Extension: "'. $conf['href'] .'" for part "'. $part.'"!' ); } return $ext->$function(); } /** * get content for action cmsHtml * * @access protected * @param array $conf confiuration for this part * @param string $part named content part * @param string $page named page * @return string $html */ function getContentCmsHtml( $conf, $part, $page ) { $cm =& wbFactory::singleton( 'wbContentManager' ); $cm->setLang( $this->_lang['lang'] ); $con = $cm->getContent( $conf['href'] ); if( patErrorManager::isError( $con ) ) { wbLog::debug( 'error', array( $this->_visitId, 'cmsHtml', $page, $part, $conf['href'], 'Could not recieve content' ) ); return $con; } $html = $con['content']; unset( $con['content'] ); $this->_tmpl->addGlobalVars( $con, $part . '_' ); return $html; } /** * insert system vars to templates * * @access protected * @return boolean $result true on success */ function _addGlobalContent() { $get = array(); foreach( $_GET as $key => $value ) { array_push( $get, $key . '=' . $value ); } // add some global data $globals = array( 'page' => $this->_page['name'], 'page_title' => _( $this->_page['title'] ), 'page_brief' => _( $this->_page['brief'] ), 'self' => $_SERVER['PHP_SELF'] . '?' . $this->_sess->getQueryString(), 'sess_name' => $this->_sess->getName(), 'sess_id' => $this->_sess->getId(), 'sid' => $this->_sess->getSID(), 'request_get' => implode( '&', $get ), 'lang' => $this->_lang['lang'], 'lang_form' => $this->_lang['form'] ); $globals['path'] = $this->_page['name']; if( isset( $this->_request['path'] ) && !empty( $this->_request['path'] ) ) { $globals['path'] = $this->_request['path']; } $this->_tmpl->addGlobalVars( $globals ); return true; } /** * add javascript to template * * @access private * @return boolean $result true on success */ function _insertJavascript() { $code = wbJSTools::getCode(); $this->_tmpl->addGlobalVar( 'javascript_code', $code['code'] ); $this->_tmpl->addGlobalVar( 'javascript_onload', $code['onload'] ); return true; } /** * select page depending on request * - choose used page by path or page * - load page config and store it in $_page * * @access private * @return boolean $result true on success * @see $_page */ function _selectPage() { // default-page $page = $this->_config['home']; $path = $page; $conf =& wbFactory::singleton( 'patConfiguration' ); $confDir = $conf->getConfigDir(); // seelct page by path if( isset( $this->_request['path'] ) && !empty( $this->_request['path'] ) ) { $path = $this->_request['path']; $tmp = explode( '/', $path ); if( !empty( $path[ count( $tmp ) - 1 ] ) ) { $page = array_pop( $tmp ); } } // select page directly else if( isset( $this->_request['page'] ) ) { $page = $this->_request['page']; $path = $page; } else { wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'No page selected, use home-page: "'. $page .'"!', 'Page' ); wbLog::info( 'site', array( $this->_visitId, 'home' ) ); } // only accept existing pages if( file_exists( $confDir . '/pages/' . $page. '.xml' ) ) { wbDebugger::addMsg( WBSITE_DEBUG_SECTION, $path, 'Path' ); } else { wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'Page "' . $page . '" not found, use home-page: "'. $this->_config['home'] .'"!', 'Path' ); $page = $this->_config['home']; $path = $page; } wbLog::info( 'site', array( $this->_visitId, 'path', $path ) ); // add page and path to request $this->_request['path'] = $path; $this->_request['page'] = $page; // load page data $conf->loadConfig( '/pages/' . $page . '.xml' ); $this->_page = $conf->getConfigValue( 'page' ); $this->_page['name'] = $page; $this->_page['path'] = $path; // use special layout $layout = $conf->getConfigValue( 'layout' ); if( empty( $layout ) ) { $layout = $this->_config['layout']; } $this->_page['layout'] = $layout; wbDebugger::addMsg( WBSITE_DEBUG_SECTION, $layout, 'Layout' ); return $page; } /** * start authetication handler * * - login user * - inform template engine about current user * * @access private * @return boolean $result true on success */ function _authenticate() { // run user authentication module first - this may affect the session-id! $params = array( 'config' => $this->_config['auth'] ); $auth =& wbFactory::singleton( 'wbAuth', $params ); if( !isset( $this->_request['login'] ) ) { $this->_request['login'] = '_no_action_'; } switch( $this->_request['login'] ) { case 'login': /* * don't try to log in if user is already logged in * * This does not solve the problem, that pressing reload after login starts a new session. * * This is caused, because a successful login creates a news session id and chucks the old * one in the bin. On reload, the browser will send the old (now invalid) session id. The server * cannot find the old session id and create a new session. This will repeat on every reload! */ if( $auth->isAuthenticated() ) { break; } // there is no use for a login attempt without any data - maybe someone hit the login button accidently if( !isset( $this->_request['login_user'] ) || !isset( $this->_request['login_passwd'] ) ) { break; } $res = $auth->login( $this->_request['login_user'], $this->_request['login_passwd'] ); if( patErrorManager::isError( $res ) ) { wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'Login attempt results in error! User "'. $this->_request['login_user'] .'"', 'Login'); wbLog::info( 'site', array( $this->_visitId, 'auth', 'auth', 'error', $this->_request['login_user'] ) ); // error during login - try to continue break; } if( $res ) { // login successful wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'Login succeeded! User "'. $this->_request['login_user'] .'"', 'Login'); wbLog::info( 'site', array( $this->_visitId, 'auth', 'login', 'ok', $this->_request['login_user'] ) ); wbEvent::trigger( 'site:auth:login', _( 'User "{USER}" authenticated at {DATE}' ), array( 'user' => $this->_request['login_user'] ) ); $userData = $auth->getUserData(); if( !empty( $userData['lang'] ) ) { $this->_initLang( $userData['lang'] ); wbLog::info( 'site', array( $this->_visitId, 'locale', 'language', 'login', $userData['lang'] ) ); } } else { // login failed $this->_tmpl->setAttribute( 'login_failed', 'visibility', 'visible' ); $this->_tmpl->addGlobalVar( 'login_user', $this->_request['login_user'] ); wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'Login attempt failed! User "'. $this->_request['login_user'] .'"', 'Login' ); wbLog::info( 'site', array( $this->_visitId, 'auth', 'login', 'failed', $this->_request['login_user'] ) ); wbEvent::trigger( 'site:auth:failed', _( 'User "{USER}" authentication failed at {DATE}' ), array( 'user' => $this->_request['login_user'] ) ); } break; case 'logout': // don't try to log out if noone is logged in! if( !$auth->isAuthenticated() ) { break; } $userData = $auth->getUserData(); $res = $auth->logoff(); if( patErrorManager::isError( $res ) ) { return $res; } wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'User "'. $userData['user'] .'" logged out!', 'Login' ); wbLog::info( 'site', array( $this->_visitId, 'auth', 'logout', 'ok', $userData['user'] ) ); wbEvent::trigger( 'site:auth:logout', _( 'User "{USER}" logged out at {DATE}' ), array( 'user' => $userData['user'] ) ); break; // neither login or out default: break; } if( $auth->isAuthenticated() ) { $this->_tmpl->addVar( 'login', 'authenticated', 'yes' ); $userData = $auth->getUserData(); $this->_tmpl->addGlobalVars( $userData, 'user_' ); wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'Current User "'. $userData['user'] .'"', 'Auth' ); } return true; } /** * configure NLS * * @access private * @param string $domain used default domain * @return boolean $result true on success */ function _localize( $domain ) { if( isset( $this->_request['lang'] ) ) { if( in_array( $this->_request['lang'], $this->_config['languages'] ) ) { $this->_initLang( $this->_request['lang'] ); wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'Set session lang to "'.$this->_request['lang'].'"', 'Lang' ); wbLog::info( 'site', array( $this->_visitId, 'locale', 'language', 'session', $this->_request['lang'] ) ); } else { wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'Selected unknown session language "'.$this->_request['lang'].'"', 'Lang' ); wbLog::info( 'site', array( $this->_visitId, 'locale', 'language', 'init', $this->_config['locale'] ) ); } } if( !$this->_sess->has( 'wb:lang' ) ) { $this->_initLang(); } $this->_lang = $this->_sess->get( 'wb:lang' ); wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'Using language "'.$this->_lang['lang'].'"', 'Locale' ); // register text domains bindtextdomain( 'wombat', wbFactory::getParam( 'systemDir' ) . '/var/lang' ); bind_textdomain_codeset( 'wombat', 'UTF-8' ); bindtextdomain( $this->_config['locale_domain'], wbFactory::getParam( 'baseDir' ) . '/' . wbFactory::getParam( 'varDir' ) . '/lang' ); bind_textdomain_codeset( $this->_config['locale_domain'], 'UTF-8' ); textdomain( $domain ); setlocale( LC_ALL, $this->_lang['lang'] . '.UTF-8' ); return true; } /** * setup langauge container * * @access public * @param string $tmpl templates base name * @return boolean $result true on success */ function _initLang( $lang = null ) { $set = false; if( $lang ) { wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'New session language "'. $lang . '"', 'Language' ); $set = true; } else if( !$this->_sess->has( 'wb:lang' ) ) { wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'Session language from config "'. $this->_config['locale'] . '"', 'Language' ); $lang = $this->_config['locale']; $set = true; } // save new session language if( $set ) { $this->_lang = array( 'lang' => $lang, 'form' => $lang, ); if( $lang != 'C' ) { $this->_lang['form'] = substr( $lang, 0, 2 ); } $this->_sess->set( 'wb:lang', $this->_lang ); } return true; } /** * run authorisation plugin * - start auth module * - mangle page-config if necessary * * @access private * @return boolean $result true on success */ function _authorize() { $module = $this->_config['auth']['module']; $param = $this->_config['auth']['param']; if( isset( $this->_page['auth'] ) && !empty( $this->_page['auth'] ) ) { $module = $this->_page['auth']['module']; $param = $this->_page['auth']['param']; } $auth =& wbFactory::singleton( 'wbAuthorize' ); $auth->setRule( $module, $param ); $result = $auth->checkAuthorisation(); // error if( patErrorManager::isError( $result ) ) { return $result; } // authorisation completed if( $result ) { return true; } // otherwise change change page-settings foreach( $this->_config['auth']['denied'] as $part => $conf ) { $this->_page['content'][$part] = $conf; } wbDebugger::addMsg( WBSITE_DEBUG_SECTION, 'Permission denied! Module: "'. $module.'" Parameter: "'. $param.'"', 'Authorisation' ); wbLog::info( 'site', array( $this->_visitId, 'auth', 'permission', 'denied', $module, $param ) ); return false; } /** * display error message * * @access private * @param string $part content area to insert error message * @return boolean $result true on success * @see */ function _insertErrorContent( $part ) { if( !$this->_tmpl->exists( 'error_' . $part ) ) { $this->_tmpl->readTemplatesFromInput( $this->_config['errortemplate'] . '.tmpl' ); } // $this->_tmpl->parseIntoVar( 'error_' . $part, 'page', $part ); /* * workaround for patTemplate bug in parseIntoVar */ $err = $this->_tmpl->getParsedTemplate( 'error_' . $part ); $this->_tmpl->addVar( 'page', $part, $err ); return true; } } ?>