/*

 This class is to handle the caching of html pages, css and javascript for a website

 It should save off static copies of the website, and with minimal of processing, supply it to the browser

 Founding principles:

 - avoid MySql completely, as it is slow to connect to, especially on our system where it is on a separate server

 - minimise PHP - ie don't load any big classes if we can avoid it

 - I'd avoid PHP too if I was good enough (I'm not)

 - pages need to be stored in such a way that they are portable, ie can be sent or served from an ASP server for example
 
 AND lastly a note - certain pages cannot be cached - forms for instance, or at least form responses, so a website needs a way of skipping caching

 - we could assume that if there are post variables, we shouldn't cache, perhaps

 */

class website_cache
{

	const STATUS_LOCKED = 'locked';
	const STATUS_CACHED = 'cached';
	const STATUS_FLUSHED = null;
	const STATUS_EXPIRED = 'expired';

	private $_uri = '';
	private $_cacheFilePath = null;
	private $_cacheFileName = null;
	private $_cacheAge = 0;
	private $_fileType = 'html';
	private $_status = null;
	
	protected $_fileTypes = array(
		'html' => 'text/html',
		'css' => 'text/css',
		'js' => 'application/javascript'
	);

	public function __construct ($uri)
	{		
		if(!$this->setupURI($uri))
			return false;
		
		$this->_setStatus();
	}

	/**
	 * Parse the URI and set the filename and dir of the cache file
	 * @param string $uri 
	 * @return bool
	 */
	
	public function setupURI ($uri)
	{			
		// MAKE SAFE!!!
		$uri = preg_replace ('~[^a-z0-9\-_\/\+\.]~i', '', $uri) ;
		
		// Check that we have some content in there
		if (! empty($uri))
			$this->_uri = $uri;
		else
			$this->_uri = 'index.html';
		
		// Grab the filetype via a regex
		if(preg_match("/\.([^\.]+)$/", $uri, $matches))
			$this->_fileType = $matches[1];
		
		// We dont recognise this 
		if(! in_array($this->_fileType, array_keys($this->_fileTypes)))
			return false;
		
		// make the cache path
		$this->_cacheFileName = md5($uri);
		$cacheSubDir = substr($this->_cacheFileName, 0, 1);
		$this->_cacheFilePath = CACHE_PATH.$cacheSubDir.'/';
		return true;
	}

	/**
	 * Flushes the cache for the URL you are requesting
	 * @return bool $bool
	 */
	
	public function flush()
	{
		@unlink($this->_getFullCachePath());
		@unlink($this->_getAgeFilePath());
		@unlink($this->_getLockFilePath());
		
		$this->_status = self::STATUS_FLUSHED;
		
		return true;
	}

	/**
	 * Locks the cache
	 * @todo make this static
	 * @return bool
	 */
	
	public function lock()
	{
		if($this->isLocked())
			return false;
		
		if(!$this->isCached())
			return false;
		
		file_put_contents($this->_getLockFilePath(), time());
		$this->_status = self::STATUS_LOCKED;
		return true;
	}

	/**
	 * Unlocks the cache
	 * @return bool
	 */
	
	public function unlock()
	{
		if(!$this->isLocked())
			return false;
		
		if(!$this->isCached())
			return false;
		
		unlink ($this->_getLockFilePath()) ;
		$this->_status = self::STATUS_UNLOCKED;
		return true;
	}

	/**
	 * Returns the current status of the file.
	 * 
	 * @return string
	 */
	
	public function getStatus()
	{
		return $this->_status;
	}

	/**
	 * Sets the status of the cache based upon the status of the cache file
	 * 
	 * @return string
	 */
	
	private function _setStatus()
	{
		// @todo How to deal twith new pages?
		
		if(file_exists($this->_getFullCachePath()))
			$this->_status = self::STATUS_CACHED;
		
		// If the file is cached, check the age
		if(file_exists($this->_getAgeFilePath()))
		{
			$this->_cacheAge = trim(file_get_contents($this->_getAgeFilePath()));
			$this->isExpired();
		}
		
		if(file_exists($this->_getLockFilePath()))
			$this->_status = self::STATUS_LOCKED;
		
		return $this->_status;
	}

	/**
	 * Cache is expired
	 * 
	 * @return bool 
	 * @todo look into making this a static call
	 */
	
	public function isExpired()
	{
		if ($this->_cacheAge + CACHE_LIFETIME < time())
		{
			$this->_status = self::STATUS_EXPIRED;
			return true;
		}
		
		return false;
	}


	/**
	 * Returns a true if a lock file exists for the cache file
	 * 
	 * @return bool
	 * @todo look into making this a static call
	 */
	
	public function isLocked()
	{
		return ($this->_status == self::STATUS_LOCKED);
	}

	/**
	 * Returns true if the cache file already exists, a cache file exists if the status is not null
	 *
	 * @return bool
	 * @todo look into making this a static call
	 */
	
	public function isCached()
	{
		if($this->_status != null)
			return true;
		return false;
	}
	
	/**
	 * Returns the filename and the full path of the cache file
	 * @return string
	 */
	
	private function _getFullCachePath()
	{
		return $this->_cacheFilePath.$this->_cacheFileName;
	}
	
	/**
	 * Returns the path of the cache file
	 * 
	 * @return string
	 */
	
	private function _getLockFilePath()
	{
		return self::_getFullCachePath() . '.lck';
	}

	/**
	 * Returns the filename of the age file
	 * 
	 * @return string
	 */
	private function _getAgeFilePath()
	{
		return self::_getFullCachePath() . '.age';
	}

	/**
	 * Save the cache file to the system
	 * 
	 * @param string $content
	 * @return bool 
	 */
	
	private function _save($content)
	{
		// Only want to resave the content if it's not locked or not cached
		if($this->isCached())
		{
			if( (!$this->isExpired()) and ($this->isLocked()) )
				return false;
		}

		//if (! ($this->getMode () == 'default' || $this->getMode () == 'flush') && !$this->isLocked () && !$this->hasValidCache () )
		//	return false;
		if(! file_exists($this->_cacheFilePath))
			mkdir ($this->_cacheFilePath, 0775, true);
		
		// Based upon the file type we cache in different ways.
		// @todo improve the way that this is working to enable us to cache other file
		switch($this->_fileType)
		{
			case 'html':
				// if there is a head tag, then put in a meta tag, otherwise add a comment
				if (strpos ($content, '') !== FALSE)
					$content = str_replace ('', '' . "\n" . '', $content) ;
				break;
			case 'css':
				$content = '/* cacheDate: ' . date (DATE_RFC822) . ' */' . "\n" . $content;
				break;
			case 'js':
				$content = '/* cacheDate: ' . date (DATE_RFC822) . ' */' . "\n" . $content;
				break;
		}
		
		if(! file_put_contents ($this->_getFullCachePath(), $content))
			return false;
			
		/// we need to save a timestamp into this file so we can see what we are looking at.
		file_put_contents ($this->_getAgeFilePath(), time() ) ;
		$this->_status = self::STATUS_CACHED;

		return true;
	}

