Example #1
0
function write_debug($message, $level = DEBUG_LEVEL_FULL){
	// Only allow full debug messages to continue through if FULL DEBUG is enabled.
	if($level >= DEBUG_LEVEL_FULL && !FULL_DEBUG) return;

	$profiler = Profiler::GetDefaultProfiler();
	// Grab how many ms have passed since the application started.
	$time = $profiler->getTime();

	// Format this into a human readable format.
	$time = \Core\time_duration_format($time, 2);

	$time = str_pad($time, 10, '0', STR_PAD_LEFT);
	
	if (EXEC_MODE == 'CLI'){
		// CLI gets no formatting and is just written to the screen.
		echo '[ DEBUG ' . $time . ' ] - ' . $message . "\n";
	}
	elseif($level == DEBUG_LEVEL_LOG){
		// LOG level messages just get error logged.
		error_log('[ DEBUG ' . $time . ' ] - ' . $message);
	}
	else{
		echo '<pre class="xdebug-var-dump screen">[' . $time . '] ' . $message . '</pre>';
	}
}
Example #2
0
	/**
	 * Function to record activity, ie: a page view.
	 *
	 * @static
	 *
	 */
	public static function RecordActivity(){

		$request = \PageRequest::GetSystemRequest();
		$view = $request->getView();

		if(!$view->record) return true;

		try{

			$processingtime = (round(Profiler::GetDefaultProfiler()->getTime(), 3) * 1000);

			$log = new \UserActivityModel();
			$log->setFromArray(
				[
					'datetime' => microtime(true),
					'session_id' => session_id(),
					'user_id' => \Core\user()->get('id'),
					'ip_addr' => REMOTE_IP,
					'useragent' => $request->useragent,
					'referrer' => $request->referrer,
					'type' => $_SERVER['REQUEST_METHOD'],
					'request' => $_SERVER['REQUEST_URI'],
					'baseurl' => $request->getBaseURL(),
					'status' => $view->error,
					'db_reads' => DatamodelProfiler::GetDefaultProfiler()->readCount(),
					'db_writes' => (DatamodelProfiler::GetDefaultProfiler()->writeCount() + 1),
					'processing_time' => $processingtime,
				]
			);

			if(defined('XHPROF_RUN') && defined('XHPROF_SOURCE')){
				$log->set('xhprof_run', XHPROF_RUN);
				$log->set('xhprof_source', XHPROF_SOURCE);
			}

			$log->save();
		}
		catch(\Exception $e){
			// I don't actually care if it couldn't save.
			// This could happen if the user refreshes the page twice with in a second.
			// (and with a system that responds in about 100ms, it's very possible).
			\Core\ErrorManagement\exception_handler($e);
		}
	}
