123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- <?php
- /**
- * @package Grav\Common\Processors
- *
- * @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
- * @license MIT License; see LICENSE file for details.
- */
- namespace Grav\Common\Processors;
- use Grav\Common\Config\Config;
- use Grav\Common\Debugger;
- use Grav\Common\Errors\Errors;
- use Grav\Common\Grav;
- use Grav\Common\Page\Pages;
- use Grav\Common\Plugins;
- use Grav\Common\Session;
- use Grav\Common\Uri;
- use Grav\Common\Utils;
- use Grav\Framework\File\Formatter\YamlFormatter;
- use Grav\Framework\File\YamlFile;
- use Grav\Framework\Psr7\Response;
- use Grav\Framework\Session\Exceptions\SessionException;
- use Monolog\Formatter\LineFormatter;
- use Monolog\Handler\SyslogHandler;
- use Monolog\Logger;
- use Psr\Http\Message\RequestInterface;
- use Psr\Http\Message\ResponseInterface;
- use Psr\Http\Message\ServerRequestInterface;
- use Psr\Http\Server\RequestHandlerInterface;
- use function defined;
- use function in_array;
- /**
- * Class InitializeProcessor
- * @package Grav\Common\Processors
- */
- class InitializeProcessor extends ProcessorBase
- {
- /** @var string */
- public $id = '_init';
- /** @var string */
- public $title = 'Initialize';
- /** @var bool */
- protected static $cli_initialized = false;
- /**
- * @param Grav $grav
- * @return void
- */
- public static function initializeCli(Grav $grav)
- {
- if (!static::$cli_initialized) {
- static::$cli_initialized = true;
- $instance = new static($grav);
- $instance->processCli();
- }
- }
- /**
- * @param ServerRequestInterface $request
- * @param RequestHandlerInterface $handler
- * @return ResponseInterface
- */
- public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
- {
- $this->startTimer('_init', 'Initialize');
- // Load configuration.
- $config = $this->initializeConfig();
- // Initialize logger.
- $this->initializeLogger($config);
- // Initialize error handlers.
- $this->initializeErrors();
- // Initialize debugger.
- $debugger = $this->initializeDebugger();
- // Debugger can return response right away.
- $response = $this->handleDebuggerRequest($debugger, $request);
- if ($response) {
- $this->stopTimer('_init');
- return $response;
- }
- // Initialize output buffering.
- $this->initializeOutputBuffering($config);
- // Set timezone, locale.
- $this->initializeLocale($config);
- // Load plugins.
- $this->initializePlugins();
- // Load pages.
- $this->initializePages($config);
- // Load accounts (decides class to be used).
- // TODO: remove in 2.0.
- $this->container['accounts'];
- // Initialize session (used by URI, see issue #3269).
- $this->initializeSession($config);
- // Initialize URI (uses session, see issue #3269).
- $this->initializeUri($config);
- // Grav may return redirect response right away.
- $redirectCode = (int)$config->get('system.pages.redirect_trailing_slash', 1);
- if ($redirectCode) {
- $response = $this->handleRedirectRequest($request, $redirectCode > 300 ? $redirectCode : null);
- if ($response) {
- $this->stopTimer('_init');
- return $response;
- }
- }
- $this->stopTimer('_init');
- // Wrap call to next handler so that debugger can profile it.
- /** @var Response $response */
- $response = $debugger->profile(static function () use ($handler, $request) {
- return $handler->handle($request);
- });
- // Log both request and response and return the response.
- return $debugger->logRequest($request, $response);
- }
- public function processCli(): void
- {
- // Load configuration.
- $config = $this->initializeConfig();
- // Initialize logger.
- $this->initializeLogger($config);
- // Disable debugger.
- $this->container['debugger']->enabled(false);
- // Set timezone, locale.
- $this->initializeLocale($config);
- // Load plugins.
- $this->initializePlugins();
- // Load pages.
- $this->initializePages($config);
- // Initialize URI.
- $this->initializeUri($config);
- // Load accounts (decides class to be used).
- // TODO: remove in 2.0.
- $this->container['accounts'];
- }
- /**
- * @return Config
- */
- protected function initializeConfig(): Config
- {
- $this->startTimer('_init_config', 'Configuration');
- // Initialize Configuration
- $grav = $this->container;
- /** @var Config $config */
- $config = $grav['config'];
- $config->init();
- $grav['plugins']->setup();
- if (defined('GRAV_SCHEMA') && $config->get('versions') === null) {
- $filename = USER_DIR . 'config/versions.yaml';
- if (!is_file($filename)) {
- $versions = [
- 'core' => [
- 'grav' => [
- 'version' => GRAV_VERSION,
- 'schema' => GRAV_SCHEMA
- ]
- ]
- ];
- $config->set('versions', $versions);
- $file = new YamlFile($filename, new YamlFormatter(['inline' => 4]));
- $file->save($versions);
- }
- }
- // Override configuration using the environment.
- $prefix = 'GRAV_CONFIG';
- $env = getenv($prefix);
- if ($env) {
- $cPrefix = $prefix . '__';
- $aPrefix = $prefix . '_ALIAS__';
- $cLen = strlen($cPrefix);
- $aLen = strlen($aPrefix);
- $keys = $aliases = [];
- $env = $_ENV + $_SERVER;
- foreach ($env as $key => $value) {
- if (!str_starts_with($key, $prefix)) {
- continue;
- }
- if (str_starts_with($key, $cPrefix)) {
- $key = str_replace('__', '.', substr($key, $cLen));
- $keys[$key] = $value;
- } elseif (str_starts_with($key, $aPrefix)) {
- $key = substr($key, $aLen);
- $aliases[$key] = $value;
- }
- }
- $list = [];
- foreach ($keys as $key => $value) {
- foreach ($aliases as $alias => $real) {
- $key = str_replace($alias, $real, $key);
- }
- $list[$key] = $value;
- $config->set($key, $value);
- }
- }
- $this->stopTimer('_init_config');
- return $config;
- }
- /**
- * @param Config $config
- * @return Logger
- */
- protected function initializeLogger(Config $config): Logger
- {
- $this->startTimer('_init_logger', 'Logger');
- $grav = $this->container;
- // Initialize Logging
- /** @var Logger $log */
- $log = $grav['log'];
- if ($config->get('system.log.handler', 'file') === 'syslog') {
- $log->popHandler();
- $facility = $config->get('system.log.syslog.facility', 'local6');
- $logHandler = new SyslogHandler('grav', $facility);
- $formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%");
- $logHandler->setFormatter($formatter);
- $log->pushHandler($logHandler);
- }
- $this->stopTimer('_init_logger');
- return $log;
- }
- /**
- * @return Errors
- */
- protected function initializeErrors(): Errors
- {
- $this->startTimer('_init_errors', 'Error Handlers Reset');
- $grav = $this->container;
- // Initialize Error Handlers
- /** @var Errors $errors */
- $errors = $grav['errors'];
- $errors->resetHandlers();
- $this->stopTimer('_init_errors');
- return $errors;
- }
- /**
- * @return Debugger
- */
- protected function initializeDebugger(): Debugger
- {
- $this->startTimer('_init_debugger', 'Init Debugger');
- $grav = $this->container;
- /** @var Debugger $debugger */
- $debugger = $grav['debugger'];
- $debugger->init();
- $this->stopTimer('_init_debugger');
- return $debugger;
- }
- /**
- * @param Debugger $debugger
- * @param ServerRequestInterface $request
- * @return ResponseInterface|null
- */
- protected function handleDebuggerRequest(Debugger $debugger, ServerRequestInterface $request): ?ResponseInterface
- {
- // Clockwork integration.
- $clockwork = $debugger->getClockwork();
- if ($clockwork) {
- $server = $request->getServerParams();
- // $baseUri = str_replace('\\', '/', dirname(parse_url($server['SCRIPT_NAME'], PHP_URL_PATH)));
- // if ($baseUri === '/') {
- // $baseUri = '';
- // }
- $requestTime = $server['REQUEST_TIME_FLOAT'] ?? GRAV_REQUEST_TIME;
- $request = $request->withAttribute('request_time', $requestTime);
- // Handle clockwork API calls.
- $uri = $request->getUri();
- if (Utils::contains($uri->getPath(), '/__clockwork/')) {
- return $debugger->debuggerRequest($request);
- }
- $this->container['clockwork'] = $clockwork;
- }
- return null;
- }
- /**
- * @param Config $config
- */
- protected function initializeOutputBuffering(Config $config): void
- {
- $this->startTimer('_init_ob', 'Initialize Output Buffering');
- // Use output buffering to prevent headers from being sent too early.
- ob_start();
- if ($config->get('system.cache.gzip') && !@ob_start('ob_gzhandler')) {
- // Enable zip/deflate with a fallback in case of if browser does not support compressing.
- ob_start();
- }
- $this->stopTimer('_init_ob');
- }
- /**
- * @param Config $config
- */
- protected function initializeLocale(Config $config): void
- {
- $this->startTimer('_init_locale', 'Initialize Locale');
- // Initialize the timezone.
- $timezone = $config->get('system.timezone');
- if ($timezone) {
- date_default_timezone_set($timezone);
- }
- $grav = $this->container;
- $grav->setLocale();
- $this->stopTimer('_init_locale');
- }
- protected function initializePlugins(): Plugins
- {
- $this->startTimer('_init_plugins_load', 'Load Plugins');
- $grav = $this->container;
- /** @var Plugins $plugins */
- $plugins = $grav['plugins'];
- $plugins->init();
- $this->stopTimer('_init_plugins_load');
- return $plugins;
- }
- protected function initializePages(Config $config): Pages
- {
- $this->startTimer('_init_pages_register', 'Load Pages');
- $grav = $this->container;
- /** @var Pages $pages */
- $pages = $grav['pages'];
- // Upgrading from older Grav versions won't work without checking if the method exists.
- if (method_exists($pages, 'register')) {
- $pages->register();
- }
- $this->stopTimer('_init_pages_register');
- return $pages;
- }
- protected function initializeUri(Config $config): void
- {
- $this->startTimer('_init_uri', 'Initialize URI');
- $grav = $this->container;
- /** @var Uri $uri */
- $uri = $grav['uri'];
- $uri->init();
- $this->stopTimer('_init_uri');
- }
- protected function handleRedirectRequest(RequestInterface $request, int $code = null): ?ResponseInterface
- {
- if (!in_array($request->getMethod(), ['GET', 'HEAD'])) {
- return null;
- }
- // Redirect pages with trailing slash if configured to do so.
- $uri = $request->getUri();
- $path = $uri->getPath() ?: '/';
- $root = $this->container['uri']->rootUrl();
- if ($path !== $root && $path !== $root . '/' && Utils::endsWith($path, '/')) {
- // Use permanent redirect for SEO reasons.
- return $this->container->getRedirectResponse((string)$uri->withPath(rtrim($path, '/')), $code);
- }
- return null;
- }
- /**
- * @param Config $config
- */
- protected function initializeSession(Config $config): void
- {
- // FIXME: Initialize session should happen later after plugins have been loaded. This is a workaround to fix session issues in AWS.
- if (isset($this->container['session']) && $config->get('system.session.initialize', true)) {
- $this->startTimer('_init_session', 'Start Session');
- /** @var Session $session */
- $session = $this->container['session'];
- try {
- $session->init();
- } catch (SessionException $e) {
- $session->init();
- $message = 'Session corruption detected, restarting session...';
- $this->addMessage($message);
- $this->container['messages']->add($message, 'error');
- }
- $this->stopTimer('_init_session');
- }
- }
- }
|