	/**
	 * Loads the cached content
	 * 
	 * @return string
	 */
	private function _load()
	{
		// page is not cached
		if (! $this->isCached())
			return false;
		
		// Page is cached is not locked and has expired
		if((! $this->isLocked() ) and ($this->isExpired()))
			return false;
		
		/**
		 * @todo Do we need to send a proper cache header too.
		 * header("Expires: " . gmdate("D, d M Y H:i:s",$expires) . " GMT");
		 * header("Cache-Control: max-age=3600, must-revalidate");
		 */
		
		// Send the relevant header
		header("Content-type: ".$this->_fileTypes[$this->_fileType]."; charset=utf-8");
		
		exit(file_get_contents($this->_getFullCachePath()));
	}
	
	/* static methods */

	public static function retrieveCache ()
	{
		
		if (count($_POST) || count($_GET) > 1) {
			//exit (' no cache ');
			return false;
		}
		$cacheObject = new website_cache ($_SERVER["REQUEST_URI"]);
		
		// cacheObject could be false because somebody is trying to cache an odd extension
		if($cacheObject)
			$cacheObject->_load();
			
	}

	/**
	 * Creates a cache file if one does not exist or the cache is out of date
	 * 
	 * @static
	 * @param type $cacheObject
	 * @param type $content
	 * @return type 
	 */
	
	public static function createCache ($content)
	{
		// never cache the page if:
		// - the page request contains a querystring
		if (count($_POST) || count($_GET) > 1 || defined('NOT_CACHEABLE')) {
			return false;
		}
		
		flush();
		$cacheObject = new website_cache($_SERVER['REQUEST_URI']);
		// cacheObject could be false because somebody is trying to cache an odd extension
		if($cacheObject)
			$cacheObject->_save($content);
		
		return $cacheObject;
	}

}
/**
 * generic dynamic website
 *
 * @author Ian
 * @package website
 * @version 2.0 2009-10-29 
 * @subpackage core
 */
class website_dynamic extends website_static {

	// a static website is a set of page, with static php templates, which are stored in a directory
	// and identified by the pageRequest item in the link
	private $dataRequirement = array();
	
	private $databaseToQuery='';
	private $databaseTableToQuery;
	
	private $defaultPageRequest;
	private $linkedTables = array();
	private $idToAskFor;
	private $usefulPIDs = array();
	private $mediaSpec;
	private $templateTableName = '';
	private $footerTemplateObject;
	
	// PARENTAGE
	
	private $parentage = array();
	private $children = array();
	
	public function __construct() {
		
		// mobile redirect, if appropriate - before all other calls - 
		// has to be here because this is the first point where we have an instance of the website (overridable) AND Client and Config set up.
		if (Config::getConfig()->getPreference('websiteEnableMobileRedirect')) $this->mobileRedirect();
		
		$this->setDataBaseName("page");
		$this->setDefaultPageRequest("page");
		// soon to change to pageTemplate
		$this->setTemplateTableName('pageTemplate');
		
		$this->addDataRequirement("name");
		$this->addDataRequirement("text1");
		
		$this->setIDFromURL();
		
		if (Config::exists()) 
			$this->setGoogleAnalytics(Config::getConfig()->getPreference('googleAnalyticsCode'));
		
		parent::__construct();
	}
	
	protected function setDataBaseName ($tableName,$dbName='') {
		if (is_string($tableName) && strlen($tableName)) $this->databaseTableToQuery = helper_string::sqlescape($tableName);
		if (is_string($dbName) && strlen($dbName)) $this->databaseToQuery = helper_string::sqlescape($dbName);	
	}
	public function getDataBaseName () { return $this->databaseTableToQuery; }
	public function getDataBase () { return ($this->databaseToQuery?$this->databaseToQuery.'.':''); }
	
	protected function setTemplateTableName ($data) { if (is_string($data) && strlen($data)) $this->templateTableName = helper_string::sqlescape($data); }
	public function getTemplateTableName () { return $this->templateTableName; }