Example #3
0
	/**
	 * Save this Model into the datastore.
	 *
	 * Return true if saved successfully, false if no change required,
	 * and will throw a DMI_Exception if there was an error.
	 * 
	 * As of 5.0.0, bulk inserts can be performed by passing TRUE as the one argument.
	 * If this is done, you MUST call CommitSaves() after all data has been stored!
	 * 
	 * @param bool $defer Set to true to batch-save this data as a BULK INSERT.
	 *
	 * @return boolean
	 * @throws DMI_Exception
	 */
	public function save($defer = false) {

		\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record(
			'Issuing save() on ' . $this->get('__CLASS__') . ' ' . $this->getLabel()
		);

		// Only do the same operation if it's been changed.
		// This is actually a little more in depth than simply seeing if it's been modified, as I also
		// have to look into the linked classes and see if it exists
		$save = false;
		// new models always get saved.
		if(!$this->_exists){
			$save = true;
		}
		// Models that have changed content always get saved.
		elseif($this->changed()){
			$save = true;
		}
		else{
			foreach($this->_linked as $l){
				if(isset($l['records'])){
					// If there are any linked models in the records array, trigger the save.
					$save = true;
					break;
				}
				if(isset($l['purged'])){
					// If there are any linked models in the purged array, trigger the save, (to delete them).
					$save = true;
					break;
				}
			}
		}

		if(!$save){
			\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record(
				'No column detected as changed, skipping save.'
			);
			return false;
		}

		// Dispatch the pre-save hook for models.
		// This allows utilities to hook in and modify the model or perform some other action.
		$classname = get_called_class();
		// Allow all supplemental models to tap into this too!
		if(isset(self::$_ModelSupplementals[$classname])){
			foreach(self::$_ModelSupplementals[$classname] as $supplemental){
				if(class_exists($supplemental)){
					$ref = new ReflectionClass($supplemental);
					if($ref->hasMethod('PreSaveHook')){
						$ref->getMethod('PreSaveHook')->invoke(null, $this);
					}
				}
			}
		}
		HookHandler::DispatchHook('/core/model/presave', $this);

		// NEW in 2.8, I need to run through the linked models and see if any local key is a foreign key of a linked model.
		// If it is, then I need to save that foreign model so I can get its updated primary key, (if it changed).
		foreach($this->_linked as $l){
			// If this link has a 1-sized relationship and the local node is set as a FK, then read it as such.

			if(!is_array($l['on'])){
				// make sure it's an array.
				$l['on'] = [$l['on'] => $l['on'] ];
			}

			if($l['link'] == Model::LINK_HASONE && sizeof($l['on']) == 1){
				reset($l['on']);
				$remotek = key($l['on']);
				$localk  = $l['on'][$remotek];
				$locals = $this->getKeySchema($localk);

				// No schema?  Ok, nothing to save to!
				if(!$locals) continue;

				// If this is not a FK, then I don't care!
				if($locals['type'] != Model::ATT_TYPE_UUID_FK) continue;

				// OTHERWISE..... ;)
				if(isset($l['records'])){
					/** @var Model $model */
					$model = $l['records'];
				}
				elseif(isset($this->_columns[$localk]) && $this->_columns[$localk]->value instanceof Model){
					// The alternative location for this linked model to be.
					// This can happen when the link is established in the Schema data and the parent record doesn't exist yet.
					/** @var Model $model */
					$model = $this->_columns[$localk];
				}
				else{
					// No valid model found... :/
					continue;
				}

				$model->save();
				$this->set($localk, $model->get($remotek));
			}
		}


		if ($this->_exists){
			$changed = $this->_saveExisting();
			\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record(
				'Saved existing record to database'
			);
		}
		else{
			// Inserts can be deferred!
			$this->_saveNew($defer);
			$changed = true;
			\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record(
				'Saved new record to database'
			);
		}


		// Go through any linked tables and ensure that they're saved as well.
		foreach($this->_linked as $k => $l){
			// No need to save if it was never loaded.
			//if(!(isset($l['records']))) continue;

			// No need to save if it was never loaded.
			//if(!(isset($l['records']) || $this->changed())) continue;

			switch($l['link']){
				case Model::LINK_HASONE:
					$models = isset($l['records']) ? [$l['records']] : null;
					$deletes = isset($l['purged']) ? $l['purged'] : null;
					break;
				case Model::LINK_HASMANY:
					$models = isset($l['records']) ? $l['records'] : null;
					$deletes = isset($l['purged']) ? $l['purged'] : null;
					break;
				default:
					// There is no default behaviour... other than to ignore it.
					$models = null;
					$deletes = null;
					break;
			}

			// Are there deletes requested?
			// Deletes MUST happen before creates because if there is a record that overrides an existing record,
			// but that existing record is set to be deleted, the delete operation must be before the create operation.
			//
			// This happens on the page updates with meta fields.
			// The meta fields are completely re-created, and saved at one time only.
			// Since the incoming data has the same PK as the existing data, (that's already marked as deteled),
			// the operation fails if these orders are reversed.
			if($deletes){
				foreach($deletes as $model){
					$model->delete();
					$changed = true;
				}

				unset($l['purged']);
			}

			// Are there saves requested?
			if($models){
				foreach($models as $model){
					/** @var $model Model */
					// Ensure all linked fields still match up.  Something may have been changed in the parent.
					$model->setFromArray($this->_getLinkWhereArray($k));
					if($model->save()){
						$changed = true;
					}
				}
			}
		}

		// Commit all the columns
		$this->_exists   = true;
		foreach($this->_columns as $c){
			/** @var \Core\Datamodel\Columns\SchemaColumn $c */
			$c->commit();
		}

		// Check and see if this model extends another model.
		// If it does, then create/update that parent object to keep it in sync!
		if(($class = get_parent_class($this)) != 'Model'){
			$idx = self::GetIndexes();
			if(isset($idx['primary']) && sizeof($idx['primary']) == 1){
				$schema = $this->getKeySchema($idx['primary'][0]);
				if($schema['type'] == Model::ATT_TYPE_UUID){
					$refp = new ReflectionClass($class);
					$refm = $refp->getMethod('Construct');
					/** @var Model $parent */
					$parent = $refm->invoke(null, $this->get($idx['primary'][0]));

					// Populate the parent with this child's data.
					// Any non-existent field will simply be ignored.
					$parent->setFromArray($this->getAsArray());
					if($parent->save()){
						$changed = true;
					}
				}
			}
		}

		if($changed){
			$classname = get_called_class();
			// Allow all supplemental models to tap into this too!
			if(isset(self::$_ModelSupplementals[$classname])){
				foreach(self::$_ModelSupplementals[$classname] as $supplemental){
					if(class_exists($supplemental)){
						$ref = new ReflectionClass($supplemental);
						if($ref->hasMethod('PostSaveHook')){
							$ref->getMethod('PostSaveHook')->invoke(null, $this);
						}
					}
				}
			}
			HookHandler::DispatchHook('/core/model/postsave', $this);
			// Indicate that something happened.
			return true;
		}
		else{
			// Nothing happened!
			return false;
		}
	}
