diff --git a/.github/workflows/test-phpcpd.yml b/.github/workflows/test-phpcpd.yml index 5c89eaf4337e..c0bf72f3bf10 100644 --- a/.github/workflows/test-phpcpd.yml +++ b/.github/workflows/test-phpcpd.yml @@ -57,4 +57,5 @@ jobs: --exclude system/Debug/Exceptions.php --exclude system/HTTP/SiteURI.php --exclude system/Validation/Rules.php + --exclude system/Autoloader/Autoloader.php -- app/ public/ system/ diff --git a/app/Config/Cache.php b/app/Config/Cache.php index b29c13a9ea71..3fbade6840cc 100644 --- a/app/Config/Cache.php +++ b/app/Config/Cache.php @@ -46,25 +46,6 @@ class Cache extends BaseConfig */ public string $storePath = WRITEPATH . 'cache/'; - /** - * -------------------------------------------------------------------------- - * Cache Include Query String - * -------------------------------------------------------------------------- - * - * Whether to take the URL query string into consideration when generating - * output cache files. Valid options are: - * - * false = Disabled - * true = Enabled, take all query parameters into account. - * Please be aware that this may result in numerous cache - * files generated for the same page over and over again. - * ['q'] = Enabled, but only take into account the specified list - * of query parameters. - * - * @var bool|list - */ - public $cacheQueryString = false; - /** * -------------------------------------------------------------------------- * Key Prefix @@ -168,4 +149,23 @@ class Cache extends BaseConfig 'redis' => RedisHandler::class, 'wincache' => WincacheHandler::class, ]; + + /** + * -------------------------------------------------------------------------- + * Web Page Caching: Cache Include Query String + * -------------------------------------------------------------------------- + * + * Whether to take the URL query string into consideration when generating + * output cache files. Valid options are: + * + * false = Disabled + * true = Enabled, take all query parameters into account. + * Please be aware that this may result in numerous cache + * files generated for the same page over and over again. + * ['q'] = Enabled, but only take into account the specified list + * of query parameters. + * + * @var bool|list + */ + public $cacheQueryString = false; } diff --git a/app/Config/Optimize.php b/app/Config/Optimize.php new file mode 100644 index 000000000000..6fb441fd2288 --- /dev/null +++ b/app/Config/Optimize.php @@ -0,0 +1,32 @@ +systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php'; - -// Load environment settings from .env files into $_SERVER and $_ENV -require_once SYSTEMPATH . 'Config/DotEnv.php'; -(new CodeIgniter\Config\DotEnv(ROOTPATH))->load(); - -// Define ENVIRONMENT -if (! defined('ENVIRONMENT')) { - define('ENVIRONMENT', env('CI_ENVIRONMENT', 'production')); -} - -// Load Config Cache -// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache(); -// $factoriesCache->load('config'); -// ^^^ Uncomment these lines if you want to use Config Caching. - -/* - * --------------------------------------------------------------- - * GRAB OUR CODEIGNITER INSTANCE - * --------------------------------------------------------------- - * - * The CodeIgniter class contains the core functionality to make - * the application run, and does all the dirty work to get - * the pieces all working together. - */ - -$app = Config\Services::codeigniter(); -$app->initialize(); -$context = is_cli() ? 'php-cli' : 'web'; -$app->setContext($context); - -/* - *--------------------------------------------------------------- - * LAUNCH THE APPLICATION - *--------------------------------------------------------------- - * Now that everything is set up, it's time to actually fire - * up the engines and make this app do its thang. - */ - -$app->run(); - -// Save Config Cache -// $factoriesCache->save('config'); -// ^^^ Uncomment this line if you want to use Config Caching. +// LOAD THE FRAMEWORK BOOTSTRAP FILE +require $paths->systemDirectory . '/Boot.php'; -// Exits the application, setting the exit code for CLI-based applications -// that might be watching. -exit(EXIT_SUCCESS); +exit(CodeIgniter\Boot::bootWeb($paths)); diff --git a/spark b/spark index adbd43fafd63..a56fbc1bd7b6 100755 --- a/spark +++ b/spark @@ -12,13 +12,16 @@ /* * -------------------------------------------------------------------- - * CodeIgniter command-line tools + * CODEIGNITER COMMAND-LINE TOOLS * -------------------------------------------------------------------- * The main entry point into the CLI system and allows you to run * commands and perform maintenance on your application. - * - * Because CodeIgniter can handle CLI requests as just another web request - * this class mainly acts as a passthru to the framework itself. + */ + +/* + *--------------------------------------------------------------- + * CHECK SERVER API + *--------------------------------------------------------------- */ // Refuse to run when called from php-cgi @@ -26,7 +29,12 @@ if (strpos(PHP_SAPI, 'cgi') === 0) { exit("The cli tool is not supported when running php-cgi. It needs php-cli to function!\n\n"); } -// Check PHP version. +/* + *--------------------------------------------------------------- + * CHECK PHP VERSION + *--------------------------------------------------------------- + */ + $minPhpVersion = '8.1'; // If you update this, don't forget to update `public/index.php`. if (version_compare(PHP_VERSION, $minPhpVersion, '<')) { $message = sprintf( @@ -42,6 +50,12 @@ if (version_compare(PHP_VERSION, $minPhpVersion, '<')) { error_reporting(E_ALL); ini_set('display_errors', '1'); +/* + *--------------------------------------------------------------- + * SET THE CURRENT DIRECTORY + *--------------------------------------------------------------- + */ + // Path to the front controller define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR); @@ -57,41 +71,14 @@ chdir(FCPATH); * and fires up an environment-specific bootstrapping. */ -// Load our paths config file +// LOAD OUR PATHS CONFIG FILE // This is the line that might need to be changed, depending on your folder structure. require FCPATH . '../app/Config/Paths.php'; // ^^^ Change this line if you move your application folder $paths = new Config\Paths(); -// Location of the framework bootstrap file. -require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php'; - -// Load environment settings from .env files into $_SERVER and $_ENV -require_once SYSTEMPATH . 'Config/DotEnv.php'; -(new CodeIgniter\Config\DotEnv(ROOTPATH))->load(); - -// Define ENVIRONMENT -if (! defined('ENVIRONMENT')) { - define('ENVIRONMENT', env('CI_ENVIRONMENT', 'production')); -} - -// Grab our CodeIgniter -$app = Config\Services::codeigniter(); -$app->initialize(); - -// Grab our Console -$console = new CodeIgniter\CLI\Console(); - -// Show basic information before we do anything else. -if (is_int($suppress = array_search('--no-header', $_SERVER['argv'], true))) { - unset($_SERVER['argv'][$suppress]); // @codeCoverageIgnore - $suppress = true; -} - -$console->showHeader($suppress); - -// fire off the command in the main framework. -$exit = $console->run(); +// LOAD THE FRAMEWORK BOOTSTRAP FILE +require $paths->systemDirectory . '/Boot.php'; -exit(is_int($exit) ? $exit : EXIT_SUCCESS); +exit(CodeIgniter\Boot::bootSpark($paths)); diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 48516e522584..c8c1767a9d83 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -17,8 +17,13 @@ use Composer\Autoload\ClassLoader; use Composer\InstalledVersions; use Config\Autoload; +use Config\Kint as KintConfig; use Config\Modules; +use Config\Services; use InvalidArgumentException; +use Kint; +use Kint\Renderer\CliRenderer; +use Kint\Renderer\RichRenderer; use RuntimeException; /** @@ -481,4 +486,76 @@ public function loadHelpers(): void { helper($this->helpers); } + + /** + * Initializes Kint + */ + public function initializeKint(bool $debug = false): void + { + if ($debug) { + $this->autoloadKint(); + $this->configureKint(); + } elseif (class_exists(Kint::class)) { + // In case that Kint is already loaded via Composer. + Kint::$enabled_mode = false; + } + + helper('kint'); + } + + private function autoloadKint(): void + { + // If we have KINT_DIR it means it's already loaded via composer + if (! defined('KINT_DIR')) { + spl_autoload_register(function ($class) { + $class = explode('\\', $class); + + if (array_shift($class) !== 'Kint') { + return; + } + + $file = SYSTEMPATH . 'ThirdParty/Kint/' . implode('/', $class) . '.php'; + + if (is_file($file)) { + require_once $file; + } + }); + + require_once SYSTEMPATH . 'ThirdParty/Kint/init.php'; + } + } + + private function configureKint(): void + { + $config = new KintConfig(); + + Kint::$depth_limit = $config->maxDepth; + Kint::$display_called_from = $config->displayCalledFrom; + Kint::$expanded = $config->expanded; + + if (isset($config->plugins) && is_array($config->plugins)) { + Kint::$plugins = $config->plugins; + } + + $csp = Services::csp(); + if ($csp->enabled()) { + RichRenderer::$js_nonce = $csp->getScriptNonce(); + RichRenderer::$css_nonce = $csp->getStyleNonce(); + } + + RichRenderer::$theme = $config->richTheme; + RichRenderer::$folder = $config->richFolder; + RichRenderer::$sort = $config->richSort; + if (isset($config->richObjectPlugins) && is_array($config->richObjectPlugins)) { + RichRenderer::$value_plugins = $config->richObjectPlugins; + } + if (isset($config->richTabPlugins) && is_array($config->richTabPlugins)) { + RichRenderer::$tab_plugins = $config->richTabPlugins; + } + + CliRenderer::$cli_colors = $config->cliColors; + CliRenderer::$force_utf8 = $config->cliForceUTF8; + CliRenderer::$detect_width = $config->cliDetectWidth; + CliRenderer::$min_terminal_width = $config->cliMinWidth; + } } diff --git a/system/Boot.php b/system/Boot.php new file mode 100644 index 000000000000..026b10298205 --- /dev/null +++ b/system/Boot.php @@ -0,0 +1,326 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter; + +use CodeIgniter\Cache\FactoriesCache; +use CodeIgniter\CLI\Console; +use CodeIgniter\Config\DotEnv; +use CodeIgniter\Exceptions\FrameworkException; +use Config\Autoload; +use Config\Modules; +use Config\Optimize; +use Config\Paths; +use Config\Services; + +/** + * Bootstrap for the application + * + * @codeCoverageIgnore + */ +class Boot +{ + /** + * @used-by public/index.php + * + * Context + * web: Invoked by HTTP request + * php-cli: Invoked by CLI via `php public/index.php` + * + * @return int Exit code. + */ + public static function bootWeb(Paths $paths): int + { + static::loadDotEnv($paths); + static::defineEnvironment(); + static::loadEnvironmentBootstrap($paths); + static::definePathConstants($paths); + if (! defined('APP_NAMESPACE')) { + static::loadConstants(); + } + static::loadCommonFunctions(); + static::loadAutoloader(); + static::setExceptionHandler(); + static::checkMissingExtensions(); + static::initializeKint(); + + $configCacheEnabled = class_exists(Optimize::class) + && (new Optimize())->configCacheEnabled; + if ($configCacheEnabled) { + $factoriesCache = static::loadConfigCache(); + } + + static::autoloadHelpers(); + + $app = static::initializeCodeIgniter(); + static::runCodeIgniter($app); + + if ($configCacheEnabled) { + static::saveConfigCache($factoriesCache); + } + + // Exits the application, setting the exit code for CLI-based + // applications that might be watching. + return EXIT_SUCCESS; + } + + /** + * @used-by spark + * + * @return int Exit code. + */ + public static function bootSpark(Paths $paths): int + { + static::loadDotEnv($paths); + static::defineEnvironment(); + static::loadEnvironmentBootstrap($paths); + static::definePathConstants($paths); + if (! defined('APP_NAMESPACE')) { + static::loadConstants(); + } + static::loadCommonFunctions(); + static::loadAutoloader(); + static::setExceptionHandler(); + static::checkMissingExtensions(); + static::initializeKint(); + static::autoloadHelpers(); + + static::initializeCodeIgniter(); + $console = static::initializeConsole(); + + return static::runCommand($console); + } + + /** + * @used-by system/Test/bootstrap.php + */ + public static function bootTest(Paths $paths): void + { + static::loadDotEnv($paths); + static::loadEnvironmentBootstrap($paths, false); + static::loadConstants(); + static::loadCommonFunctions(); + static::loadAutoloader(); + static::setExceptionHandler(); + static::checkMissingExtensions(); + static::initializeKint(); + static::autoloadHelpers(); + } + + /** + * Load environment settings from .env files into $_SERVER and $_ENV + */ + protected static function loadDotEnv(Paths $paths): void + { + require_once $paths->systemDirectory . '/Config/DotEnv.php'; + (new DotEnv($paths->appDirectory . '/../'))->load(); + } + + protected static function defineEnvironment(): void + { + if (! defined('ENVIRONMENT')) { + // @phpstan-ignore-next-line + $env = $_ENV['CI_ENVIRONMENT'] ?? $_SERVER['CI_ENVIRONMENT'] ?? getenv('CI_ENVIRONMENT'); + + define('ENVIRONMENT', ($env !== false) ? $env : 'production'); + unset($env); + } + } + + protected static function loadEnvironmentBootstrap(Paths $paths, bool $exit = true): void + { + if (is_file($paths->appDirectory . '/Config/Boot/' . ENVIRONMENT . '.php')) { + require_once $paths->appDirectory . '/Config/Boot/' . ENVIRONMENT . '.php'; + + return; + } + + if ($exit) { + header('HTTP/1.1 503 Service Unavailable.', true, 503); + echo 'The application environment is not set correctly.'; + + exit(EXIT_ERROR); + } + } + + /** + * The path constants provide convenient access to the folders throughout + * the application. We have to set them up here, so they are available in + * the config files that are loaded. + */ + protected static function definePathConstants(Paths $paths): void + { + // The path to the application directory. + if (! defined('APPPATH')) { + define('APPPATH', realpath(rtrim($paths->appDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); + } + + // The path to the project root directory. Just above APPPATH. + if (! defined('ROOTPATH')) { + define('ROOTPATH', realpath(APPPATH . '../') . DIRECTORY_SEPARATOR); + } + + // The path to the system directory. + if (! defined('SYSTEMPATH')) { + define('SYSTEMPATH', realpath(rtrim($paths->systemDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); + } + + // The path to the writable directory. + if (! defined('WRITEPATH')) { + define('WRITEPATH', realpath(rtrim($paths->writableDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); + } + + // The path to the tests directory + if (! defined('TESTPATH')) { + define('TESTPATH', realpath(rtrim($paths->testsDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); + } + } + + protected static function loadConstants(): void + { + require_once APPPATH . 'Config/Constants.php'; + } + + protected static function loadCommonFunctions(): void + { + // Require app/Common.php file if exists. + if (is_file(APPPATH . 'Common.php')) { + require_once APPPATH . 'Common.php'; + } + + // Require system/Common.php + require_once SYSTEMPATH . 'Common.php'; + } + + /** + * The autoloader allows all the pieces to work together in the framework. + * We have to load it here, though, so that the config files can use the + * path constants. + */ + protected static function loadAutoloader(): void + { + if (! class_exists(Autoload::class, false)) { + require_once SYSTEMPATH . 'Config/AutoloadConfig.php'; + require_once APPPATH . 'Config/Autoload.php'; + require_once SYSTEMPATH . 'Modules/Modules.php'; + require_once APPPATH . 'Config/Modules.php'; + } + + require_once SYSTEMPATH . 'Autoloader/Autoloader.php'; + require_once SYSTEMPATH . 'Config/BaseService.php'; + require_once SYSTEMPATH . 'Config/Services.php'; + require_once APPPATH . 'Config/Services.php'; + + // Initialize and register the loader with the SPL autoloader stack. + Services::autoloader()->initialize(new Autoload(), new Modules())->register(); + } + + protected static function autoloadHelpers(): void + { + Services::autoloader()->loadHelpers(); + } + + protected static function setExceptionHandler(): void + { + Services::exceptions()->initialize(); + } + + protected static function checkMissingExtensions(): void + { + // Run this check for manual installations + if (! is_file(COMPOSER_PATH)) { + $missingExtensions = []; + + foreach ([ + 'intl', + 'json', + 'mbstring', + ] as $extension) { + if (! extension_loaded($extension)) { + $missingExtensions[] = $extension; + } + } + + if ($missingExtensions !== []) { + throw FrameworkException::forMissingExtension(implode(', ', $missingExtensions)); + } + + unset($missingExtensions); + } + } + + protected static function initializeKint(): void + { + Services::autoloader()->initializeKint(CI_DEBUG); + } + + protected static function loadConfigCache(): FactoriesCache + { + $factoriesCache = new FactoriesCache(); + $factoriesCache->load('config'); + + return $factoriesCache; + } + + /** + * The CodeIgniter class contains the core functionality to make + * the application run, and does all the dirty work to get + * the pieces all working together. + */ + protected static function initializeCodeIgniter(): CodeIgniter + { + $app = Config\Services::codeigniter(); + $app->initialize(); + $context = is_cli() ? 'php-cli' : 'web'; + $app->setContext($context); + + return $app; + } + + /** + * Now that everything is set up, it's time to actually fire + * up the engines and make this app do its thang. + */ + protected static function runCodeIgniter(CodeIgniter $app): void + { + $app->run(); + } + + protected static function saveConfigCache(FactoriesCache $factoriesCache): void + { + $factoriesCache->save('config'); + } + + protected static function initializeConsole(): Console + { + $console = new Console(); + + // Show basic information before we do anything else. + // @phpstan-ignore-next-line + if (is_int($suppress = array_search('--no-header', $_SERVER['argv'], true))) { + unset($_SERVER['argv'][$suppress]); // @phpstan-ignore-line + $suppress = true; + } + + $console->showHeader($suppress); + + return $console; + } + + protected static function runCommand(Console $console): int + { + $exit = $console->run(); + + return is_int($exit) ? $exit : EXIT_SUCCESS; + } +} diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 8322d4ee34eb..01ec43408484 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -186,24 +186,11 @@ public function __construct(App $config) */ public function initialize() { - // Define environment variables - $this->bootstrapEnvironment(); - - // Setup Exception Handling - Services::exceptions()->initialize(); - - // Run this check for manual installations - if (! is_file(COMPOSER_PATH)) { - $this->resolvePlatformExtensions(); // @codeCoverageIgnore - } - // Set default locale on the server Locale::setDefault($this->config->defaultLocale ?? 'en'); // Set default timezone on the server date_default_timezone_set($this->config->appTimezone ?? 'UTC'); - - $this->initializeKint(); } /** @@ -214,6 +201,8 @@ public function initialize() * @throws FrameworkException * * @codeCoverageIgnore + * + * @deprecated 4.5.0 Moved to system/bootstrap.php. */ protected function resolvePlatformExtensions() { @@ -240,6 +229,8 @@ protected function resolvePlatformExtensions() * Initializes Kint * * @return void + * + * @deprecated 4.5.0 Moved to Autoloader. */ protected function initializeKint() { @@ -255,6 +246,9 @@ protected function initializeKint() helper('kint'); } + /** + * @deprecated 4.5.0 Moved to Autoloader. + */ private function autoloadKint(): void { // If we have KINT_DIR it means it's already loaded via composer @@ -277,6 +271,9 @@ private function autoloadKint(): void } } + /** + * @deprecated 4.5.0 Moved to Autoloader. + */ private function configureKint(): void { $config = new KintConfig(); @@ -578,6 +575,8 @@ protected function detectEnvironment() * is wrong. At the very least, they should have error reporting setup. * * @return void + * + * @deprecated 4.5.0 Moved to system/bootstrap.php. */ protected function bootstrapEnvironment() { diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index 588f66534949..dec0ac2020d8 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -15,6 +15,7 @@ use CodeIgniter\Autoloader\Autoloader; use CodeIgniter\Autoloader\FileLocator; +use CodeIgniter\Autoloader\FileLocatorCached; use CodeIgniter\Autoloader\FileLocatorInterface; use CodeIgniter\Cache\CacheInterface; use CodeIgniter\Cache\ResponseCache; @@ -71,6 +72,7 @@ use Config\Images; use Config\Migrations; use Config\Modules; +use Config\Optimize; use Config\Pager as ConfigPager; use Config\Services as AppServices; use Config\Toolbar as ConfigToolbar; @@ -235,7 +237,14 @@ public static function locator(bool $getShared = true) { if ($getShared) { if (empty(static::$instances['locator'])) { - static::$instances['locator'] = new FileLocator(static::autoloader()); + $cacheEnabled = class_exists(Optimize::class) + && (new Optimize())->locatorCacheEnabled; + + if ($cacheEnabled) { + static::$instances['locator'] = new FileLocatorCached(new FileLocator(static::autoloader())); + } else { + static::$instances['locator'] = new FileLocator(static::autoloader()); + } } return static::$mocks['locator'] ?? static::$instances['locator']; diff --git a/system/Test/bootstrap.php b/system/Test/bootstrap.php index 8b992be9f884..0810ac5d180c 100644 --- a/system/Test/bootstrap.php +++ b/system/Test/bootstrap.php @@ -11,9 +11,7 @@ * the LICENSE file that was distributed with this source code. */ -use CodeIgniter\Config\DotEnv; -use Config\Autoload; -use Config\Modules; +use CodeIgniter\Boot; use Config\Paths; use Config\Services; @@ -21,11 +19,28 @@ ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); +/* + * --------------------------------------------------------------- + * DEFINE ENVIRONMENT + * --------------------------------------------------------------- + */ + // Make sure it recognizes that we're testing. $_SERVER['CI_ENVIRONMENT'] = 'testing'; define('ENVIRONMENT', 'testing'); + defined('CI_DEBUG') || define('CI_DEBUG', true); +/* + * --------------------------------------------------------------- + * SETUP OUR PATH CONSTANTS + * --------------------------------------------------------------- + * + * The path constants provide convenient access to the folders + * throughout the application. We have to set them up here + * so they are available in the config files that are loaded. + */ + // Often these constants are pre-defined, but query the current directory structure as a fallback defined('HOMEPATH') || define('HOMEPATH', realpath(rtrim(getcwd(), '\\/ ')) . DIRECTORY_SEPARATOR); $source = is_dir(HOMEPATH . 'app') @@ -35,59 +50,42 @@ defined('PUBLICPATH') || define('PUBLICPATH', realpath($source . 'public') . DIRECTORY_SEPARATOR); unset($source); +// LOAD OUR PATHS CONFIG FILE // Load framework paths from their config file require CONFIGPATH . 'Paths.php'; $paths = new Paths(); // Define necessary framework path constants -defined('APPPATH') || define('APPPATH', realpath(rtrim($paths->appDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); -defined('WRITEPATH') || define('WRITEPATH', realpath(rtrim($paths->writableDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); -defined('SYSTEMPATH') || define('SYSTEMPATH', realpath(rtrim($paths->systemDirectory, '\\/')) . DIRECTORY_SEPARATOR); -defined('ROOTPATH') || define('ROOTPATH', realpath(APPPATH . '../') . DIRECTORY_SEPARATOR); -defined('CIPATH') || define('CIPATH', realpath(SYSTEMPATH . '../') . DIRECTORY_SEPARATOR); -defined('FCPATH') || define('FCPATH', realpath(PUBLICPATH) . DIRECTORY_SEPARATOR); -defined('TESTPATH') || define('TESTPATH', realpath(HOMEPATH . 'tests/') . DIRECTORY_SEPARATOR); +defined('APPPATH') || define('APPPATH', realpath(rtrim($paths->appDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); +defined('ROOTPATH') || define('ROOTPATH', realpath(APPPATH . '../') . DIRECTORY_SEPARATOR); +defined('SYSTEMPATH') || define('SYSTEMPATH', realpath(rtrim($paths->systemDirectory, '\\/')) . DIRECTORY_SEPARATOR); +defined('WRITEPATH') || define('WRITEPATH', realpath(rtrim($paths->writableDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); +defined('TESTPATH') || define('TESTPATH', realpath(HOMEPATH . 'tests/') . DIRECTORY_SEPARATOR); + +defined('CIPATH') || define('CIPATH', realpath(SYSTEMPATH . '../') . DIRECTORY_SEPARATOR); +defined('FCPATH') || define('FCPATH', realpath(PUBLICPATH) . DIRECTORY_SEPARATOR); + defined('SUPPORTPATH') || define('SUPPORTPATH', realpath(TESTPATH . '_support/') . DIRECTORY_SEPARATOR); defined('COMPOSER_PATH') || define('COMPOSER_PATH', (string) realpath(HOMEPATH . 'vendor/autoload.php')); defined('VENDORPATH') || define('VENDORPATH', realpath(HOMEPATH . 'vendor') . DIRECTORY_SEPARATOR); -// Load Common.php from App then System -if (is_file(APPPATH . 'Common.php')) { - require_once APPPATH . 'Common.php'; -} - -require_once SYSTEMPATH . 'Common.php'; - -// Set environment values that would otherwise stop the framework from functioning during tests. -if (! isset($_SERVER['app.baseURL'])) { - $_SERVER['app.baseURL'] = 'http://example.com/'; -} - -// Load necessary components -require_once SYSTEMPATH . 'Config/AutoloadConfig.php'; -require_once APPPATH . 'Config/Autoload.php'; -require_once APPPATH . 'Config/Constants.php'; -require_once SYSTEMPATH . 'Modules/Modules.php'; -require_once APPPATH . 'Config/Modules.php'; - -require_once SYSTEMPATH . 'Autoloader/Autoloader.php'; -require_once SYSTEMPATH . 'Config/BaseService.php'; -require_once SYSTEMPATH . 'Config/Services.php'; -require_once APPPATH . 'Config/Services.php'; - -// Initialize and register the loader with the SPL autoloader stack. -Services::autoloader()->initialize(new Autoload(), new Modules())->register(); -Services::autoloader()->loadHelpers(); - -// Now load Composer's if it's available -if (is_file(COMPOSER_PATH)) { - require_once COMPOSER_PATH; -} +/* + *--------------------------------------------------------------- + * BOOTSTRAP THE APPLICATION + *--------------------------------------------------------------- + * This process sets up the path constants, loads and registers + * our autoloader, along with Composer's, loads our constants + * and fires up an environment-specific bootstrapping. + */ -// Load environment settings from .env files into $_SERVER and $_ENV -require_once SYSTEMPATH . 'Config/DotEnv.php'; +// LOAD THE FRAMEWORK BOOTSTRAP FILE +require $paths->systemDirectory . '/Boot.php'; +Boot::bootTest($paths); -$env = new DotEnv(ROOTPATH); -$env->load(); +/* + * --------------------------------------------------------------- + * LOAD ROUTES + * --------------------------------------------------------------- + */ Services::routes()->loadRoutes(); diff --git a/system/bootstrap.php b/system/bootstrap.php index e03fd570ca4c..f091aa306527 100644 --- a/system/bootstrap.php +++ b/system/bootstrap.php @@ -11,6 +11,14 @@ * the LICENSE file that was distributed with this source code. */ +/** + * --------------------------------------------------------------- + * + * @deprecated 4.5.0 This file is no longer used. Moved to Boot.php. + * --------------------------------------------------------------- + */ + +use CodeIgniter\Exceptions\FrameworkException; use Config\Autoload; use Config\Modules; use Config\Paths; @@ -26,11 +34,10 @@ * so they are available in the config files that are loaded. */ +/** @var Paths $paths */ + // The path to the application directory. if (! defined('APPPATH')) { - /** - * @var Paths $paths - */ define('APPPATH', realpath(rtrim($paths->appDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); } @@ -41,31 +48,22 @@ // The path to the system directory. if (! defined('SYSTEMPATH')) { - /** - * @var Paths $paths - */ define('SYSTEMPATH', realpath(rtrim($paths->systemDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); } // The path to the writable directory. if (! defined('WRITEPATH')) { - /** - * @var Paths $paths - */ define('WRITEPATH', realpath(rtrim($paths->writableDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); } // The path to the tests directory if (! defined('TESTPATH')) { - /** - * @var Paths $paths - */ define('TESTPATH', realpath(rtrim($paths->testsDirectory, '\\/ ')) . DIRECTORY_SEPARATOR); } /* * --------------------------------------------------------------- - * GRAB OUR CONSTANTS & COMMON + * GRAB OUR CONSTANTS * --------------------------------------------------------------- */ @@ -73,6 +71,12 @@ require_once APPPATH . 'Config/Constants.php'; } +/* + * --------------------------------------------------------------- + * LOAD COMMON FUNCTIONS + * --------------------------------------------------------------- + */ + // Require app/Common.php file if exists. if (is_file(APPPATH . 'Common.php')) { require_once APPPATH . 'Common.php'; @@ -106,3 +110,46 @@ // Initialize and register the loader with the SPL autoloader stack. Services::autoloader()->initialize(new Autoload(), new Modules())->register(); Services::autoloader()->loadHelpers(); + +/* + * --------------------------------------------------------------- + * SET EXCEPTION AND ERROR HANDLERS + * --------------------------------------------------------------- + */ + +Services::exceptions()->initialize(); + +/* + * --------------------------------------------------------------- + * CHECK SYSTEM FOR MISSING REQUIRED PHP EXTENSIONS + * --------------------------------------------------------------- + */ + +// Run this check for manual installations +if (! is_file(COMPOSER_PATH)) { + $missingExtensions = []; + + foreach ([ + 'intl', + 'json', + 'mbstring', + ] as $extension) { + if (! extension_loaded($extension)) { + $missingExtensions[] = $extension; + } + } + + if ($missingExtensions !== []) { + throw FrameworkException::forMissingExtension(implode(', ', $missingExtensions)); + } + + unset($missingExtensions); +} + +/* + * --------------------------------------------------------------- + * INITIALIZE KINT + * --------------------------------------------------------------- + */ + +Services::autoloader()->initializeKint(CI_DEBUG); diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index e583b8a67194..a31e73c749cf 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -26,7 +26,6 @@ use CodeIgniter\Session\Handlers\FileHandler; use CodeIgniter\Session\Session; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Mock\MockCodeIgniter; use CodeIgniter\Test\Mock\MockIncomingRequest; use CodeIgniter\Test\Mock\MockSecurity; use CodeIgniter\Test\Mock\MockSession; @@ -710,8 +709,7 @@ public function testDWithCSP(): void $config->CSPEnabled = true; // Initialize Kint - $app = new MockCodeIgniter($config); - $app->initialize(); + Services::autoloader()->initializeKint(CI_DEBUG); $cliDetection = Kint::$cli_detection; Kint::$cli_detection = false; @@ -736,8 +734,7 @@ public function testTraceWithCSP(): void $config->CSPEnabled = true; // Initialize Kint - $app = new MockCodeIgniter($config); - $app->initialize(); + Services::autoloader()->initializeKint(CI_DEBUG); Kint::$cli_detection = false; diff --git a/user_guide_src/source/changelogs/v4.5.0.rst b/user_guide_src/source/changelogs/v4.5.0.rst index 12c1b77e82fc..98666185389e 100644 --- a/user_guide_src/source/changelogs/v4.5.0.rst +++ b/user_guide_src/source/changelogs/v4.5.0.rst @@ -185,6 +185,8 @@ Others - **Web Page Caching:** ``ResponseCache`` has been improved to include the request HTTP method in the cache key. This means that the same URI will be cached separately if the HTTP method is different. +- **Bootstrap:** The ``CodeIgniter\Boot`` class has been introduced, replacing + **system/bootstrap.php**. ******** BREAKING @@ -445,8 +447,22 @@ Changes Deprecations ************ -- **CodeIgniter:** The ``determinePath()`` method has been deprecated. No longer - used. +- **CodeIgniter:** + - The ``determinePath()`` method has been deprecated. No longer used. + - The ``resolvePlatformExtensions()`` method has been deprecated. No longer + used. It has been moved to the ``CodeIgniter\Boot::checkMissingExtensions()`` + method. + - The ``bootstrapEnvironment()`` method has been deprecated. No longer used. + It has been moved to the ``CodeIgniter\Boot::loadEnvironmentBootstrap()`` + method. + - The ``initializeKint()`` method has been deprecated. No longer used. It has + been moved to the ``Autoloader``. + - The ``autoloadKint()`` method has been deprecated. No longer used. It has + been moved to the ``Autoloader``. + - The ``configureKint()`` method has been deprecated. No longer used. It has + been moved to the ``Autoloader``. +- **system/bootstrap.php:** This file has been deprecated. No longer used. + The code has been moved to the new ``CodeIgniter\Boot`` class. - **Response:** The constructor parameter ``$config`` has been deprecated. No longer used. - **Filters:** diff --git a/user_guide_src/source/concepts/autoloader.rst b/user_guide_src/source/concepts/autoloader.rst index 7328dd00c0aa..26ce27a673be 100644 --- a/user_guide_src/source/concepts/autoloader.rst +++ b/user_guide_src/source/concepts/autoloader.rst @@ -190,6 +190,10 @@ Or simply delete the **writable/cache/FileLocatorCache** file. How to Enable FileLocator Caching ================================= -Add the following code in **app/Config/Services.php**: +Set the following property to ``true`` in **app/Config/Optimize.php**:: -.. literalinclude:: autoloader/004.php + public bool $locatorCacheEnabled = true; + +.. note:: + This property cannot be overridden by + :ref:`environment variables `. diff --git a/user_guide_src/source/concepts/autoloader/004.php b/user_guide_src/source/concepts/autoloader/004.php deleted file mode 100644 index 090149e6486c..000000000000 --- a/user_guide_src/source/concepts/autoloader/004.php +++ /dev/null @@ -1,25 +0,0 @@ -load('config'); - +$factoriesCache = new \CodeIgniter\Cache\FactoriesCache(); - +$factoriesCache->load('config'); - // ^^^ Uncomment these lines if you want to use Config Caching. - - /* - @@ -79,7 +79,7 @@ $app->setContext($context); - $app->run(); - - // Save Config Cache - -// $factoriesCache->save('config'); - +$factoriesCache->save('config'); - // ^^^ Uncomment this line if you want to use Config Caching. - - // Exits the application, setting the exit code for CLI-based applications +.. versionadded:: 4.5.0 + +Set the following property to ``true`` in **app/Config/Optimize.php**:: + + public bool $configCacheEnabled = true; + +.. note:: + This property cannot be overridden by + :ref:`environment variables `. + +.. note:: + Prior to v4.5.0, uncomment the following code in **public/index.php**:: + + --- a/public/index.php + +++ b/public/index.php + @@ -49,8 +49,8 @@ if (! defined('ENVIRONMENT')) { + } + + // Load Config Cache + -// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache(); + -// $factoriesCache->load('config'); + +$factoriesCache = new \CodeIgniter\Cache\FactoriesCache(); + +$factoriesCache->load('config'); + // ^^^ Uncomment these lines if you want to use Config Caching. + + /* + @@ -79,7 +79,7 @@ $app->setContext($context); + $app->run(); + + // Save Config Cache + -// $factoriesCache->save('config'); + +$factoriesCache->save('config'); + // ^^^ Uncomment this line if you want to use Config Caching. + + // Exits the application, setting the exit code for CLI-based applications diff --git a/user_guide_src/source/installation/upgrade_450.rst b/user_guide_src/source/installation/upgrade_450.rst index 53498a20b301..27fe4bc67593 100644 --- a/user_guide_src/source/installation/upgrade_450.rst +++ b/user_guide_src/source/installation/upgrade_450.rst @@ -15,6 +15,26 @@ Please refer to the upgrade instructions corresponding to your installation meth Mandatory File Changes ********************** +index.php and spark +=================== + +The following files received significant changes and +**you must merge the updated versions** with your application: + +- ``public/index.php`` +- ``spark`` + +.. important:: If you don't update the above files, CodeIgniter will not work + properly after running ``composer update``. + + The upgrade procedure, for example, is as follows: + + .. code-block:: console + + composer update + cp vendor/codeigniter4/framework/public/index.php public/index.php + cp vendor/codeigniter4/framework/spark spark + Breaking Changes ****************