Exemplo n.º 1
0
 public static function IncludeJQuery()
 {
     $use2x = \ConfigHandler::Get('/jquery/use_2_x');
     if ($use2x === 'auto') {
         // Determine if it should be used based on the UA.
         // Remember, only IE <= 8.0 requires this.
         $ua = \Core\UserAgent::Construct();
         if ($ua->browser == 'IE' && $ua->version <= 8) {
             $use2x = '0';
         } else {
             $use2x = '1';
         }
     }
     if ($use2x == '1') {
         // The site is setup to use 2.x, (default as of Core 4.0).
         \Core\view()->addScript('js/jquery/jquery-2.1.4.js');
     } else {
         // The admin requested not to use the new version of jQuery.  Stick with 1.11 then.
         \Core\view()->addScript('js/jquery/jquery-1.11.0.js');
     }
     // IMPORTANT!  Tells the script that the include succeeded!
     return true;
 }
	public function historical(){
		$request = $this->getPageRequest();
		$view = $this->getView();

		if(!$request->isJSON()) return View::ERROR_BADREQUEST;
		$view->contenttype = View::CTYPE_JSON;
		$view->mode = View::MODE_AJAX;
		$view->record = false;

		$profiler = new \Core\Utilities\Profiler\Profiler('useractivity');

		$limit  = $this->_getQueryLimit();
		$dstart = $request->getParameter('dstart');
		$dend   = $request->getParameter('dend');

		if(!$dend){
			$dend = Time::GetCurrent();
		}
		else{
			$dend = strtotime($dend);
		}
		if(!$dstart){
			$dstart = $dend - (3600 * 24 * 30);
		}
		else{
			$dstart = strtotime($dstart);
		}
		// Use FindRaw because it's faster than using full Models for everything, especially when dealing with 20k + records.
		$listings = UserActivityModel::FindRaw(array('datetime >= ' . $dstart, 'datetime <= ' . $dend), $limit, 'datetime DESC');
		$profiler->record('Found raw models');

		$data = array(
			'performance' => array('get' => 0, 'post' => 0),
			'requests'    => array('get' => 0, 'post' => 0),
			'counts'      => array('bots' => 0, 'users' => 0, 'visitors' => 0),
			'browsers'    => array(),
			'referrers'   => array(),
			'ips'         => array(),
			'os'          => array(),
			'notfounds'   => array(),
			'pages'       => array(),
		);

		$sessions = array();
		$x = 0;

		foreach($listings as $log){
			++$x;

			if($log['type'] == 'GET'){
				$data['performance']['get'] += $log['processing_time'];
				$data['requests']['get']++;
			}
			elseif($log['type'] == 'POST'){
				$data['performance']['post'] += $log['processing_time'];
				$data['requests']['post']++;
			}

			$ua = \Core\UserAgent::Construct($log['useragent']);

			if($ua->isBot()){
				$data['counts']['bots']++;
			}
			else{
				$data['counts']['users']++;

				if(!isset($sessions[ $log['session_id'] ])) $sessions[ $log['session_id'] ] = true;
			}

			$browser = $ua->browser . ' ' . $ua->version;

			if(!isset($data['browsers'][ $browser ])) $data['browsers'][ $browser ] = 1;
			else $data['browsers'][ $browser ]++;

			if($log['referrer'] == ''){
				$referrer = 'none';
			}
			elseif(strpos($log['referrer'], 'http://' . HOST) === 0){
				$referrer = 'internal';
			}
			elseif(strpos($log['referrer'], 'https://' . HOST) === 0){
				$referrer = 'internal-ssl';
			}
			else{
				// I want to trim the referrer a bit so I don't end up with a bunch of one-offs.
				if(($qpos = strpos($log['referrer'], '?')) !== false) $referrer = substr($log['referrer'], 0, $qpos);
				else $referrer = $log['referrer'];
			}

			if(!isset($data['referrers'][ $referrer ])) $data['referrers'][ $referrer ] = 1;
			else $data['referrers'][ $referrer ]++;

			if(!isset($data['ips'][ $log['ip_addr'] ])) $data['ips'][ $log['ip_addr'] ] = 1;
			else $data['ips'][ $log['ip_addr'] ]++;

			if(!isset($data['os'][ $ua->platform ])) $data['os'][ $ua->platform ] = 1;
			else $data['os'][ $ua->platform ]++;

			if($log['status'] == 404){
				if(!isset($data['notfounds'][ $log['request'] ])) $data['notfounds'][ $log['request'] ] = 1;
				else $data['notfounds'][ $log['request'] ]++;
			}

			if($log['status'] == 200){
				if(!isset($data['pages'][ $log['baseurl'] ])) $data['pages'][ $log['baseurl'] ] = 1;
				else $data['pages'][ $log['baseurl'] ]++;
			}

			$profiler->record('Parsed record #' . $x);
		}
//UserAgent::Test(); die();
		if($data['requests']['get'] > 0) $data['performance']['get'] = round($data['performance']['get'] /  $data['requests']['get'], 2);
		if($data['requests']['post'] > 0) $data['performance']['post'] = $data['performance']['post'] /  $data['requests']['post'];

		$data['counts']['visitors'] = sizeof($sessions);

		// Do some sorting on a few of the arrays.
		arsort($data['browsers']);
		arsort($data['referrers']);
		arsort($data['ips']);
		arsort($data['os']);
		arsort($data['notfounds']);
		arsort($data['pages']);

		$profiler->record('Sorted all data');

		// DEBUG!
		//echo '<pre>';
		//echo $profiler->getEventTimesFormatted();
		//die();

		//var_dump($data, $users, $listings); die();
		$view->jsondata = $data;
	}