Example #4
0
	/**
	 * @deprecated 2013.05.31
	 * @return float
	 */
	public static function GetProfileTimeTotal() {
		error_log(__FUNCTION__ . ' is deprecated, please use \Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->getTime() instead', E_USER_DEPRECATED);
		return \Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->getTime();
	}
	/**
	 * Sync the search index fields of every model on the system.
	 *
	 * @return int
	 */
	public function syncSearchIndex(){
		// Admin-only page.
		if(!\Core\user()->checkAccess('g:admin')){
			return View::ERROR_ACCESSDENIED;
		}

		// Just run through every component currently installed and reinstall it.
		// This will just ensure that the component is up to date and correct as per the component.xml metafile.
		$view = $this->getView();
		$changes = [];
		$outoftime = false;
		$counter = 0;
		$resume = \Core\Session::Get('syncsearchresume', 1);
		$timeout = ini_get('max_execution_time');
		// Dunno why this is returning 0, but if it is, reset it to 30 seconds!
		if(!$timeout) $timeout = 30;
		$memorylimit = ini_get('memory_limit');
		if(stripos($memorylimit, 'M') !== false){
			$memorylimit = str_replace(['m', 'M'], '', $memorylimit);
			$memorylimit *= (1024*1024);
		}
		elseif(stripos($memorylimit, 'G') !== false){
			$memorylimit = str_replace(['g', 'G'], '', $memorylimit);
			$memorylimit *= (1024*1024*1024);
		}

		foreach(\Core::GetComponents() as $c){
			/** @var Component_2_1 $c */

			if($outoftime){
				break;
			}

			foreach($c->getClassList() as $class => $file){
				if($outoftime){
					break;
				}

				if($class == 'model'){
					continue;
				}
				if(strrpos($class, 'model') !== strlen($class) - 5){
					// If the class doesn't explicitly end with "Model", it's also not a model.
					continue;
				}
				if(strpos($class, '\\') !== false){
					// If this "Model" class is namespaced, it's not a valid model!
					// All Models MUST reside in the global namespace in order to be valid.
					continue;
				}

				$ref = new ReflectionClass($class);
				if(!$ref->getProperty('HasSearch')->getValue()){
					// This model doesn't have the searchable flag, skip it.
					continue;
				}

				$c = ['name' => $class, 'count' => 0];
				$fac = new ModelFactory($class);
				while(($m = $fac->getNext())){
					++$counter;

					if($counter < $resume){
						// Allow this process to be resumed where it left off, since it may take more than 30 seconds.
						continue;
					}

					if(\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->getTime() + 5 >= $timeout){
						// OUT OF TIME!
						// Remember where this process left off and exit.
						\Core\Session::Set('syncsearchresume', $counter);
						$outoftime = true;
						break;
					}

					if(memory_get_usage(true) + 40485760 >= $memorylimit){
						// OUT OF MEMORY!
						// Remember where this process left off and exit.
						\Core\Session::Set('syncsearchresume', $counter);
						$outoftime = true;
						break;
					}

					/** @var Model $m */
					$m->set('search_index_pri', '!');
					$m->save();
					$c['count']++;
				}

				$changes[] = $c;
			}
		}

		if(!$outoftime){
			// It finished!  Unset the resume counter.
			\Core\Session::UnsetKey('syncsearchresume');
		}


		$view->title = 'Sync Searchable Index';
		$view->assign('changes', $changes);
		$view->assign('outoftime', $outoftime);
	}
	/**
	 * Render the View to the browser.
	 */
	public function render(){
		\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Starting PageRequest->render()');

		$view = $this->getView();
		$page = $this->getPageModel();

		// Dispatch the hooks here if it's a 404 or 403.
		if ($view->error == View::ERROR_ACCESSDENIED || $view->error == View::ERROR_NOTFOUND) {
			// Let other things chew through it... (optionally)
			HookHandler::DispatchHook('/core/page/error-' . $view->error, $view);
		}

		try {
			// This will pre-fetch the contents of the entire page and store it into memory.
			// If it is cacheable, then it will be cached and used for the next execution.

			// If the user has the view user activity permission, add the link to that page!
			if(\Core\user()->checkAccess('p:user_activity_list') && $page && $page->exists()){
				$view->addControl(
					'User Activity Details',
					'/useractivity/details?filter[baseurl]=' . $page->get('baseurl'),
					'eye'
				);
			}

			$view->fetch();
		}
		catch (Exception $e) {
			// If something happens in the rendering of the template... consider it a server error.
			$view->error   = View::ERROR_SERVERERROR;
			$view->baseurl = '/error/error/500';
			$view->setParameters(array());
			$view->templatename   = '/pages/error/error500.tpl';
			$view->mastertemplate = ConfigHandler::Get('/theme/default_template');
			$view->assignVariable('exception', $e);
			\Core\ErrorManagement\exception_handler($e);

			$view->fetch();
		}


		if($this->isCacheable()){
			$uakey = \Core\UserAgent::Construct()->getPseudoIdentifier();
			$urlkey = $this->host . $this->uri;
			$expires = $page->get('expires'); // Number of seconds.
			$key = 'page-cache-' . md5($urlkey . '-' . $uakey);

			$d = new \Core\Date\DateTime();
			$d->modify('+' . $expires . ' seconds');

			$view->headers['Cache-Control'] = 'max-age=' . $expires;
			$view->headers['Expires'] = $d->format('r', \Core\Date\Timezone::TIMEZONE_GMT);
			$view->headers['Vary'] = 'Accept-Encoding,User-Agent,Cookie';
			$view->headers['X-Core-Cached-Date'] = \Core\Date\DateTime::NowGMT('r');
			$view->headers['X-Core-Cached-Server'] = 1; // @todo Implement multi-server support.
			$view->headers['X-Core-Cached-Render-Time'] = \Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->getTimeFormatted();

			// Record the actual View into cache.
			\Core\Cache::Set($key, $view, $expires);

			// And record the key onto an index cache record so there's a record of what to delete on updates.
			$indexkey = $page->getIndexCacheKey();
			$index = \Core\Cache::Get($indexkey, SECONDS_ONE_DAY);
			if(!$index){
				$index = [];
			}
			$index[] = $key;
			\Core\Cache::Set($indexkey, $index, SECONDS_ONE_DAY);
		}
		elseif(($reason = $this->isNotCacheableReason()) !== null){
			$view->headers['X-Core-NotCached-Reason'] = $reason;
		}
		$view->headers['X-Core-Render-Time'] = \Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->getTimeFormatted();

		$view->render();

		// Make sure I update any existing page now that the controller has ran.
		if ($page && $page->exists() && $view->error == View::ERROR_NOERROR) {

			// Only increase the pageview count if the visitor is not a bot.
			// UA detection isn't very accurate, but this isn't for precision accuracy, merely a rough estimate.
			if(!\Core\UserAgent::Construct()->isBot()){
				$page->set('pageviews', $page->get('pageviews') + 1);
			}

			$page->set('last_template', $view->templatename);
			$page->set('body', $view->fetchBody());

			$page->save();
		}

		// Just before the page stops execution...
		HookHandler::DispatchHook('/core/page/postrender');
	}
