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>'; } }
/** * 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); } }
/** * 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; } }
/** * @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'); }
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); } }
/** * 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; }
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')){