Exemplo n.º 3
0
	/**
	 * 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');
	}
Exemplo n.º 4
0
	/**
	 * Function that attaches the core javascript to the page.
	 *
	 * This should be called automatically from the hook /core/page/preexecute.
	 */
	public static function _AttachCoreJavascript() {

		if(Core::IsComponentAvailable('User')){
			$userid   = (\Core\user()->get('id') ? \Core\user()->get('id') : 0);
			$userauth = \Core\user()->exists() ? 'true' : 'false';
		}
		else{
			$userid   = 0;
			$userauth = 'false';
		}

		$ua = \Core\UserAgent::Construct();
		$uastring = '';
		foreach($ua->asArray() as $k => $v){
			if($v === true){
				$uastring .= "\t\t\t$k: true,\n";
			}
			elseif($v === false){
				$uastring .= "\t\t\t$k: false,\n";
			}
			else{
				$uastring .= "\t\t\t$k: \"$v\",\n";
			}

		}
		$uastring .= "\t\t\tis_mobile: " . ($ua->isMobile() ? 'true' : 'false') . "\n";

		$url = htmlentities(\Core\page_request()->uriresolved);

		if(ConfigHandler::Get('/core/page/url_remove_stop_words')){
			$stopwords = json_encode(\Core\get_stop_words());
			$removeStopWords = 'true';
		}
		else{
			$stopwords = '""';
			$removeStopWords = 'false';
		}
		$version      = DEVELOPMENT_MODE ? self::GetComponent()->getVersion() : '';
		$rootWDIR     = ROOT_WDIR;
		$rootURL      = ROOT_URL;
		$rootURLSSL   = ROOT_URL_SSL;
		$rootURLnoSSL = ROOT_URL_NOSSL;
		$ssl          = SSL ? 'true' : 'false';
		$sslMode      = SSL_MODE;

		$script = <<<EOD
<script type="text/javascript">
	var Core = {
		Version: "$version",
		ROOT_WDIR: "$rootWDIR",
		ROOT_URL: "$rootURL",
		ROOT_URL_SSL: "$rootURLSSL",
		ROOT_URL_NOSSL: "$rootURLnoSSL",
		SSL: $ssl,
		SSL_MODE: "$sslMode",
		User: {
			id: "$userid",
			authenticated: $userauth
		},
		Url: "$url",
		Browser: { $uastring },
		URLRemoveStopWords: $removeStopWords,
		StopWords: $stopwords
	};
</script>
EOD;

		$minified = \ConfigHandler::Get('/core/javascript/minified');
		if($minified){
			$script = str_replace(["\t", "\n"], ['', ''], $script);
		}

		\Core\view()->addScript($script, 'head');

		// And the static functions.
		\Core\view()->addScript('js/core.js', 'foot');
		//\Core\view()->addScript('js/core-foot.js', 'foot');
	}
Exemplo n.º 5
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;
	}