Example #7
0
	public function getPreviewFile($dimensions = '300x300'){
		// If the system is getting too close to the max_execution_time variable, just return the mimetype!
		// One note though, this is only available when running php from the web.
		// CLI scripts don't have it!
		if(ini_get('max_execution_time') && \Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->getTime() + 5 >= ini_get('max_execution_time')){
			// Try and get the mime icon for this file.
			$filemime = str_replace('/', '-', $this->getMimetype());

			$file = Factory::File('assets/images/mimetypes/' . $filemime . '.png');
			if(!$file->exists()){
				$file = Factory::File('assets/images/mimetypes/unknown.png');
			}
			return $file;
		}

		// This will get me the file, but none of the data or anything.
		$file = $this->getQuickPreviewFile($dimensions);

		$bits   = \Core\Filestore\get_resized_key_components($dimensions, $this);
		$width  = $bits['width'];
		$height = $bits['height'];
		$mode   = $bits['mode'];
		$key    = $bits['key'];

		// dunno how this may work... but prevent the possible infinite loop scenario.
		if($file == $this){
			return $this;
		}

		if (!$this->exists()) {
			// This will be a 404 image.
			//$file = \Core\Filestore\Factory::File('assets/images/mimetypes/notfound.png');
			return $file->getPreviewFile($dimensions);
		}
		elseif ($this->isPreviewable()) {
			// If no resize was requested, simply return the full size image.
			if($width === false) return $file;

			// if this file was smaller than the requested size, (and the mode isn't set to force the size)...
			$currentdata = getimagesize($this->getFilename());
			if(($mode == '' || $mode == '<') && $currentdata[0] <= $width){
				return $this;
			}
			//var_dump($currentdata, $width, $mode); die();

			if (!$file->exists()) {
				$this->_resizeTo($file, $width, $height, $mode);
			}

			return $file;
		}
		else {
			// This will be a mimetype image.
			return $file->getPreviewFile($dimensions);
		}
	}
