/** * Handles an exception by showing an appropriate * error page. */ public function handleError(Exception $e, $server = null, array &$headers = null) { $displayErrors = $this->pieCrust->isDebuggingEnabled() || $this->pieCrust->getConfig()->getValue('site/display_errors'); // If debugging is enabled, just display the error and exit. if ($displayErrors) { if ($e->getMessage() == '404') { //TODO: set header? piecrust_show_system_message('404'); return; } $errorMessage = self::formatException($e, true); piecrust_show_system_message('error', $errorMessage); return; } // First of all, check that we're not running // some completely brand new and un-configured website. if ($this->isEmptySetup()) { piecrust_show_system_message('welcome'); return; } // Generic error message in case we don't have anything custom. $errorMessage = "<p>We're sorry but something very wrong happened, and we don't know what. " . "We'll try to do better next time.</p>" . PHP_EOL; // Get the URI to the custom error page, and the error code. if ($e->getMessage() == '404') { HttpHeaderHelper::setOrAddHeader(0, 404, $headers); $errorPageUri = '_404'; } else { HttpHeaderHelper::setOrAddHeader(0, 500, $headers); $errorPageUri = '_error'; } // Get the error page's info. try { $errorPageUriInfo = UriParser::parseUri($this->pieCrust, $errorPageUri, UriParser::PAGE_URI_REGULAR); } catch (Exception $inner) { // What the f**k. piecrust_show_system_message('critical', $errorMessage); return; } // Render the error page (either a custom one, or a generic one). if ($errorPageUriInfo != null and is_file($errorPageUriInfo['path'])) { // We have a custom error page. Show it, or display // the "fatal error" page if even this doesn't work. try { $runner = new PieCrustRunner($this->pieCrust); $runner->runUnsafe($errorPageUri, $server, null, $headers); } catch (Exception $inner) { // Well there's really something wrong. piecrust_show_system_message('critical', $errorMessage); } } else { // We don't have a custom error page. Just show the generic // error page. $errorMessage = self::formatException($e, false); piecrust_show_system_message(substr($errorPageUri, 1), $errorMessage); } }
/** * Runs PieCrust on the given URI with the given extra page rendering data, * but without any error handling. */ public function runUnsafe($uri = null, array $server = null, $extraPageData = null, array &$headers = null) { // Create an execution context. $executionContext = $this->pieCrust->getEnvironment()->getExecutionContext(true); // Check the cache validity, and clean it automatically. if ($this->pieCrust->isCachingEnabled()) { $cacheInfo = new PieCrustCacheInfo($this->pieCrust); $cacheValidity = $cacheInfo->getValidity(true); $executionContext->isCacheValid = $cacheValidity['is_valid']; $executionContext->wasCacheCleaned = $cacheValidity['was_cleaned']; } // Get the resource URI and corresponding physical path. if ($server == null) { $server = $_SERVER; } if ($uri == null) { $uri = ServerHelper::getRequestUri($server, $this->pieCrust->getConfig()->getValueUnchecked('site/pretty_urls')); } // Do the heavy lifting. $page = Page::createFromUri($this->pieCrust, $uri); $executionContext->pushPage($page); if ($extraPageData != null) { $page->setExtraPageData($extraPageData); } $pageRenderer = new PageRenderer($page); $output = $pageRenderer->get(); // Set or return the HTML headers. HttpHeaderHelper::setOrAddHeaders(PageRenderer::getHeaders($page->getConfig()->getValue('content_type'), $server), $headers); // Handle caching. if (!$this->pieCrust->isDebuggingEnabled()) { $hash = md5($output); HttpHeaderHelper::setOrAddHeader('Etag', '"' . $hash . '"', $headers); $clientHash = null; if (isset($server['HTTP_IF_NONE_MATCH'])) { $clientHash = $server['HTTP_IF_NONE_MATCH']; } if ($clientHash != null) { $clientHash = trim($clientHash, '"'); if ($hash == $clientHash) { HttpHeaderHelper::setOrAddHeader(0, 304, $headers); HttpHeaderHelper::setOrAddHeader('Content-Length', '0', $headers); return; } } } if ($this->pieCrust->isDebuggingEnabled()) { HttpHeaderHelper::setOrAddHeader('Cache-Control', 'no-cache, must-revalidate', $headers); } else { $cacheTime = PageHelper::getConfigValue($page, 'cache_time', 'site'); if ($cacheTime) { HttpHeaderHelper::setOrAddHeader('Cache-Control', 'public, max-age=' . $cacheTime, $headers); } } // Output with or without GZip compression. $gzipEnabled = ($this->pieCrust->getConfig()->getValueUnchecked('site/enable_gzip') === true and array_key_exists('HTTP_ACCEPT_ENCODING', $server) and strpos($server['HTTP_ACCEPT_ENCODING'], 'gzip') !== false); if ($gzipEnabled) { $zippedOutput = gzencode($output); if ($zippedOutput === false) { HttpHeaderHelper::setOrAddHeader('Content-Length', strlen($output), $headers); echo $output; } else { HttpHeaderHelper::setOrAddHeader('Content-Encoding', 'gzip', $headers); HttpHeaderHelper::setOrAddHeader('Content-Length', strlen($zippedOutput), $headers); echo $zippedOutput; } } else { HttpHeaderHelper::setOrAddHeader('Content-Length', strlen($output), $headers); echo $output; } }