* @package core */ abstract class ccPage { /** page variables **/ protected $page_info; //ccVFS_PageInfo object protected $vfs; //ccVFS object -- basically used for calling functions of the class protected $authMan; //ccAuthManager object for validating users protected $userObj; //ccUser object holding user information protected $feedback; //ccUserMessage object for passing messages to user /** * ccPage constructor */ public function __construct() { set_error_handler(array($this, 'errorHandler'), E_WARNING | E_STRICT | E_USER_WARNING | E_USER_NOTICE | E_USER_ERROR); } /** * Runs a Page * @return void */ public function Run() { try { /** if set to validate xhtml -- then start doing so **/ if(ccConfig::$show_validate_xhtml == true) ob_start(); /** get template instance **/ $tpl = ccTPL::instance(); /** instantiate data members **/ $this->vfs = new ccVFS(); $this->page_info = new ccVFS_PageInfo($this->vfs->findPageInfo($_SERVER['REQUEST_URI'])); if ( strrpos($_SERVER['REQUEST_URI'], ".cc") !== false && $this->page_info->isDirectory() ) $this->redirect404(); $this->feedback = new ccUserMessage(); //messages for user $this->authMan = new ccAuthManager(); /** check for a valid user. **/ $this->authMan->validateUser(); if(true == $this->authMan->getSession()->isValid()) { //if valid user then set user object $this->userObj = $this->authMan->getUserObj(); } else { //otherwise set user object to false $this->userObj = false; } //get template object for requested page $template_info = new ccTemplate($this->page_info->getTemplateId(), $this->page_info->getPageId()); if ( $_SERVER['QUERY_STRING'] != "" ) $t_extras = "/?".$_SERVER['QUERY_STRING']; else $t_extras = ""; $t_cache = str_replace("/","|", $template_info->getFileName().$this->page_info->getFullPath().$t_extras); $tpl->setCacheId($t_cache); if ( $this->page_info->isVirtual() ) { $tpl->setCacheEnabled(true); } else $tpl->setCacheEnabled(false); /********** Check for draft mode *******/ if ( $this->page_info->isShow() == false ) { //page is not viewable by default $t_allowed = $this->page_info->isWriteAllowed($this->userObj); if ( ! $t_allowed ) $this->redirect404(); $this->feedback->addWarningMessage("This page '{$this->page_info->getName()}' is currently in draft mode."); //echo "I'm here. yes i am"; } /*********** Security for private pages **********/ if ( $this->page_info->isPrivate() ) { $t_uri = $this->page_info->getFullPath(); if ( $_SERVER['QUERY_STRING'] != "" ) $t_uri .= "?".$_SERVER['QUERY_STRING']; $this->requireSecureUser($t_uri); $t_allowed = $this->page_info->isReadAllowed($this->userObj); //echo "allowed: $t_allowed"; //if not allowed, redirect to 403 Forbidden error if ( ! $t_allowed ) $this->redirect403(); } /**************** Page Editing stuff *************/ if ( $this->isEditMode() ) { //user has requested page in edit mode //first check to make sure they're logged in securely $this->requireSecureUser($this->page_info->getFullPath()."?".$_SERVER['QUERY_STRING']); $tpl->setCacheEnabled(false); $tpl->clearSpecificCache(substr($t_cache, 0, strrpos($t_cache, "|"))); //make sure valid user has access to page $t_acls = $this->page_info->getAllowed($this->userObj, ccACL::getWritePermission()); //if authorized, then set appropriate stuff if ($t_acls !== false) { $tpl->assign('acl', $t_acls[0]); //this should always be the ACL granting highest level of access (priority) $tpl->assign('mode', "edit"); } //otherwise give some negative feedback else $this->feedback->addNegativeMessage("Sorry, you do not have access to edit this page."); } if ( $this->isEditPosted() ) { //user has posted page changes from edit mode //$tpl->clearCache(); //still need to make sure user can -- i.e. secure session hasn't timed out $this->requireSecureUser($this->page_info->getFullPath()."?".$_SERVER['QUERY_STRING']); //make sure user has access to page $t_acls = $this->page_info->getAllowed($this->userObj, ccACL::getWritePermission()); //if authorized, submit content changes if ( $t_acls !== false ) { $t_sanitize = true; foreach( $t_acls as $t_num => $t_acl ) { if ($t_acl->hasWritePermission(ccACL::getHTMLPermission()) ) { $t_sanitize = false; break; } else continue; } $t_is_success = $this->makeContentChanges($t_sanitize); if ( $t_is_success ) { $this->feedback->addPositiveMessage("Your changes have been submitted successfully!"); $tpl->clearSpecificCache(substr($t_cache, 0, strrpos($t_cache, "|"))); } else $this->feedback->addNegativeMessage($t_is_success); } //otherwise give some negative feedback else $this->feedback->addNegativeMessage("Sorry, you do not have sufficient permissions to edit this page"); } /********* END page editing stuff **************/ // test for cached $this->PreAssign(); //function overridden in child pages (classes) if($tpl->isCached()) { // no assignment -- using cached values. } else { // Run assign since there is not a cached version $this->AssignPageInfo($template_info); //assign page info -- theme, content, etc $this->Assign(); //function overridden by child pages (classes) $tpl->assign('msg', $this->feedback); //assign messages to user } } //now catch any exceptions thrown catch(ccException $e) { if(ccConfig::$show_error_detailed != false) $this->getDevError($e); else $this->getPublicError($e); } catch(Exception $e) { if(ccConfig::$show_error_detailed != false) $this->getDevError($e); else $this->getPublicError($e); } // render -- show me some XHTML $this->Render(); if(ccConfig::$show_validate_xhtml == true) { $t_content = ob_get_contents(); $tidy = $this->check_xhtml($t_content); if(tidy_warning_count($tidy) || tidy_error_count($tidy)) { $tid = $this->save_page_info($tidy, $t_content); $t_content = $this->add_tidy_link($tid, $t_content); ob_clean(); echo $t_content; } ob_end_flush(); } } /** * Redirect page to given uri * @param string $p_url String representing url to redirect to * @return void */ public function redirect($p_url) { if(!headers_sent($t_file, $t_line)) { // Headers aren't sent yet, we can do a cool redirect. // TODO: Add for WHY we are redirecting to /login.php AND have // login.php redirect to out sending page header("Location: ". $p_url); } else { throw new ccException("Unable to redirect. Headers Sent. TODO: Someone write a /redirect.php!","Headers sent from file '$t_file', line '$t_line'"); } exit(); } public function redirect404() { if(!headers_sent($t_file, $t_line)) { // Headers aren't sent yet, we can do a cool redirect. // TODO: Add for WHY we are redirecting to /login.php AND have // login.php redirect to out sending page header("HTTP/1.0 404 Not Found"); header("Location: ".ccConfig::$http_base."/404.php"); exit(); } else { throw new ccException("Unable to redirect. Headers Sent. TODO: Someone write a /redirect.php!","Headers sent from file '$t_file', line '$t_line'"); } exit(); } public function redirect403() { if(!headers_sent($t_file, $t_line)) { // Headers aren't sent yet, we can do a cool redirect. // TODO: Add for WHY we are redirecting to /login.php AND have // login.php redirect to out sending page header("HTTP/1.0 403 Forbidden"); header("Location: ".ccConfig::$http_base."/403.cc"); exit(); } else { throw new ccException("Unable to redirect. Headers Sent. TODO: Someone write a /redirect.php!","Headers sent from file '$t_file', line '$t_line'"); } exit(); } /** * Check for secure user. If not a secure user, user is redirected to login page * @param string $p_uri Optional string parameter representing page to be redirected back to after log in * @return bool Returns true if secure user, otherwise false and redirected to login page */ public function requireSecureUser($p_uri=NULL) { if( $this->authMan->getSession()->isValid() && $this->authMan->getSession()->isSecure() && $this->requireUser()) { return true; } if ( $p_uri !== NULL ) $var_string = "?uri=$p_uri"; else $var_string = ""; $this->redirect('/login.php'.$var_string); return false; } /** * Checks for valid user. Does not have to be secure user. * @param string $p_uri Optional string parameter representing page to be redirected back after log in * @param bool Returns true if valid user, otherwise false and redirected to login page */ public function requireUser($p_uri=NULL) { if(false === is_object($this->userObj)) { // This page requires a valid user. Send the User to a login Page. if ( $p_uri !== NULL ) $var_string = "?uri=$p_uri"; else $var_string = ""; $this->redirect('/login.php'.$var_string); return false; } return true; } /** * Checks if page is in edit mode * @return bool Returns true if page is in edit mode, otherwise false */ public function isEditMode() { if ( (isset($_GET["mode"] ) && $_GET["mode"] == "edit") || (isset($_COOKIE["mode"]) && $_COOKIE["mode"] == "edit") ) { return true; } else return false; } /** * Checks if page changes have been posted * @return bool Returns true if changes have been submitted, otherwise false */ public function isEditPosted() { if ( isset($_POST["submitContent"]) && $_POST["submitContent"] == "save changes" ) return true; else return false; } /** * Submits content changes to database * @return true|string Returns true if successful, otherwise returns an error message */ public function makeContentChanges( $p_sanitize = true ) { //array of content ids $t_id_array = $_POST["content_id"]; $t_warned = false; //loop through content ids and make changes $t_success = true; if ( !empty($t_id_array) ) { foreach ( $t_id_array as $t_num => $t_id ) { $t_content_title = $_POST["content_title".$t_id]; $t_content = $_POST["content".$t_id]; $t_contentmap_id = $_POST["contentmap_id".$t_id]; $t_templatearea_id = $_POST["templatearea_id".$t_id]; $t_order = $_POST["order".$t_id]; //sanitize HTML from people not authorized if ( $p_sanitize ) { $t_had_html = false; if ( strlen($t_content_title) !== strlen(strip_tags($t_content_title)) || strlen($t_content) !== strlen(strip_tags($t_content)) ) { if ( !$t_warned ) { //only add warning message if it hasn't already been added //we don't want to overwhelm user with same warning message $this->feedback->addWarningMessage("HTML was detected in your content changes. Unfortunately, at this time, you do not have access to add HTML to content. Please use the style helper provided to add special styling."); $t_warned = true; } } $t_content_title = htmlentities($t_content_title, ENT_QUOTES); $t_content = htmlentities($t_content, ENT_QUOTES); } $t_content_obj = new ccContent($t_id, $_POST["vfs_id"], $t_content_title, $t_content); try { $t_success = ccContentMapDAO::update($t_contentmap_id, $t_templatearea_id, $t_content_obj, $t_order); } catch ( ccDAO_exception $e ) { /*if we get an error updating content we're just going to quit and return first error message we encounter -- because, you know, we can */ $t_success = $e->getMessage(); return $t_success; } } } return $t_success; } /** * Function defined in child classes * @abstract */ abstract function PreAssign(); /** * Assigns template, theme, content template, content, and other page info to page before rendering * @return void * @todo add rules for dealing with types of binary content other than images */ private function AssignPageInfo($template_info) { /* Setup of: * - CSS Styles * - Blocks? * - Anything else related to 'themes' */ $tpl = ccTPL::instance(); //var_dump($this->page_info); //get content template info $content_info = new ccTemplate($this->page_info->getContentTemplateId(), $this->page_info->getPageId()); //echo $content_info->getFileName(); //echo "Template: {$template_info->getFileName()}
"; //assign base template $tpl->setTemplate($template_info->getFileName()); //XXXX: how do we want to do cache ids? //$tpl->clear_cache(null, 'root'); //assign header and footer templates $tpl->assign('header', $template_info->getHeader()); $tpl->assign('footer', $template_info->getFooter()); //set other stuff -- theme, image, page title $tpl->assign('theme', $this->page_info->getTheme()->getCSSFile()); //set stylesheet for page $tpl->assign('page_id', $this->page_info->getPageId()); //set page id $tpl->assign('page_title', stripslashes($this->page_info->getTitle())); //set page title $tpl->assign('cur_page', $this->page_info->getPageId()); //set cur page for setting active nav item $tpl->assign('page_stitle', stripslashes($this->page_info->getShortTitle())); //set page short title for cookie crumb $tpl->assign('keywords', $this->page_info->getKeywords()); //set page keywords -- metadata $tpl->assign('description', $this->page_info->getDescription()); //set page description -- metadata $tpl->assign('trail', $this->page_info->getCrumbInfo()); //set crumb trail array $tpl->assign('page_path', $this->page_info->getFullPath()); //set full path of page //don't override content_file if assigned from within child page class if ( $tpl->getTemplateVars('content_file') == NULL || $tpl->getTemplateVars('content_file') == "") { $tpl->assign('content_file', $content_info->getFileName()); //set content template file } //assign binary content to areas of template -- want to do this whether virtual or not if ( !(NULL == $this->page_info->getBinaryContent()) ) { $t_bin_content = $this->page_info->getBinaryContent(); //loop through binary content of page and assign as needed foreach ( $t_bin_content as $num => $t_map ) { //XXXX: rules for different types of binary content? $t_cont_obj = $t_map->getBinaryContent(); if ( strpos($t_cont_obj->getFileType(),"image") !== false ) { $tpl->assign($t_map->getAssignVar(), $t_cont_obj->getFilePath() ); } } } //assign content maps to areas of template -- if virtual, otherwise pages will do it themselves? //if ( $this->page_info->isVirtual() === true ) //{ //get content areas for page template $t_tempareas = $content_info->getAreas(); //only show content if there is some if ( !(NULL == $t_tempareas) ) { //cycle through template areas and assign content //content rendering will be done through smarty foreach ( $t_tempareas as $num => $t_area ) { $tpl->assign($t_area->getAssignVar(), $t_area); } } //} //get block areas for output -- could be in either the parent or content template $t_blockareas = ccBlockArea::getBlockAreas(array($this->page_info->getTemplateId(),$this->page_info->getContentTemplateId()), $this->page_info->getPageId()); //var_dump($t_blockareas); if ( !is_null($t_blockareas) ) { //cycle through and assign block areas //the block rendering will be done in smarty foreach ( $t_blockareas as $t_num => $t_area ) { $tpl->assign($t_area->getAssignVar(), $t_area); } } //set side bar navigation if page needs it if ( $this->page_info->isNav() ) { $page_side_nav = new ccNav($this->page_info->kPageId, $this->page_info->kParentId); $tpl->assign('navitems', $page_side_nav->getNavItems()); } } /** * Function defined in child classes * @abstract */ abstract function Assign(); /** * Renders a Page with a Template. * @return void */ public function Render() { try { $tpl = ccTPL::instance(); $tpl->display(); } catch(ccException $e) { if(ccConfig::$show_error_detailed != false) { $this->getDevError($e); } else { $this->getPublicError($e); } } catch(Exception $e) { if(ccConfig::$show_error_detailed != false) { $this->getDevError($e); } else { $this->getPublicError($e); } } } /** * Handles errors of many times -- mostly dev errors * @return void */ public function errorHandler($p_errno, $p_errstr, $p_errfile, $p_errline, $p_ctx) { if(ini_get('error_reporting') == 0) return; @ob_end_flush(); $errortype = array ( E_ERROR => "Error", E_WARNING => "Warning", E_PARSE => "Parsing Error", E_NOTICE => "Notice", E_CORE_ERROR => "Core Error", E_CORE_WARNING => "Core Warning", E_COMPILE_ERROR => "Compile Error", E_COMPILE_WARNING => "Compile Warning", E_USER_ERROR => "User Error", E_USER_WARNING => "User Warning", E_USER_NOTICE => "User Notice", E_STRICT => "Runtime Notice" ); echo '

'; echo 'Fatal Error:'; echo 'Error message: '.$p_errstr.'
'. "\n"; echo 'Error Number: '.$p_errno.'
'. "\n"; echo 'Error code: '.$errortype[$p_errno].'
'. "\n"; echo 'Script Name: '.$p_errfile.'
'. "\n"; echo 'Line Number: '.$p_errline.'
'. "\n"; echo 'Backtrace:
'. DBG_GetBacktrace() .'
'. "\n"; echo '

';
        	print_r($p_ctx); 
        	echo '

'; die(); } /** * Validates a Page for XHTML * @param string $p_content Content to validate * @return object Tidy Object */ function check_xhtml($p_content) { $tidy = tidy_parse_string($p_content); return $tidy; } /** * Saves a Pages Info from to the Tidy Database Table * * @param object $p_tidy Tidy Object for this page * @param string $p_content Page Content Before Tidy * @return void */ public function save_page_info($p_tidy, $p_content) { $t_db = ccDB::instance(); $t_sql = ccDB::queryf(" INSERT INTO ccSite_validate SET event_time = NOW(), globals = %s, tidy_error = %s, tidy_error_count = %d, tidy_warning_count = %d, page_content = %s ", serialize(array($_SERVER,$_POST,$_GET,$_ENV)), tidy_get_error_buffer($p_tidy), tidy_error_count($p_tidy), tidy_warning_count($p_tidy), $p_content ); $t_res = $t_db->write($t_sql); return $t_res->insertId(); } /** * Outputs a Link to the Tidy Debuger * * @param int $p_idx Tidy Debuger Event ID Number * @param string $p_content Page Content to edit. * @return void */ public function add_tidy_link($p_idx, $p_content) { $t_content = ""; // This is a Special String that Should be in All Templates. // If this string does not exist, you will not get a Tidy link. $t_special_string = ''; $t_tidy_link = '
This Page is not Valid XHTML
'; $t_content = str_replace ( $t_special_string, $t_tidy_link, $p_content); return $t_content; } /** * Get exception error for developer * @param object $e Exception to retrieve developer error from * @param bool $use_templates Optional parameter * return void */ private function getDevError($e, $use_templates = true) { if($use_templates == false || 1) { // swap once pretty errors are ready // Hard Errors. Templates cannot be used. echo 'Error message: '.$e->getMessage().'
'. "\n"; echo 'Error code: '.$e->getCode().'
'. "\n"; echo 'Script Name: '.$e->getFile().'
'. "\n"; echo 'Line Number: '.$e->getLine().'
'. "\n"; if( is_subclass_of($e, 'ccException') || ($e instanceof ccException)) { echo 'Dev Error message: '.$e->getDebugMsg().'
'. "\n"; } echo 'Backtrace:
'. DBG_GetBacktrace() .'
'. "\n"; echo 'Backtrace:
'. $e->getTraceAsString() .'

'. "\n"; } else { // Pretty Errors. Template Based. } exit(); } /** * Get exception error for public user * @param object $e Exception to retrieve public user error from * @param bool $use_templates Optional parameter */ private function getPublicError($e, $use_templates = true) { // TODO: Implement This Function return $e->getMessage(); } } /** * Generates a Backtrace * * @return string HTML Formatted Backtrace */ function DBG_GetBacktrace() { // TODO: Clean this function up. Make Pretty Output too! $s = ''; $MAXSTRLEN = 1024; $s = '
';
   	$traceArr = debug_backtrace();
   	array_shift($traceArr);
   	$tabs = sizeof($traceArr)-1;
   	
   	foreach($traceArr as $arr)
   	{
       		for ($i=0; $i < $tabs; $i++) $s .= '   ';
       		$tabs -= 1;
       		$s .= '';
       		
       		if (isset($arr['class'])) $s .= $arr['class'].'.';
       		$args = array();
       
       		if(!empty($arr['args'])) foreach($arr['args'] as $v)
       		{
           		if (is_null($v)) $args[] = 'null';
           		else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
           		else if (is_object($v)) $args[] = 'Object:'.get_class($v);
           		else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
           		else
           		{
               			$v = (string) @$v;
               			$str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
               			if (strlen($v) > $MAXSTRLEN) $str .= '...';
               			$args[] = "\"".$str."\"";
           		}
       		}
       		
       		$s .= $arr['function'].'('.implode(', ',$args).')';
       		$line = (isset($arr['line'])? $arr['line'] : "unknown");
       		$file = (isset($arr['file'])? $arr['file'] : "unknown");
       		$s .= sprintf(" # line %4d, file: %s",
           		$line, $file, $file);
       		$s .= "\n";
   	}   
   	
   	$s .= '
'; return $s; } ?>