Example #8
0
	/**
	 * Fetch this view as an HTML string.
	 * @return mixed|null|string
	 */
	public function fetch() {

		if($this->_fetchCache !== null){
			// w00t ;)
			return $this->_fetchCache;
		}

		try{
			$body = $this->fetchBody();
			\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record(
				'Fetched application content from within View->fetch() for ' . $this->templatename
			);
		}
		catch(Exception $e){
			$this->error = View::ERROR_SERVERERROR;
			\Core\ErrorManagement\exception_handler($e, ($this->mode == View::MODE_PAGE));
			$body = '';
		}


		// If there's no template, I have nothing to even do!
		if ($this->mastertemplate === false) {
			return $body;
		}
		// Else if it's null, it's just not set yet :p
		// @deprecated here!
		elseif ($this->mastertemplate === null) {
			$this->mastertemplate = ConfigHandler::Get('/theme/default_template');
		}

		// Whee!
		//var_dump($this->templatename, Core\Templates\Template::ResolveFile($this->templatename));
		// Content types take priority on controlling the master template.
		if ($this->contenttype == View::CTYPE_JSON) {
			$mastertpl = false;
		}
		else {
			// Master template depends on the render mode.
			switch ($this->mode) {
				case View::MODE_PAGEORAJAX:
					if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
						$mastertpl = false;
						$this->mode = View::MODE_AJAX;
					}
					else{
						$mastertpl = ROOT_PDIR . 'themes/' . ConfigHandler::Get('/theme/selected') . '/skins/' . $this->mastertemplate;
						$this->mode = View::MODE_PAGE;
					}
					break;
				case View::MODE_NOOUTPUT:
				case View::MODE_AJAX:
					$mastertpl = false;
					break;
				case View::MODE_PAGE:
				case View::MODE_EMAILORPRINT:
					$mastertpl = Core\Templates\Template::ResolveFile('skins/' . $this->mastertemplate);
					//$mastertpl = ROOT_PDIR . 'themes/' . ConfigHandler::Get('/theme/selected') . '/skins/' . $this->mastertemplate;
					break;
				case View::MODE_WIDGET:
					$mastertpl = Core\Templates\Template::ResolveFile('widgetcontainers/' . $this->mastertemplate);
					break;
			}
		}

		// If there's *still* no template, I still have nothing to do.
		if (!$mastertpl) return $body;


		$template = \Core\Templates\Template::Factory($mastertpl);
		// Ensure that the template is linked to this View correctly.
		$template->setView($this);
		//$template = new Core\Templates\Template();
		//$template->setBaseURL('/');
		// Page-level views have some special variables.
		if ($this->mode == View::MODE_PAGE) {
			$template->assign('breadcrumbs', $this->getBreadcrumbs());
			$template->assign('controls', $this->controls);
			$template->assign('messages', Core::GetMessages());

			// Tack on the pre and post body variables from the current page.
			//$body = CurrentPage::GetBodyPre() . $body . CurrentPage::GetBodyPost();
		}
		// Widgets need some special variables too.
		//if($this->mode == View::MODE_WIDGET){
		//	//var_dump($this->getVariable('widget')); die();
		//	$template->assign('widget', $this->getVariable('widget'));
		//}


		// This logic is needed for the SEO title, since that's usually completely human unfriendly.
		if(isset($this->meta['title']) && $this->meta['title']){
			$template->assign('seotitle', $this->meta['title']);
		}
		else{
			$template->assign('seotitle', $this->getTitle());
		}
		$template->assign('title', $this->getTitle());
		$template->assign('body', $body);

		// The body needs some custom classes for assisting the designers.
		// These are mainly pulled from the UA.
		$ua = \Core\UserAgent::Construct();

		$this->bodyclasses = array_merge($this->bodyclasses, $ua->getPseudoIdentifier(true));

		// Provide a way for stylesheets to target this page specifically.
		switch ($this->error) {
			case View::ERROR_BADREQUEST:
			case View::ERROR_PAYMENTREQUIRED:
			case View::ERROR_ACCESSDENIED:
			case View::ERROR_NOTFOUND:
			case View::ERROR_METHODNOTALLOWED:
			case View::ERROR_NOTACCEPTABLE:
			case View::ERROR_PROXYAUTHENTICATIONREQUIRED:
			case View::ERROR_REQUESTTIMEOUT:
			case View::ERROR_CONFLICT:
			case View::ERROR_GONE:
			case View::ERROR_LENGTHREQUIRED:
			case View::ERROR_PRECONDITIONFAILED:
			case View::ERROR_ENTITYTOOLARGE:
			case View::ERROR_URITOOLARGE:
			case View::ERROR_UNSUPPORTEDMEDIATYPE:
			case View::ERROR_RANGENOTSATISFIABLE:
			case View::ERROR_EXPECTATIONFAILED:
			case View::ERROR_UNAUTHORIZED:
				$url = 'error-' . $this->error;
				break;
			case 403:
				$url = "error-403 page-user-login";
				break;
			default:
				$url  = strtolower(trim(preg_replace('/[^a-z0-9\-]*/i', '', str_replace('/', '-', $this->baseurl)), '-'));
		}

		while($url != ''){
			$this->bodyclasses[] = 'page-' . $url;
			$url = substr($url, 0, strrpos($url, '-'));
		}


		$bodyclasses = strtolower(implode(' ', $this->bodyclasses));
		$template->assign('body_classes', $bodyclasses);

		try{
			$data = $template->fetch();
		}
		catch(SmartyException $e){
			$this->error = View::ERROR_SERVERERROR;
			error_log('[view error]');
			error_log('Template name: [' . $mastertpl . ']');
			\Core\ErrorManagement\exception_handler($e);
			require(ROOT_PDIR . 'core/templates/halt_pages/fatal_error.inc.html');
			die();
		}
		catch(TemplateException $e){
			$this->error = View::ERROR_SERVERERROR;
			error_log('[view error]');
			error_log('Template name: [' . $mastertpl . ']');
			\Core\ErrorManagement\exception_handler($e);
			require(ROOT_PDIR . 'core/templates/halt_pages/fatal_error.inc.html');
			die();
		}

		if($this->mode == View::MODE_EMAILORPRINT && $this->contenttype == View::CTYPE_HTML){
			// Inform other elements that the page is just about to be rendered.
			HookHandler::DispatchHook('/core/page/rendering', $this);

			// Replace the </head> tag with the head data from the current page
			// and the </body> with the foot data from the current page.
			// This is needed to be done at this stage because some element in
			// the template after rendering may add additional script to the head.
			// Also tack on any attributes for the <html> tag.
			if(preg_match('#</head>#i', $data)){
				// I need to do preg_replace because I only want to replace the FIRST instance of </head>
				$data = preg_replace('#</head>#i', $this->getHeadContent() . "\n" . '</head>', $data, 1);
			}
		}
		elseif ($this->mode == View::MODE_PAGE && $this->contenttype == View::CTYPE_HTML) {
			// Inform other elements that the page is just about to be rendered.
			HookHandler::DispatchHook('/core/page/rendering', $this);

			// Metadata!  w00t

			// Replace the </head> tag with the head data from the current page
			// and the </body> with the foot data from the current page.
			// This is needed to be done at this stage because some element in
			// the template after rendering may add additional script to the head.
			// Also tack on any attributes for the <html> tag.
			if(preg_match('#</head>#i', $data)){
				// I need to do preg_replace because I only want to replace the FIRST instance of </head>
				$data = preg_replace('#</head>#i', $this->getHeadContent() . "\n" . '</head>', $data, 1);
			}
			if(preg_match('#</body>#i', $data)){
				// I need to use strrpos because I only want the LAST instance of </body>
				$match = strrpos($data, '</body>');

				$foot = $this->getFootContent();

				if(defined('ENABLE_XHPROF') && function_exists('xhprof_disable')){
					require_once('xhprof_lib/utils/xhprof_lib.php'); #SKIPCOMPILER
					require_once('xhprof_lib/utils/xhprof_runs.php'); #SKIPCOMPILER
					$xhprof_data = xhprof_disable();
					$namespace = trim(str_replace(['.', '/'], '-', HOST . REL_REQUEST_PATH), '-');
					$xhprof_runs = new XHProfRuns_Default();
					$run_id = $xhprof_runs->save_run($xhprof_data, $namespace);

					define('XHPROF_RUN', $run_id);
					define('XHPROF_SOURCE', $namespace);

					$xhprof_link = sprintf(
						'<a href="' . SERVERNAME . '/xhprof/index.php?run=%s&source=%s" target="_blank">View XHprof Profiler Report</a>' . "\n",
						$run_id,
						$namespace
					);
				}
				else{
					$xhprof_link = '';
				}

				// If the viewmode is regular and DEVELOPMENT_MODE is enabled, show some possibly useful information now that everything's said and done.
				if (DEVELOPMENT_MODE) {
					$legend = '<div class="fieldset-title">%s<i class="icon-chevron-down expandable-hint"></i><i class="icon-chevron-up collapsible-hint"></i></div>' . "\n";

					$debug = '';
					$debug .= '<pre class="xdebug-var-dump screen">';
					$debug .= '<fieldset class="debug-section collapsible" id="debug-section-template-information">';
					$debug .= sprintf($legend, 'Template Information');
					$debug .= "<span>";
					$debug .= 'Base URL: ' . $this->baseurl . "\n";
					$debug .= 'Template Requested: ' . $this->templatename . "\n";
					$debug .= 'Template Actually Used: ' . \Core\Templates\Template::ResolveFile($this->templatename) . "\n";
					$debug .= 'Master Skin: ' . $this->mastertemplate . "\n";
					$debug .= "</span>";
					$debug .= '</fieldset>';

					$debug .= '<fieldset class="debug-section collapsible" id="debug-section-performance-information">';
					$debug .= sprintf($legend, 'Performance Information');
					$debug .= "<span>";
					$debug .= $xhprof_link;
					$debug .= "Database Reads: " . \Core\Utilities\Profiler\DatamodelProfiler::GetDefaultProfiler()->readCount() . "\n";
					$debug .= "Database Writes: " . \Core\Utilities\Profiler\DatamodelProfiler::GetDefaultProfiler()->writeCount() . "\n";
					//$debug .= "Number of queries: " . DB::Singleton()->counter . "\n";
					//$debug .= "Amount of memory used by PHP: " . \Core\Filestore\format_size(memory_get_usage()) . "\n";
					$debug .= "Amount of memory used by PHP: " . \Core\Filestore\format_size(memory_get_peak_usage(true)) . "\n";
					$profiler = Core\Utilities\Profiler\Profiler::GetDefaultProfiler();
					$debug .= "Total processing time: " . $profiler->getTimeFormatted() . "\n";
					$debug .= "</span>";
					$debug .= '</fieldset>';

					$debug .= '<fieldset class="debug-section collapsible" id="debug-section-profiler-information">';
					$debug .= sprintf($legend, 'Core Profiler');
					$debug .= "<span>";
					$debug .= $profiler->getEventTimesFormatted();
					$debug .= "</span>";
					$debug .= '</fieldset>';

					$debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-components-information">';
					// Tack on what components are currently installed.
					$debug .= sprintf($legend, 'Available Components');
					$debugcomponents = array_merge(Core::GetComponents(), Core::GetDisabledComponents());
					$debug .= "<span>";
					// Give me sorting!
					ksort($debugcomponents);
					foreach ($debugcomponents as $l => $v) {
						if($v->isEnabled() && $v->isReady()){
							$debug .= '[<span style="color:green;">Enabled</span>]';
						}
						elseif($v->isEnabled() && !$v->isReady()){
							$debug .= '[<span style="color:red;">!ERROR!</span>]';
						}
						else{
							$debug .= '[<span style="color:red;">Disabled</span>]';
						}


						$debug .= $v->getName() . ' ' . $v->getVersion() . "<br/>";
					}
					$debug .= "</span>";
					$debug .= '</fieldset>';

					$debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-hooks-information">';
					// I wanna see what hooks are registered too!
					$debug .= sprintf($legend, 'Registered Hooks');
					foreach(HookHandler::GetAllHooks() as $hook){
						$debug .= "<span>";
						/** @var $hook Hook */
						$debug .= $hook->name;
						if($hook->description) $debug .= ' <em> - ' . $hook->description . '</em>';
						$debug .= "\n" . '<span style="color:#999;">Return expected: ' . $hook->returnType . '</span>';
						$debug .= "\n" . '<span style="color:#999;">Attached by ' . $hook->getBindingCount() . ' binding(s).</span>';
						foreach($hook->getBindings() as $b){
							$debug .= "\n" . ' * ' . $b['call'];
						}
						$debug .= "\n\n";
						$debug .= "</span>";
					}
					$debug .= '</fieldset>';

					// Display the licensed content on this application
					$debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-licenser-information">';
					$debug .= sprintf($legend, 'Licensed Information');
					$lic = \Core\Licenser::GetRaw();
					$debug .= '<div>';
					foreach($lic as $dat){
						$debug .= $dat['url'] . '::' . $dat['feature'] . ' => ' . $dat['value'] . "\n";
					}
					$debug .= '</div></fieldset>';

					$debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-includes-information">';
					// I want to see how many files were included.
					$debug .= sprintf($legend, 'Included Files');
					$debug .= '<span>Number: ' . sizeof(get_included_files()) . "</span>";
					$debug .= '<span>'. implode("<br/>", get_included_files()) . "</span>";
					$debug .= '</fieldset>';

					$debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-query-information">';
					$debug .= sprintf($legend, 'Query Log');
					$profiler = \Core\Utilities\Profiler\DatamodelProfiler::GetDefaultProfiler();
					$debug .= '<div>' . $profiler->getEventTimesFormatted() . '</div>';
					$debug .= '</fieldset>';

					// Display all the i18n strings available on the system.
					$debug .= '<fieldset class="debug-section collapsible collapsed" id="debug-section-i18nstrings-information">';
					$debug .= sprintf($legend, 'I18N Strings Available');
					$strings = \Core\i18n\I18NLoader::GetAllStrings();
					$debug .= '<ul>';
					foreach($strings as &$s){
						$debug .= '<li>' . $s['key'] . '</li>';
					}
					$debug .= '</ul>';
					$debug .= '</fieldset>';
					$debug .= '</pre>';

					// And append!
					$foot .= "\n" . $debug;
				}
				$data = substr_replace($data, $foot . "\n" . '</body>', $match, 7);
			}
			$data = preg_replace('#<html#', '<html ' . $this->getHTMLAttributes(), $data, 1);


			// This logic has been migrated to the {$body_classes} variable.
			/*
			if(preg_match('/<body[^>]*>/', $data, $matches)){
				// body is $matches[0].
				$fullbody = $matches[0];
				if($fullbody == '<body>'){
					$body = '<body class="' . $bodyclass . '">';
				}
				elseif(strpos($fullbody, 'class=') === false){
					// Almost as easy, other elements but no class.
					$body = substr($fullbody, 0, -1) . ' class="' . $bodyclass . '">';
				}
				else{
					// parsing HTML is far easier with XML objects.
					$node = new SimpleXMLElement($fullbody . '</body>');
					$body = '<body';
					foreach($node->attributes() as $k => $v){
						if($k == 'class'){
							$body .= ' ' . $k . '="' . $bodyclass . ' ' . $v . '"';
						}
						else{
							$body .= ' ' . $k . '="' . $v . '"';
						}
					}
					$body .= '>';
				}

				// And replace!
				$data = preg_replace('#<body[^>]*>#', $body, $data, 1);
			}
			*/
		}

		$this->_fetchCache = $data;

		return $data;
	}
	/**
	 * Actually execute a binding call and get back the result.
	 *
	 * @param $call
	 * @param $args
	 *
	 * @return null|boolean|array
	 */
	public function callBinding($call, $args){
		// If the type is set to something and the call type is that
		// OR
		// The call type is not set/null.

		if(strpos($call['call'], '::') !== false){
			// Make sure this class exists first.
			// This way I can throw a pretty error instead of the default "Class not found".
			$parts = explode('::', $call['call']);
			if(!class_exists($parts[0])){
				trigger_error('The hook [' . $this->name . '] has an invalid call binding, the class [' . $parts[0] . '] does not appear to exist.', E_USER_NOTICE);
				$result = null;
			}
			else{
				$result = call_user_func_array($call['call'], $args);
			}
		}
		else{
			$result = call_user_func_array($call['call'], $args);
		}

		// If it's expecting an array, make sure it's an array!
		if($this->returnType == self::RETURN_TYPE_ARRAY && !is_array($result)){
			$result = array();
		}

		\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Called Hook Binding ' . $call['call']);
		return $result;
	}
Example #10
0
	error_log($e->getMessage());
	// Couldn't establish connection... do something fun!
	// If it's in development mode, redirect back to the installer, which should hopefully
	// get whatever problem this was fixed.
	if (DEVELOPMENT_MODE) {
		//header('HTTP/1.1 302 Moved Temporarily');
		//header('Location: ' . ROOT_WDIR . 'install');
		die('Please <a href="' . ROOT_WDIR . 'install' . '">install Core Plus.</a>');
	}

	else {
		require(ROOT_PDIR . 'core/templates/halt_pages/fatal_error.inc.html');
		die();
	}
}
\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Core Plus Data Model Interface loaded and ready');


unset($start_time, $predefines_time, $preincludes_time, $maindefines_time, $dbconn);




// < 2.5.0 Hack
// This is to provide support with < 2.5.0 configuration.xml files.
// Many of the CDN and FTP configuration options have been moved into the root configuration.xml file
// so that it's better supported in the installer.
if(!defined('FTP_USERNAME')){
	define('FTP_USERNAME', ConfigHandler::Get('/core/ftp/username'));
}
if(!defined('FTP_PASSWORD')){