	protected function setDefaultPageRequest ($data) { if (is_string($data) && strlen($data)) $this->defaultPageRequest = helper_string::sqlescape($data); }
	protected function getDefaultPageRequest () { return $this->defaultPageRequest; }

/**
 * set a default pageid
 */
	protected function setDefaultID ($data) {
		$this->setID( $data );	
		// and change the page request accordingly so that new links are correct
		// $pageid??
		//PageRequest::getPageRequest()->getLink()->setRecordID( $pageid );
		PageRequest::getPageRequest()->getLink()->setRecordID( $this->getID() );
		PageRequest::getPageRequest()->getLink()->setPageRequest( $this->getDefaultPageRequest() );
	}
	protected function setDefaultIDByTemplateName ($templateName) {

		list($pageid) = $this->getPageIdByTemplateName( $templateName );
		if ($pageid) $this->setDefaultID($pageid);
		
																
	}
	protected function setDefaultIDByTreeRoot () {
	
		$datasource = Client::getClient()->getDatasource();
		
		list($pageid) = $datasource->get1row("select ".$this->getDataBaseName()."id
			from ".$this->getDataBase().$this->getDataBaseName()."
			where sectionid = 0
			and approved = 1
			order by position asc
			limit 1");
	
	
		$this->setDefaultID( $pageid );	
		
	}
	
	protected function setIDFromURL () {
		//print "getPageRequest";
		$link = PageRequest::getPageRequest()->getLink();
		
		$idToAskFor = $link->getRecordID();
		
		if ($idToAskFor) $this->setID($idToAskFor);
	}
		
	protected function setID ($data) {
		if ( (int) $data > 0 ) {
			$this->idToAskFor = (int) $data;
	 	//print "set id:".$data;
		}
	}
	public function getID () { return $this->idToAskFor; }
	
	
	public function addToParentage ( $pageid,$name,$themeid=0 ,$passwordProtect=0) {
		
		//we don't want the footer to appear as the parent in both breadcrumb and backto
		list($footerID) = $this->getPageIdByTemplateName( 'footer' );
		
		if($pageid != $footerID){
			$this->parentage[] = array(
			   "id"=>$pageid,
			   "name"=>$name,
			   "themeid"=>$themeid,
			   "passwordProtect"=>$passwordProtect
			);
		}
		
	}
		
	public function getParentage()
	{
		return $this->parentage;
	}
	
	public function getChildren()
	{
		return $this->children;
	}
	
	// @todo we could make this a more flexible function so that we can call it with a pageId
	protected function establishParentage()
	{
		$ds = Client::getClient()->getDatasource();
		
		$sectionid = $this->getID();
	
		$i = 0;
		while($sectionid > 0 && $i<=10)
		{
			$pageInfo = $ds->get1row("select sectionid,name,".$this->getDataBaseName()."Themeid,passwordProtect from ".$this->getDataBase().$this->getDataBaseName()." where ".$this->getDataBaseName()."id = '".$sectionid."'");
			$this->addToParentage( $sectionid, $pageInfo['name'], $pageInfo['pageThemeid'], $pageInfo['passwordProtect']);
			
			$sectionid = $pageInfo['sectionid'];
			
			$i++;
			//break;
		}
		
	}
	protected function findChildrenQuery () {
		/* IF YOU CHANGE THIS FUNCTION - PLEASE REMEMBER THAT THERE IS A VERY SIMILAR DUPLICATE IN TEMPLATE  - FOOTER*/
		
		/* ensure that shortDescription and thumbnail are included in query */
		$children = new Index ( Client::getClient() );
		$children->setTable( $this->getDataBase().$this->getDataBaseName() );
		$children->addField('text1');
		$children->addField('shortDescription');
		$children->addField('thumbnail','json');
		$children->addField('name');
		$children->addField($this->getTemplateTableName().'.className as templateName');// 
		$children->addField($this->getDataBaseName().'Themeid as themeid');// 
		$children->setSortable();
		$children->addCondition('sectionid',$this->getID());
		$children->addCondition('inchildnav',1);
		$children->addCondition('approved',1);
		$children->addJoin($this->getDataBase().$this->getTemplateTableName());
		return $children;
	}
	protected function findChildren () {
		/* MORENA LOOK HERE*/
		/* ensure that shortDescription and thumbnail are sent through to the childnav array */
		$children = $this->findChildrenQuery();
		$children->processIndex();
		foreach ($children->getResults() as $child) {
			$this->addToChildren( $child );
		}
		return $children;
	}
	public function addToChildren ( $child ) { $this->children[] = $child; }
	
	protected function checkAccessRights () {
		// find the first password protected page in the parentage
		foreach ($this->getParentage() as $parent) {
			if ($parent['passwordProtect']) {
			
				// mark as not cacheable
				define('NOT_CACHEABLE',true);		
				
				// tbc
				if (Client::getClient()->isAllowed( $this->getDatabaseName(), $parent['id'] )) {
				
					return true;
				}
				// then work out if user has the right to view the page by bouncing request of the client		
				return false;			
			}
		}
		return true;
	}
	
	
	// TEMPLATE NAME
	
	
	
	public function getTemplateName () {
		// template name here is dynamic - it comes on the basis of what the client is asking for - 
		// page/14 would look in a page table for the template page.
		// print $this->getTemplateName();
		
		$client = Client::getClient();
		if (!is_object($client)) exit ("You must initiate the Client object to get this to work.");
		
		
		
		// is the querystring request the "accountDetails" page? (only a logged in user can see it, to change his details)
		$username = Client::getClient()->getSession()->getUsername();
		//if( isset($_REQUEST['accountDetails']) ) Zend_Registry::get("log")->debug("SECOND PAGE ?accountDetails=1: ".print_r($_SESSION,true));
		//@todo REMOVED by IB 6/10/2011 remove this horrible hacky flag  Not working properly so removing for next release 2.3.2
		//if( $username && (isset($_REQUEST['accountDetails']) || isset($_REQUEST['doAccountDetails'])) ) return 'accountDetails'; // template name: 'accountDetails'
		
		// is the querystring request the "forgottenPassword" page?
		// @todo REMOVED by CL 28/07/2011 - Not working properly so removing for next release 2.3.1
		//if( isset($_REQUEST['forgottenPassword']) || isset($_REQUEST['doForgottenPassword']) ) 
		//	return 'forgottenPassword'; // template name: 'forgottenPassword'
		
		// is this page protected? if so, and the user is not logged in, show him the login page
		if( !$this->checkAccessRights() ) 
			return LOGIN_CLASS_NAME;
		
		$datasource = Client::getClient()->getDatasource();
		
		list($templateName,$mediaSpec,$cacheable) = $datasource->get1row("select 
																".$this->getTemplateTableName().".className,
																".$this->getTemplateTableName().".mediaSpec ".
																(CACHE_ENABLE?','.$this->getTemplateTableName().'.isCacheable':'')
																
																."
															
															from ".$this->getDataBase().$this->getDataBaseName()."
															
															inner join ".$this->getDataBase().$this->getTemplateTableName()." using (".$this->getTemplateTableName()."id)
																where ".$this->getDataBaseName()."id = '".$this->getID()."' limit 1");
		
		// mark as not cacheable
		if (CACHE_ENABLE && !$cacheable)
			define('NOT_CACHEABLE',true);	
				
		// exit if the template name is footer - footers are not navigable
		if ($templateName == 'footer') { header('Location: /'); exit; }
		
		if ($mediaSpec) $this->setMediaSpec($mediaSpec);
		//if (!$templateName) $templateName = "default";
		if (!$templateName) $templateName = "homepage";
		//print $databaseToQuery; exit;

		return $templateName;
		
	}
	private function setMediaSpec ( $jsonSpec ) {
		//print "
".$jsonSpec;
		$this->mediaSpec = json_decode( $jsonSpec,true ); 
	}
	public function getMediaSpec () {
		return $this->mediaSpec;
	}
	
	public static function getMediaSpecByPageId ($pageid, $table = 'page',$templateTable='pageTemplate') {
		
		if (!$pageid) return array();
		
		if ( method_exists  ( $this  , 'getDataBaseName'  ) ) {
			$tableString = $this->getDataBaseName();
			$templateString = $this->getTemplateTableName();
		} else {
			$tableString = $table;
			$templateString = $templateTable;
		}
		
		$datasource = Client::getClient()->getDatasource();
		
		list($templateid,$mediaSpec) = $datasource->get1row("select ".$templateString."id,mediaSpec from ".$templateString." inner join ".helper_string::sqlescape($tableString )."
															 using (".$templateString."id)
																where ".helper_string::sqlescape($tableString )."id = '".(int) $pageid."' limit 1");
		return json_decode( $mediaSpec,true );
	}

	public function getPageIdByTemplateName ($templateName, $table = 'page', $templateTable = 'pageTemplate') {
		
		// use table and templateTable dynamically if possible
		
		if ( method_exists  ( $this  , 'getDataBaseName'  ) ) {
			$db_tableString = $this->getDataBase().$this->getDataBaseName();
			$tableString = $this->getDataBaseName();
			$db_templateString = $this->getDataBase().$this->getTemplateTableName();
			$templateString = $this->getTemplateTableName();
		} else {
			$db_tableString = $table;
			$tableString = end(explode('.',$table));
			$db_templateString = $templateTable;
			$templateString = end(explode('.',$templateTable));
		}
		
		$doSearch = false;
		if (!method_exists  ( $this  , 'getDataBaseName'  )) $doSearch = true;
		else if (!$this->usefulPIDs[$templateName]) $doSearch = true;
		
		if ($doSearch == true) {
			
			$templateName = helper_string::sqlescape($templateName);
			$tableString = helper_string::sqlescape($tableString);
			$db_tableString = helper_string::sqlescape($db_tableString);
			$db_templateString = helper_string::sqlescape($db_templateString);
			
			$sql = "select ".$tableString.".name,".$tableString.".".$tableString."id from ".$db_tableString." inner join ".$db_templateString." using (".$templateString."id) where ".$templateString.".className = '".$templateName."' limit 1";
			
			list($pageName,$pageid) = Client::getClient()->getDatasource()->get1row($sql);
			$this->usefulPIDs[$templateName] = array($pageid,$pageName);
		}
		return $this->usefulPIDs[$templateName];
	//	usefulPIDs;
	}
	
	protected function addDataRequirement ($input,$type='') {
			// very important to clean the data;
		$input = helper_string::sqlescape($input);
		if ($input) $this->dataRequirement [] = array('field'=>$input,'type'=>$type);
	}
	
	protected function getDataRequirement () {
	
		$output = $this->dataRequirement;
		return $output;
	
	}
	private function addLinkedTable ($tableName) {
		if (array_search($tableName,$this->linkedTables) === FALSE ) {
			$this->linkedTables[] = $tableName;
		}
	}
	private function getLinkedTables () {
		return $this->linkedTables;
	}
	
	protected function addWidgets() {
		
		if (Client::getClient()->getDatasource()->tableExists($this->getDataBase().$this->getDataBaseName()."Widget")) {
			
			$template = $this->getTemplate();
			// get excluded widgets for this page
			$widgetExcludeArray = array();
			$widgetexclude = new Index (Client::getClient(), $this->getDataBase().$this->getDataBaseName().'WidgetExclude');
			$widgetexclude->addField($this->getDataBaseName().'Widgetid');
			$widgetexclude->addCondition($this->getDataBaseName().'id',$this->getID());
			$widgetexclude->processIndex();
			foreach ($widgetexclude->getResults() as $we) $widgetExcludeArray [] = $we[$this->getDataBaseName().'Widgetid'];
			
			// get widgets
			//WIDGET_PATH
			$widgets = new Index (Client::getClient(), $this->getDataBase().$this->getDataBaseName().'Widget');
			$widgets->addField('name');
			$widgets->setOrder($this->getDataBaseName().'Widget.position asc, '.$this->getDataBaseName().'Widget.'.$this->getDataBaseName().'Widgetid asc');
			$widgets->addCondition('approved',1);
			if (count($widgetExcludeArray)) $widgets->addNotIn($this->getDataBaseName().'Widgetid',$widgetExcludeArray);
			$widgets->processIndex();
			foreach ($widgets->getResults() as $widget) $template->addWidget( WIDGET_ROOT.'_'.$widget['name'] );
		}
	}
	
	protected function createNav () {
		return new website_navigation_dynamic ();	
	}
	
	

	public function getCrossSellMediaSpec () {
		return Config::getConfig()->getPreference('pages_crossSellMediaSpec',true);
	
	}
	public function getThemeMediaSpec () {
		return Config::getConfig()->getPreference('pages_themeMediaSpec',true);
	}
	
	
	public function processWebsite ( $formData = array() ) {
		
		// if there is no ID set, then we must get it from the default
		if (!$this->getID())
			$this->setDefaultIDByTemplateName("homepage");
			
		if (!$this->getID())
			$this->setDefaultIDByTreeRoot();
		
		if (!$this->getID())
			$this->setDefaultID(1);
			
		/*
		MAIN QUERY - GETTING THE RECORD DATA
		*/
		// find the parentage of the template
		$this->establishParentage();
		$this->findChildren();
		// data comes from the record
		// find out the template's data requirement, then ask the database for that data.
	
		$template = $this->getTemplate();
		
		foreach ($template->getDataRequirement() as $field) {
			$this->addDataRequirement( $field['field'],$field['type'] );
		}
		
		$dataRequirement = $this->getDataRequirement();
		
		// get the data for the page
		$dbData = array();
		if (count($dataRequirement)) {
		
			// REPLACE WITH INDEX
			$pageQuery = new Index ( Client::getClient() , $this->getDatabase().$this->getDataBaseName() );
			foreach ($dataRequirement as $field) $pageQuery->addField($field['field'],$field['type']);
					
			foreach ($this->getLinkedTables() as $table) {
				$pageQuery->addJoin($table);
			}
					
			$pageQuery->addCondition( 		$this->getDataBaseName()."id", 		$this->getID() );
			$pageQuery->setPerPage(1);
			
			$pageQuery->processIndex();
			
			/* IF NO PAGE IS FOUND, THEN WE NEED TO FIRE A 404 ERROR */
			/* OR PERHAPS DO A 301 TO A 404 returned page */
			/* throw a 404 and redirect to homepage */
			/* note - will only get called if the link looks like a 'classic' link but the page doesn't exist: /6/Contact-us/12/asd */
			if ($pageQuery->numRows() == 0) {
				$e404 = new website_error404 ('/');
				$e404->getPage();
			}
			
			$dbData = $pageQuery->getFirstResult();
			
			$dbData = $this->getTranslation ( $dbData );
			
		}
		// override the default navigation to add the database actions
		
	//print '1';
		// set up the basics (from website.inc.php)
		
	//	print '2';
		$template = $this->getTemplate();
		
	//	print '3';
		
		$this->addWidgets();
		
		$template->processTemplate ( $dbData, $formData );
		
		// widgets need to be called AFTER template, as some require data from the template
		// as such, the widget processing was removed from template->processTemplate() and given its own method:
		$template->processWidgets();
		
	//print '4';
		//parent::processWebsite( $dbData );
	
		// and populate navigation, crucially after parent functions have been run which decide which navigation to use
		if (is_object($this->getNav()))
			if (!$this->getNav()->getPopulated())
				$this->getNav()->getLinksFromDatabase
				($this->getID(),$this->getDataBaseName(),0,false,$this->getDefaultPageRequest());
	//print '5';
		
		// populate the footer
		$this->processFooter();
		
		
	}
	
	//Translations
	protected function getTranslation ( $dbData ) {
	
		$selectedLanguage = Client::getClient()->retrieve('language');
		// no selected translation
		if (!strlen($selectedLanguage)) return $dbData;
		
		// otherwise we do a query against the pageTranslation table, and swap out any content that we find
		
		$translationIndex = Index::createIndex('pageTranslation');
		
		$fieldsArray = array('name');
                //get the fields from the Database eg text1, text2, text3.....
		for($i=1;$i<=7;$i++)
			$fieldsArray[] = 'text'.$i;
		
		
		foreach ($fieldsArray as $field)
			$translationIndex->addField($field);
		
		$translationIndex->addCondition('linkid',$this->getID());
		$translationIndex->addCondition('language',$selectedLanguage);
		
		$translationIndex->processIndex();
		//get the frst result ie single result
		$result = $translationIndex->getFirstResult();
		
		// if there is a result, swap out the data
		
		if (count($result)) {
			
			foreach ($fieldsArray as $field) $dbData [$field] = $result[$field];
		}
		
		return $dbData;
		
	}
	
/* checks if the footer is installed and enabled, starts the footerTemplateObject, finds the data for the template page, and sends it to the template then makes the HTML
* return string, the html for the footer
*/	
	protected function processFooter ()
	{
		
		if (Config::getConfig()->getPreference('pages_enableDynamicFooter'))
		{
		
			$footerTemplateName = APP_TEMPLATE_URL."_footer";
			$footerTemplateObject = new $footerTemplateName ( $this );
			$footerTemplateObject->setWebsite($this);
			
			$dataRequirement = $footerTemplateObject->getDataRequirement();
			
			// find the data for the template page, and send it to the template
			$footerQuery = Index::createIndex('page');
			foreach ($dataRequirement as $dr)
				$footerQuery->addField( $dr['field'],$dr['type'] );
			$footerQuery->addJoin('pageTemplate');
			$footerQuery->addCondition('pageTemplate.className','footer');
			$footerQuery->setPerPage(1);
			$footerQuery->processIndex();
			
			$footerData = $footerQuery->getFirstResult();
			
			$footerTemplateObject->processTemplate ( $footerData );
			
			$this->setFooter($footerTemplateObject->makeHTML());
		
		}
		
		
	}
	
	public function makeHTML () {
		// add the template body class onto the templates
		$this->getBody()->setID( "p".$this->getID() );
		
		// process the footer
		
		return parent::makeHTML();
		
	}
	
	
	public function factoryAutoLogin() {
		if( isset($_REQUEST['autoLogin']) ) {
			Client::getClient()->doAutoLogin($_REQUEST);
		}
	}
	
	public function factoryLogin () {
		if (isset($_REQUEST['logOut'])) {
			Client::getClient()->logOut();
		} else {
			//	print 'do login';
			Client::getClient()->doLogin ($_REQUEST);
			
		}
	}
	
	/* redirect for sites to use to bounce to mobile site */
	protected static function mobileRedirect () {
		// if there is a flag 'backtomainsite' OR a session of the same name, DO NOT redirect, otherwise go to the mobile URL in preferences
		if ( isset($_REQUEST['backtomainsite']) ) setcookie("backtomainsite", true, time()+86400);
		if ( isset($_REQUEST['backtomainsite']) || $_COOKIE['backtomainsite']) return false;
		// otherwise browser test and bounce
		$ua = $_SERVER['HTTP_USER_AGENT'];
		$checker = array(
			  'iphone'=>preg_match('~iPhone|iPod~i', $ua),//|iPad
			  'blackberry'=>preg_match('~BlackBerry~i', $ua),
 			  'android'=>preg_match('~Android~i', $ua)
		);
		if ($checker['iphone'] || $checker['android']) {
				header("Location: http://".Config::getConfig()->getPreference('websiteURL_mobile').$_SERVER["REQUEST_URI"]);
			 	exit;
		}
	}
	
	
	public static function factory ( $className, $database,$databaseUsername,$databasePassword ) {
		// get the config layer
		Config::setUp(CONFIG_DB,$databaseUsername,$databasePassword);
		// now sort out the client and log them in if you need
		$client = Client::setUp($database,$databaseUsername,$databasePassword);
		// this is the page that the person asked for.
		PageRequest::setUp($_SERVER['REQUEST_URI']); //, "codeBase_link"

		// then make them a website!
		$website = new $className ();
		$website->factoryAutoLogin();
		$website->factoryLogin();
		$website->processWebsite(); // $_REQUEST 

		header("Content-type: text/html; charset=utf-8");

		if (isset($_REQUEST['ajax'])) {
			return $website->makeForAjax();
		} else {
			return $website->makeHTML();
		}
		
	}
	

}
	


/**
 * generic static website
 *
 * @author Ian
 * @package website
 * @subpackage core
 * @version 2.0 2009-10-29 
 */
class website_static extends Website {

	// a static website is a set of page, with static php templates, which are stored in a directory
	// and identified by the pageRequest item in the link

	private $templateObject;
	private $templateName; // name to instantiate
	
	public function __construct () {
		
		if (!is_object(PageRequest::getPageRequest() )) //throw new Error 
			exit ('PageRequest is not inititated. You must call PageRequest::setUp($_SERVER[\'SCRIPT_NAME\'].$_SERVER[\'PATH_INFO\']); before you initiate a Website');
		
		parent::__construct();
		
	}
	
	
	public function setTemplateName ( $data ) { $this->templateName = $data; }//helper_string::sqlescape( }
	public function getTemplateName () {
		return PageRequest::getPageRequest()->returnPageName();
	
	}

	protected function checkSSL ( $templateObject ) {
		if ($templateObject->getSSLRequired() && $_SERVER['SERVER_PORT'] == 80) {
			// redirect to secure version of page
			header('Location: https://'.$_SERVER['HTTP_HOST'].PageRequest::getPageRequest()->getLink()->makeLink());
			exit;
		} elseif(!$templateObject->getSSLRequired() && $_SERVER['SERVER_PORT'] == 443) {
			// redirect to normal version of page
			header('Location: http://'.$_SERVER['HTTP_HOST'].PageRequest::getPageRequest()->getLink()->makeLink());
			exit;
		}	
	}


	public function getTemplate () { 
		// send it straight back if we have it already
		if (is_object($this->templateObject)) {
			return $this->templateObject;
			
		}
		//otherwise figure it out
		$templateName = APP_TEMPLATE_URL."_".$this->getTemplateName();
		//print "templateName".$templateName;
		$templateObject = new $templateName ( $this );
		//print_r($templateObject);
		
		$this->checkSSL($templateObject);
				
		/* 
			log in required - 
				templates can be made password protected (here)
				or records can be password protected (in website_dynamic::getTemplateName
		*/
		
		if ($templateObject->getLoginRequired()) {
			// a client is required for login
			$client = Client::getClient();
			if (!is_object($client)) //throw new Error 
				exit ("in order to have a logged in page a client is required - initiate by calling Client::setUp();");
			
			if (!$client->isLoggedIn()) {
				// redirect to the login page
				unset ($templateObject);
				$templateName = APP_TEMPLATE_URL.'_'.LOGIN_CLASS_NAME;
				$template = $templateObject = new $templateName ( $this );
			}
			
		}
			//print '--GOT TEMPLATE--2
'; $templateObject->setWebsite($this); $this->templateObject = $templateObject; return $templateObject; } /**/ //public function setContent ($content) { $this->content = $content; } protected function makeTemplate () { $this->setContent( $this->getTemplate()->makeHTML() ); $this->setWidgets( $this->getTemplate()->makeWidgets() ); } public function processWebsite ( $formData = array() ) { parent::processWebsite(); $template = $this->getTemplate(); $template->processTemplate ( array(), $formData ); } public function makeHTML () { $this->makeTemplate(); // add the template body class onto the templates $bodyClass = str_replace(APP_TEMPLATE_URL."_","",get_class($this->getTemplate())); //$this->getBody()->addClass( $bodyClass ); $this->getOuterContainer()->addClass( $bodyClass ); return parent::makeHTML(); } public function makeForAjax () { $this->makeTemplate(); return parent::makeForAjax(); } }

Error:

/home/easyCMSReleases/releases/easyCMS-2.4.2/classes/website/static.inc.php

/**
 * generic website
 *
 * @author Ian
 * @package website
 * @subpackage core
 *
 */
/**
 * @version 2.0 2009-10-29 
 * @package website
 * @subpackage core
 *
 */
class Website {

	private $styleSheets = array();
	private $styles = array();
	private $javascript = array();
	private $deferredJavascript = array();
	private $title = array();
	private $titleSeparator = "|";
	protected $metaDescription = '';
	private $metaKeywords = '';
	private $navigationClass;
	private $logo = array();
	private $logoUrl = "";
	private $footer = "";
	private $head = "";
	private $content = "";
	private $widgets = "";
	private $navigationObject;
	private $textHandler = 'codeBase_transform_text';
	private $googleCode = "";
	private $widgetsInContent = false;
	private $footerFree = false;
	private $className;
	
	private $_thumbnail = '';
	private $_pagetype = 'website';
	private $_locale = 'en_GB';

	private $htmlPage;
	
	/**
	 * @var string the URL for the current page
	 */
	protected $_canonicalLink = null;

	/*dataModel*/
	public function __construct () {
		
		$this->setUpHtmlPageObject();
		$this->getHtmlPageObject()->setContainer('container');
		
		$this->setNav ( $this->createNav() );
		$this->setClassName(get_class($this));
		$this->setCanonicalLink( PageRequest::getPageRequest()->getLink()->makeLink() );
	}


	protected function setClassName( $input ) { $this->className = $input;	}
	public function getClassName () { return $this->className; }

	protected function setHtmlPage( $htmlPage ) { $this->htmlPage = $htmlPage;	}
	protected function getHtmlPage() { return $this->htmlPage; }
	
	protected function setUpHtmlPageObject () {
		
		$languageSingleton = Language::singleton();
		$languageCode = $languageSingleton->getLanguageCode();
		$textDirection = $languageSingleton->getTextDirection();
		
		$htmlPage = new page_htmlPage();
		$htmlPage->setLang($languageCode);
		$htmlPage->setTextDirection($textDirection);
		$this->htmlPage = $htmlPage;
	}
	public function getHtmlPageObject () {
		return $this->htmlPage;
	}
	
	public function getBody () {
		return $this->getHtmlPageObject()->getBody();
	}
	
	public function getHead () {
		return $this->getHtmlPageObject()->getHead();
	}
	public function getContainer () {
		return $this->getHtmlPageObject()->getContainer();
	}
	public function getOuterContainer () {
		return $this->getHtmlPageObject()->getOuterContainer();
	}
	
	public function getWebsiteUrl( $subdomain='' ) {
		
		// if the environment is not local or live, ie an uncertain environment - we do not switch across sub-domains
		// also true for SSL - as only one sub-domain will be SSL
		if($_SERVER['HTTPS'] || (ENVIRONMENT != 'LOCAL' && ENVIRONMENT != 'LIVE')) {
			return '';
			// no subdomain for https paths
			//$input = 'https://'.$url;
		} else {
			
			$url = str_replace('www.','',Config::getConfig()->getPreference('websiteURL'));
			$input = 'http://'.($subdomain?$subdomain.'.':'').$url;
			return $input;
			
		}
	}
	
	// stylesheets
	public function addStyleSheet ( $inputURL, $media = '' ) {
		if ($inputURL) $this->getHtmlPageObject()->addStyleSheet( $this->getWebsiteUrl('css').$inputURL, $media );
	}
	public function addIEStyleSheet ( $inputURL, $version = 6, $op = '' ) {
		if ($inputURL)	$this->getHtmlPageObject()->addIEStyleSheet( $this->getWebsiteUrl('css').$inputURL, $version, $op );
	}
	
//	private function getStyleSheets () { return $this->getHtmlPageObject()->getStyleSheets(); }
	
	public function addStyle ( $input ) {
		if ($input)	$this->getHtmlPageObject()->addStyle( $input );
	}
	
	// javascript
	public function addJavascript ( $inputURL ) {
		if ($inputURL) $this->getHtmlPageObject()->addJavascript( $this->getWebsiteUrl('js').$inputURL );
	}
	public function addDeferredJavascript ( $inputURL ) {
		if ($inputURL) $this->deferredJavascript[] = $this->getWebsiteUrl('js').$inputURL;
		//if ($input) $this->getHtmlPageObject()->addJavascript( $input );
	}
	public function getDeferredJavascript () {
		//$input = 'http://js.'.str_replace('www.','',Config::getConfig()->getPreference('websiteURL')).$input;
		return $this->deferredJavascript;
		//if ($input) $this->getHtmlPageObject()->addJavascript( $input );
	}
	
	protected function makeDeferredJavascript () {
		//return '';
		$output = '";	
			$i+=10;
		}

		return $output;
	}

	public function addInlineJavascript ( $input ) {
		if ($input) $this->getHtmlPageObject()->addInlineJavascript( $input );
	}
	
	public function addIEJavascript ( $inputURL, $version = 6, $op = 'lte') {
		if ($inputURL)	$this->getHtmlPageObject()->addIEJavascript( $this->getWebsiteUrl('js').$inputURL, $version, $op );
	}
	
	public function setEmulateIE7 ( $input ) {
		if ($input)	$this->getHtmlPageObject()->setEmulateIE7( $input );
	}
	
	public function setContentType ($input) {
		if ($input) $this->getHtmlPageObject()->setContentType( $input );
	}
	
	public function setFavicon ($input) {
		if ($input) $this->getHtmlPageObject()->setFavicon( $this->getWebsiteUrl('assets1').$input, $version );
	}
	
	public function setRssLink ( $title, $path ) {
		if ($title && $path) $this->getHtmlPageObject()->setRssLink( $title, $path );
	}	


	public function setTitle ( $data ) { $this->title = array( $data ); }
	public function addToTitle ( $data ) { array_unshift($this->title, $data); }
	public function getTitle () { return $this->title; }
	protected function makeTitle () {
		if (count($this->getTitle()))
			return ''.implode(" ".$this->getTitleSeparator()." ",$this->getTitle()).''."\r";
		else 
			return "";
	}
	public function setTitleSeparator ( $data ) { $this->titleSeparator = $data; }
	protected function getTitleSeparator () { return $this->titleSeparator; }
	
	public function setMetaDescription ( $data ) { $this->metaDescription = $data; }
	public function getMetaDescription () {
		 return htmlspecialchars ( $this->metaDescription, ENT_COMPAT, 'UTF-8' ) ;
	}
	protected function makeMetaDescription () {
		if ( count($this->getTitle()) ) $title = implode(" - ",$this->getTitle());
		strlen($this->getMetaDescription())?$content=$this->getMetaDescription():$content=$title;
		return ''."\r";
	}
	
	public function setMetaKeywords ( $data ) { $this->metaKeywords = $data; }
	public function getMetaKeywords () { return $this->metaKeywords; }
	protected function makeMetaKeywords () {
		if ( count($this->getTitle()) ) $title = implode(", ",$this->getTitle());
		strlen($this->getMetaKeywords())?$content=$this->getMetaKeywords():$content=$title;
		return ''."\r";
	}
	
	protected function makeJquery () {
		return '';
	}
	
	protected function makeCufonIEFix () {
		return '';
	}
	
/**
 * forces widgets inside content... sets true only.
 */
	protected function setWidgetsInContent () { $this->widgetsInContent = true; }
	public function getWidgetsInContent () { return $this->widgetsInContent; }
	
/**
 * forces footer outsite containerInner... sets true only.
 */
	protected function setFooterFree () { $this->footerFree = true; }
	public function getFooterFree () { return $this->footerFree; }

	
	public function setLogo ($logoURL,$width=0,$height=0,$alt="*") { 
		if ($logoURL) $logoURL = $this->getWebsiteUrl('assets1').$logoURL;
		$this->logo = array(
				"url"=>$logoURL,
				"width"=>$width,
				"height"=>$height,
				"alt"=>$alt);
	}
	
	public function setLogoLink ($url) { $this->logoUrl = $url; }
	private function getLogoLink () {
		if (!$this->logoUrl) return "/";
		return $this->logoUrl;
	}
																	
	protected function getLogo () { return $this->logo; }
	protected function hasLogo () { 
			$logo = $this->getLogo();
			if (isset($logo['url'])) return true;
			return false;
	}
	
	/**
	 * Make the logo for the site.
	 * 
	 * @return string
	 */
	protected function makeLogo ()
	{ 
		if (!$this->hasLogo())
			return "";
		
		$logo = $this->getLogo();
		return '';
	}
	
	
	public function setFooter ($footer) { $this->footer = $footer; }
	protected function getFooter () { return $this->footer; }
	protected function makeFooter () {
			if (strlen($this->getFooter())) {
					// tbc: new div "last" added (useful to stick the footer at the bottom)
					return '
 
'; } else { return ""; } } public function setHeader ($header) { $this->head = $header; } public function getHeader () { return $this->head; } protected function makeHeader () { if (strlen($this->getHeader()) || $this->hasLogo()) { return ''; } else { return ""; } } public function setContent ($content) { $this->content = $content; } protected function hasContent () { if (strlen($this->getContent())) return true; return false; } protected function getContent () { return $this->content; } protected function makeContent () { //print 'website->makeContent'; $content = $this->getContent(); if ($this->getWidgetsInContent()) $content .= $this->makeWidgets().'
'; if (strlen($content)) { return '
'.$content.'
'; } else { return ""; } } public function setWidgets ($widg) { $this->widgets = $widg; } protected function getWidgets () { return $this->widgets; } protected function makeWidgets () { $content = $this->getWidgets(); return '
'.$content.'
'; } /* NAVIGATION OBJECT */ protected function createNav () { return new website_Navigation (); } protected function setNav ( $navObject ) { if (is_object($navObject)) { $this->navigationObject = $navObject; $navObject->setWebsite($this); } } public function getNav () { return $this->navigationObject; } protected function makeNav () { if (!is_object($this->getNav())) return ""; return ''; } protected function setTextHandler ( $txtProcessor) { // called by the templates to process their text $this->textHandler = $txtProcessor; } public function getTextHandler () { // called by the templates to process their text return $this->textHandler; } /*businessLogic*/ public function processWebsite () { } //gc protected function setGoogleAnalytics ($googleCode) { $this->googleCode = $googleCode; } private function getGoogleAnalytics () { return $this->googleCode; } protected function addGoogleAnalytics () { if (strlen($this->getGoogleAnalytics())) { $this->getHtmlPageObject()->getBody()->addContent( helper_html::googleAnalytics($this->getGoogleAnalytics())); } } //made by mind unit added by Abdul Latif - nice work Abdul. protected function addMadeByMindUnit($pos = 'r',$removeIe6='') { $this->getHtmlPageObject()->getBody()->addContent( helper_html::madeByMindUnit($pos,$removeIe6) ); } /** * make container's html content */ protected function makeContainer () { $output = ''; $output .= $this->makeHeader(); $output .= $this->makeContent(); if (!$this->getWidgetsInContent()) { $output .= $this->makeWidgets(); $output .= '
'; } $output .= $this->makeNav(); if (!$this->getFooterFree()) $output .= $this->makeFooter(); return $output; } /*view/interface*/ public function makeHTML () { //gc $output .= ''; //print 1; $htmlPage = $this->getHtmlPageObject(); //print 2; if ($this->getTitle()) { $htmlPage->getHead()->addContent( $this->makeTitle() ); $htmlPage->getHead()->addContent( $this->makeMetaDescription() ); $htmlPage->getHead()->addContent( $this->makeMetaKeywords() ); } $htmlPage->getHead()->addContent( $this->makeSocialLinksAndImages () ) ; if (strlen($jquery = $this->makeJquery())) $htmlPage->getHead()->addContent( $jquery ); $output .= $this->makeContainer(); if ($this->getFooterFree()) $htmlPage->getOuterContainer()->addContent( $this->makeFooter() ); //print 7; $htmlPage->getContainer()->addContent( $output ); if (strlen($cufon = $this->makeCufonIEFix())) $this->getBody()->addContent( $cufon ); // default state, assume no js. (allows for noJS styling) $this->getBody()->addClass('noJavascript'); //exit($cufon); if (count($this->getDeferredJavascript())) $this->getHead()->addContent( $this->makeDeferredJavascript() ); //$this->addDeferredJavascript(); $this->addMadeByMindUnit(); //print 8; $this->addGoogleAnalytics(); if( $this->getFooterFree() ) { // If the footer is free, we also add a "push" element - this will make sure (with the proper CSS applied) // the footer sticks to the bottom of the page $this->getContainer()->addContent( '
 
' ); } $thePage = $htmlPage->makePage(); return $thePage; } /** * Collects all of the elements for the social aspects, links and thumbnails for the site * * @param object $head * @return null */ public function makeSocialLinksAndImages () { $html = $this->getHtmlPageObject()->getRoot(); // facebook $html->setAttribute('xmlns:og','http://ogp.me/ns#'); $html->setAttribute('xmlns:fb','http://www.facebook.com/2008/fbml'); // google /* ideal but causes validation error AND fails emails */ //$html->setAttribute('itemscope'); //$html->setAttribute('itemtype', 'http://schema.org/Organization'); $url = str_replace('www.','',Config::getConfig()->getPreference('websiteURL')); $url = 'http'.($_SERVER['HTTPS']?'s':'').'://'.$url; ob_start(); ?> getMetaDescription()) { ?> getThumbnail()) { ?> getCanonicalLink()) { ?> getPreference('websiteFacebookAppId')) { ?> getPreference('websiteFacebookAdminId')) { ?> _locale = $locale; } public function getLocale () { return $this->_locale; } public function setPageType ( $pagetype ) { $this->_pagetype = $pagetype; } public function getPageType () { return $this->_pagetype; } public function getThumbnail ( $variant='default' ) { if ($this->_thumbnail[$variant]) return $this->_thumbnail[$variant]; return $this->_thumbnail['default']; } /** * Stores the URL of the thumbnail * Takes either an array OR a value * array should have '114x114' => 'image1.png' * array should have '57x57' => 'image2.png' * array should have 'default' => 'image3.png' (50x50 ish) * * @param string $url * @param bool $bool flag for a full url * @return null */ public function setThumbnail ( $path, $thumb ) { if (!is_array($thumb)) $thumb = array('default' => $thumb); /* else go through each entry and make sure that it is set */ $this->_thumbnail = array(); foreach ($thumb as $key => $val) { $this->_thumbnail[$key] = $path.$val; } //var_dump($this->_thumbnail); //exit; } /** * Stores the canonical URL. * If we pass a true value, $this->_canonicalLink will take the url contained in $url literally, * otherwise we append the website URL from the preferences to the given page URL, this uses a * preference that determines * * @param string $url * @param bool $bool flag for a full url * @return null */ public function setCanonicalLink ( $url, $bool = false ) { /* if( $bool === false ) { // strip wwww if it's in there $mainUrl = str_replace('www.','',Config::getConfig()->getPreference('websiteURL')); // Find out from the preferences if the end user wants a www prefix $this->_canonicalLink = Config::getConfig()->getPreference('websitePrefixWWW') ? 'www.'.$mainUrl : $mainUrl; // Use HTTPS if we are operating on https $this->_canonicalLink = $_SERVER['HTTPS'] ? 'https://'.$this->_canonicalLink : 'http://'.$this->_canonicalLink; } */ $this->_canonicalLink = $url; } /** * Returns the canonical URL * * @return string */ public function getCanonicalLink () { return $this->_canonicalLink; } public function makeForAjax () { $content = '
'.$this->getContent( ); if ($this->getWidgetsInContent()) { $content .= $this->makeWidgets(); } $content .= '
'; return $content; } }
(19887)