ricardogj08/semillero
feat: Inicialización del proyecto
Commit fb767cc · Ricardo García Jiménez · 2026-09-01T01:11:11-06:00
feat: Inicialización del proyecto Signed-off-by: Ricardo García Jiménez <[email protected]>
Comments
No comments yet.
Diff
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1786c28
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,129 @@
+#-------------------------
+# Operating Specific Junk Files
+#-------------------------
+
+# OS X
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# OS X Thumbnails
+._*
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+# Linux
+*~
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+#-------------------------
+# Environment Files
+#-------------------------
+# These should never be under version control,
+# as it poses a security risk.
+.env
+.vagrant
+Vagrantfile
+
+#-------------------------
+# Temporary Files
+#-------------------------
+/writable/cache/*
+!/writable/cache/index.html
+
+/writable/logs/*
+!/writable/logs/index.html
+
+/writable/session/*
+!/writable/session/index.html
+
+/writable/uploads/*
+!/writable/uploads/index.html
+
+/writable/debugbar/*
+!/writable/debugbar/index.html
+
+php_errors.log
+
+#-------------------------
+# User Guide Temp Files
+#-------------------------
+/user_guide_src/build/*
+/user_guide_src/cilexer/build/*
+/user_guide_src/cilexer/dist/*
+/user_guide_src/cilexer/pycilexer.egg-info/*
+
+#-------------------------
+# Test Files
+#-------------------------
+/tests/coverage*
+
+# Don't save phpunit under version control.
+/phpunit
+
+#-------------------------
+# Composer
+#-------------------------
+vendor/
+
+#-------------------------
+# IDE / Development Files
+#-------------------------
+
+# Modules Testing
+_modules/*
+
+# phpenv local config
+.php-version
+
+# Jetbrains editors (PHPStorm, etc)
+.idea/
+*.iml
+
+# NetBeans
+/nbproject/
+/build/
+/nbbuild/
+/dist/
+/nbdist/
+/nbactions.xml
+/nb-configuration.xml
+/.nb-gradle/
+
+# Sublime Text
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+*.sublime-workspace
+*.sublime-project
+.phpintel
+/api/
+
+# Visual Studio Code
+.vscode/
+
+/results/
+/phpunit.xml
+
+# CodeIgniter Coding Standard
+.php-cs-fixer.cache
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
new file mode 100644
index 0000000..5d245e4
--- /dev/null
+++ b/.php-cs-fixer.dist.php
@@ -0,0 +1,6 @@
+<?php
+
+use CodeIgniter\CodingStandard\CodeIgniter4;
+use Nexus\CsConfig\Factory;
+
+return Factory::create(new CodeIgniter4())->forProjects();
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..24728f6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2014-2019 British Columbia Institute of Technology
+Copyright (c) 2019-present CodeIgniter Foundation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..45f98af
--- /dev/null
+++ b/README.md
@@ -0,0 +1,69 @@
+# CodeIgniter 4 Application Starter
+
+## What is CodeIgniter?
+
+CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure.
+More information can be found at the [official site](https://codeigniter.com).
+
+This repository holds a composer-installable app starter.
+It has been built from the
+[development repository](https://github.com/codeigniter4/CodeIgniter4).
+
+More information about the plans for version 4 can be found in [CodeIgniter 4](https://forum.codeigniter.com/forumdisplay.php?fid=28) on the forums.
+
+You can read the [user guide](https://codeigniter.com/user_guide/)
+corresponding to the latest version of the framework.
+
+## Installation & updates
+
+`composer create-project codeigniter4/appstarter` then `composer update` whenever
+there is a new release of the framework.
+
+When updating, check the release notes to see if there are any changes you might need to apply
+to your `app` folder. The affected files can be copied or merged from
+`vendor/codeigniter4/framework/app`.
+
+## Setup
+
+Copy `env` to `.env` and tailor for your app, specifically the baseURL
+and any database settings.
+
+## Important Change with index.php
+
+`index.php` is no longer in the root of the project! It has been moved inside the *public* folder,
+for better security and separation of components.
+
+This means that you should configure your web server to "point" to your project's *public* folder, and
+not to the project root. A better practice would be to configure a virtual host to point there. A poor practice would be to point your web server to the project root and expect to enter *public/...*, as the rest of your logic and the
+framework are exposed.
+
+**Please** read the user guide for a better explanation of how CI4 works!
+
+## Repository Management
+
+We use GitHub issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages.
+We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss
+FEATURE REQUESTS.
+
+This repository is a "distribution" one, built by our release preparation script.
+Problems with it can be raised on our forum, or as issues in the main repository.
+
+## Server Requirements
+
+PHP version 8.2 or higher is required, with the following extensions installed:
+
+- [intl](http://php.net/manual/en/intl.requirements.php)
+- [mbstring](http://php.net/manual/en/mbstring.installation.php)
+
+> [!WARNING]
+> - The end of life date for PHP 7.4 was November 28, 2022.
+> - The end of life date for PHP 8.0 was November 26, 2023.
+> - The end of life date for PHP 8.1 was December 31, 2025.
+> - If you are still using below PHP 8.2, you should upgrade immediately.
+> - The end of life date for PHP 8.2 will be December 31, 2026.
+
+Additionally, make sure that the following extensions are enabled in your PHP:
+
+- json (enabled by default - don't turn it off)
+- [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) if you plan to use MySQL
+- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use the HTTP\CURLRequest library
diff --git a/app/.htaccess b/app/.htaccess
new file mode 100644
index 0000000..3462048
--- /dev/null
+++ b/app/.htaccess
@@ -0,0 +1,6 @@
+<IfModule authz_core_module>
+ Require all denied
+</IfModule>
+<IfModule !authz_core_module>
+ Deny from all
+</IfModule>
diff --git a/app/Common.php b/app/Common.php
new file mode 100644
index 0000000..95f5544
--- /dev/null
+++ b/app/Common.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * The goal of this file is to allow developers a location
+ * where they can overwrite core procedural functions and
+ * replace them with their own. This file is loaded during
+ * the bootstrap process and is called during the framework's
+ * execution.
+ *
+ * This can be looked at as a `master helper` file that is
+ * loaded early on, and may also contain additional functions
+ * that you'd like to use throughout your entire application
+ *
+ * @see: https://codeigniter.com/user_guide/extending/common.html
+ */
diff --git a/app/Config/App.php b/app/Config/App.php
new file mode 100644
index 0000000..b761da7
--- /dev/null
+++ b/app/Config/App.php
@@ -0,0 +1,202 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class App extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Base Site URL
+ * --------------------------------------------------------------------------
+ *
+ * URL to your CodeIgniter root. Typically, this will be your base URL,
+ * WITH a trailing slash:
+ *
+ * E.g., http://example.com/
+ */
+ public string $baseURL = 'http://localhost:8080/';
+
+ /**
+ * Allowed Hostnames in the Site URL other than the hostname in the baseURL.
+ * If you want to accept multiple Hostnames, set this.
+ *
+ * E.g.,
+ * When your site URL ($baseURL) is 'http://example.com/', and your site
+ * also accepts 'http://media.example.com/' and 'http://accounts.example.com/':
+ * ['media.example.com', 'accounts.example.com']
+ *
+ * @var list<string>
+ */
+ public array $allowedHostnames = [];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Index File
+ * --------------------------------------------------------------------------
+ *
+ * Typically, this will be your `index.php` file, unless you've renamed it to
+ * something else. If you have configured your web server to remove this file
+ * from your site URIs, set this variable to an empty string.
+ */
+ public string $indexPage = 'index.php';
+
+ /**
+ * --------------------------------------------------------------------------
+ * URI PROTOCOL
+ * --------------------------------------------------------------------------
+ *
+ * This item determines which server global should be used to retrieve the
+ * URI string. The default setting of 'REQUEST_URI' works for most servers.
+ * If your links do not seem to work, try one of the other delicious flavors:
+ *
+ * 'REQUEST_URI': Uses $_SERVER['REQUEST_URI']
+ * 'QUERY_STRING': Uses $_SERVER['QUERY_STRING']
+ * 'PATH_INFO': Uses $_SERVER['PATH_INFO']
+ *
+ * WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
+ */
+ public string $uriProtocol = 'REQUEST_URI';
+
+ /*
+ |--------------------------------------------------------------------------
+ | Allowed URL Characters
+ |--------------------------------------------------------------------------
+ |
+ | This lets you specify which characters are permitted within your URLs.
+ | When someone tries to submit a URL with disallowed characters they will
+ | get a warning message.
+ |
+ | As a security measure you are STRONGLY encouraged to restrict URLs to
+ | as few characters as possible.
+ |
+ | By default, only these are allowed: `a-z 0-9~%.:_-`
+ |
+ | Set an empty string to allow all characters -- but only if you are insane.
+ |
+ | The configured value is actually a regular expression character group
+ | and it will be used as: '/\A[<permittedURIChars>]+\z/iu'
+ |
+ | DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
+ |
+ */
+ public string $permittedURIChars = 'a-z 0-9~%.:_\-';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Default Locale
+ * --------------------------------------------------------------------------
+ *
+ * The Locale roughly represents the language and location that your visitor
+ * is viewing the site from. It affects the language strings and other
+ * strings (like currency markers, numbers, etc), that your program
+ * should run under for this request.
+ */
+ public string $defaultLocale = 'en';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Negotiate Locale
+ * --------------------------------------------------------------------------
+ *
+ * If true, the current Request object will automatically determine the
+ * language to use based on the value of the Accept-Language header.
+ *
+ * If false, no automatic detection will be performed.
+ */
+ public bool $negotiateLocale = false;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Supported Locales
+ * --------------------------------------------------------------------------
+ *
+ * If $negotiateLocale is true, this array lists the locales supported
+ * by the application in descending order of priority. If no match is
+ * found, the first locale will be used.
+ *
+ * IncomingRequest::setLocale() also uses this list.
+ *
+ * @var list<string>
+ */
+ public array $supportedLocales = ['en'];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Application Timezone
+ * --------------------------------------------------------------------------
+ *
+ * The default timezone that will be used in your application to display
+ * dates with the date helper, and can be retrieved through app_timezone()
+ *
+ * @see https://www.php.net/manual/en/timezones.php for list of timezones
+ * supported by PHP.
+ */
+ public string $appTimezone = 'UTC';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Default Character Set
+ * --------------------------------------------------------------------------
+ *
+ * This determines which character set is used by default in various methods
+ * that require a character set to be provided.
+ *
+ * @see http://php.net/htmlspecialchars for a list of supported charsets.
+ */
+ public string $charset = 'UTF-8';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Force Global Secure Requests
+ * --------------------------------------------------------------------------
+ *
+ * If true, this will force every request made to this application to be
+ * made via a secure connection (HTTPS). If the incoming request is not
+ * secure, the user will be redirected to a secure version of the page
+ * and the HTTP Strict Transport Security (HSTS) header will be set.
+ */
+ public bool $forceGlobalSecureRequests = false;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Reverse Proxy IPs
+ * --------------------------------------------------------------------------
+ *
+ * If your server is behind a reverse proxy, you must whitelist the proxy
+ * IP addresses from which CodeIgniter should trust headers such as
+ * X-Forwarded-For or Client-IP in order to properly identify
+ * the visitor's IP address.
+ *
+ * You need to set a proxy IP address or IP address with subnets and
+ * the HTTP header for the client IP address.
+ *
+ * Here are some examples:
+ * [
+ * '10.0.1.200' => 'X-Forwarded-For',
+ * '192.168.5.0/24' => 'X-Real-IP',
+ * ]
+ *
+ * @var array<string, string>
+ */
+ public array $proxyIPs = [];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Content Security Policy
+ * --------------------------------------------------------------------------
+ *
+ * Enables the Response's Content Secure Policy to restrict the sources that
+ * can be used for images, scripts, CSS files, audio, video, etc. If enabled,
+ * the Response object will populate default values for the policy from the
+ * `ContentSecurityPolicy.php` file. Controllers can always add to those
+ * restrictions at run time.
+ *
+ * For a better understanding of CSP, see these documents:
+ *
+ * @see http://www.html5rocks.com/en/tutorials/security/content-security-policy/
+ * @see http://www.w3.org/TR/CSP/
+ */
+ public bool $CSPEnabled = false;
+}
diff --git a/app/Config/Autoload.php b/app/Config/Autoload.php
new file mode 100644
index 0000000..9a92824
--- /dev/null
+++ b/app/Config/Autoload.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\AutoloadConfig;
+
+/**
+ * -------------------------------------------------------------------
+ * AUTOLOADER CONFIGURATION
+ * -------------------------------------------------------------------
+ *
+ * This file defines the namespaces and class maps so the Autoloader
+ * can find the files as needed.
+ *
+ * NOTE: If you use an identical key in $psr4 or $classmap, then
+ * the values in this file will overwrite the framework's values.
+ *
+ * NOTE: This class is required prior to Autoloader instantiation,
+ * and does not extend BaseConfig.
+ */
+class Autoload extends AutoloadConfig
+{
+ /**
+ * -------------------------------------------------------------------
+ * Namespaces
+ * -------------------------------------------------------------------
+ * This maps the locations of any namespaces in your application to
+ * their location on the file system. These are used by the autoloader
+ * to locate files the first time they have been instantiated.
+ *
+ * The 'Config' (APPPATH . 'Config') and 'CodeIgniter' (SYSTEMPATH) are
+ * already mapped for you.
+ *
+ * You may change the name of the 'App' namespace if you wish,
+ * but this should be done prior to creating any namespaced classes,
+ * else you will need to modify all of those classes for this to work.
+ *
+ * @var array<string, list<string>|string>
+ */
+ public $psr4 = [
+ APP_NAMESPACE => APPPATH,
+ ];
+
+ /**
+ * -------------------------------------------------------------------
+ * Class Map
+ * -------------------------------------------------------------------
+ * The class map provides a map of class names and their exact
+ * location on the drive. Classes loaded in this manner will have
+ * slightly faster performance because they will not have to be
+ * searched for within one or more directories as they would if they
+ * were being autoloaded through a namespace.
+ *
+ * Prototype:
+ * $classmap = [
+ * 'MyClass' => '/path/to/class/file.php'
+ * ];
+ *
+ * @var array<string, string>
+ */
+ public $classmap = [];
+
+ /**
+ * -------------------------------------------------------------------
+ * Files
+ * -------------------------------------------------------------------
+ * The files array provides a list of paths to __non-class__ files
+ * that will be autoloaded. This can be useful for bootstrap operations
+ * or for loading functions.
+ *
+ * Prototype:
+ * $files = [
+ * '/path/to/my/file.php',
+ * ];
+ *
+ * @var list<string>
+ */
+ public $files = [];
+
+ /**
+ * -------------------------------------------------------------------
+ * Helpers
+ * -------------------------------------------------------------------
+ * Prototype:
+ * $helpers = [
+ * 'form',
+ * ];
+ *
+ * @var list<string>
+ */
+ public $helpers = [];
+}
diff --git a/app/Config/Boot/development.php b/app/Config/Boot/development.php
new file mode 100644
index 0000000..a868447
--- /dev/null
+++ b/app/Config/Boot/development.php
@@ -0,0 +1,34 @@
+<?php
+
+/*
+ |--------------------------------------------------------------------------
+ | ERROR DISPLAY
+ |--------------------------------------------------------------------------
+ | In development, we want to show as many errors as possible to help
+ | make sure they don't make it to production. And save us hours of
+ | painful debugging.
+ |
+ | If you set 'display_errors' to '1', CI4's detailed error report will show.
+ */
+error_reporting(E_ALL);
+ini_set('display_errors', '1');
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG BACKTRACES
+ |--------------------------------------------------------------------------
+ | If true, this constant will tell the error screens to display debug
+ | backtraces along with the other error information. If you would
+ | prefer to not see this, set this value to false.
+ */
+defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG MODE
+ |--------------------------------------------------------------------------
+ | Debug mode is an experimental flag that can allow changes throughout
+ | the system. This will control whether Kint is loaded, and a few other
+ | items. It can always be used within your own application too.
+ */
+defined('CI_DEBUG') || define('CI_DEBUG', true);
diff --git a/app/Config/Boot/production.php b/app/Config/Boot/production.php
new file mode 100644
index 0000000..1822cf5
--- /dev/null
+++ b/app/Config/Boot/production.php
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ |--------------------------------------------------------------------------
+ | ERROR DISPLAY
+ |--------------------------------------------------------------------------
+ | Don't show ANY in production environments. Instead, let the system catch
+ | it and display a generic error message.
+ |
+ | If you set 'display_errors' to '1', CI4's detailed error report will show.
+ */
+error_reporting(E_ALL & ~E_DEPRECATED);
+// If you want to suppress more types of errors.
+// error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED);
+ini_set('display_errors', '0');
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG MODE
+ |--------------------------------------------------------------------------
+ | Debug mode is an experimental flag that can allow changes throughout
+ | the system. It's not widely used currently, and may not survive
+ | release of the framework.
+ */
+defined('CI_DEBUG') || define('CI_DEBUG', false);
diff --git a/app/Config/Boot/testing.php b/app/Config/Boot/testing.php
new file mode 100644
index 0000000..40b6ca8
--- /dev/null
+++ b/app/Config/Boot/testing.php
@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * The environment testing is reserved for PHPUnit testing. It has special
+ * conditions built into the framework at various places to assist with that.
+ * You can’t use it for your development.
+ */
+
+/*
+ |--------------------------------------------------------------------------
+ | ERROR DISPLAY
+ |--------------------------------------------------------------------------
+ | In development, we want to show as many errors as possible to help
+ | make sure they don't make it to production. And save us hours of
+ | painful debugging.
+ */
+error_reporting(E_ALL);
+ini_set('display_errors', '1');
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG BACKTRACES
+ |--------------------------------------------------------------------------
+ | If true, this constant will tell the error screens to display debug
+ | backtraces along with the other error information. If you would
+ | prefer to not see this, set this value to false.
+ */
+defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
+
+/*
+ |--------------------------------------------------------------------------
+ | DEBUG MODE
+ |--------------------------------------------------------------------------
+ | Debug mode is an experimental flag that can allow changes throughout
+ | the system. It's not widely used currently, and may not survive
+ | release of the framework.
+ */
+defined('CI_DEBUG') || define('CI_DEBUG', true);
diff --git a/app/Config/CURLRequest.php b/app/Config/CURLRequest.php
new file mode 100644
index 0000000..bc5947f
--- /dev/null
+++ b/app/Config/CURLRequest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class CURLRequest extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * CURLRequest Share Connection Options
+ * --------------------------------------------------------------------------
+ *
+ * Share connection options between requests.
+ *
+ * @var list<int>
+ *
+ * @see https://www.php.net/manual/en/curl.constants.php#constant.curl-lock-data-connect
+ */
+ public array $shareConnectionOptions = [
+ CURL_LOCK_DATA_CONNECT,
+ CURL_LOCK_DATA_DNS,
+ ];
+
+ /**
+ * --------------------------------------------------------------------------
+ * CURLRequest Share Options
+ * --------------------------------------------------------------------------
+ *
+ * Whether share options between requests or not.
+ *
+ * If true, all the options won't be reset between requests.
+ * It may cause an error request with unnecessary headers.
+ */
+ public bool $shareOptions = false;
+}
diff --git a/app/Config/Cache.php b/app/Config/Cache.php
new file mode 100644
index 0000000..38ac541
--- /dev/null
+++ b/app/Config/Cache.php
@@ -0,0 +1,198 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Cache\CacheInterface;
+use CodeIgniter\Cache\Handlers\ApcuHandler;
+use CodeIgniter\Cache\Handlers\DummyHandler;
+use CodeIgniter\Cache\Handlers\FileHandler;
+use CodeIgniter\Cache\Handlers\MemcachedHandler;
+use CodeIgniter\Cache\Handlers\PredisHandler;
+use CodeIgniter\Cache\Handlers\RedisHandler;
+use CodeIgniter\Cache\Handlers\WincacheHandler;
+use CodeIgniter\Config\BaseConfig;
+
+class Cache extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Primary Handler
+ * --------------------------------------------------------------------------
+ *
+ * The name of the preferred handler that should be used. If for some reason
+ * it is not available, the $backupHandler will be used in its place.
+ */
+ public string $handler = 'file';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Backup Handler
+ * --------------------------------------------------------------------------
+ *
+ * The name of the handler that will be used in case the first one is
+ * unreachable. Often, 'file' is used here since the filesystem is
+ * always available, though that's not always practical for the app.
+ */
+ public string $backupHandler = 'dummy';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Key Prefix
+ * --------------------------------------------------------------------------
+ *
+ * This string is added to all cache item names to help avoid collisions
+ * if you run multiple applications with the same cache engine.
+ */
+ public string $prefix = '';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Default TTL
+ * --------------------------------------------------------------------------
+ *
+ * The default number of seconds to save items when none is specified.
+ *
+ * WARNING: This is not used by framework handlers where 60 seconds is
+ * hard-coded, but may be useful to projects and modules. This will replace
+ * the hard-coded value in a future release.
+ */
+ public int $ttl = 60;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Reserved Characters
+ * --------------------------------------------------------------------------
+ *
+ * A string of reserved characters that will not be allowed in keys or tags.
+ * Strings that violate this restriction will cause handlers to throw.
+ * Default: {}()/\@:
+ *
+ * NOTE: The default set is required for PSR-6 compliance.
+ */
+ public string $reservedCharacters = '{}()/\@:';
+
+ /**
+ * --------------------------------------------------------------------------
+ * File settings
+ * --------------------------------------------------------------------------
+ *
+ * Your file storage preferences can be specified below, if you are using
+ * the File driver.
+ *
+ * @var array{storePath?: string, mode?: int}
+ */
+ public array $file = [
+ 'storePath' => WRITEPATH . 'cache/',
+ 'mode' => 0640,
+ ];
+
+ /**
+ * -------------------------------------------------------------------------
+ * Memcached settings
+ * -------------------------------------------------------------------------
+ *
+ * Your Memcached servers can be specified below, if you are using
+ * the Memcached drivers.
+ *
+ * @see https://codeigniter.com/user_guide/libraries/caching.html#memcached
+ *
+ * @var array{host?: string, port?: int, weight?: int, raw?: bool}
+ */
+ public array $memcached = [
+ 'host' => '127.0.0.1',
+ 'port' => 11211,
+ 'weight' => 1,
+ 'raw' => false,
+ ];
+
+ /**
+ * -------------------------------------------------------------------------
+ * Redis settings
+ * -------------------------------------------------------------------------
+ *
+ * Your Redis server can be specified below, if you are using
+ * the Redis or Predis drivers.
+ *
+ * @var array{
+ * host?: string,
+ * password?: string|null,
+ * port?: int,
+ * timeout?: int,
+ * async?: bool,
+ * persistent?: bool,
+ * database?: int
+ * }
+ */
+ public array $redis = [
+ 'host' => '127.0.0.1',
+ 'password' => null,
+ 'port' => 6379,
+ 'timeout' => 0,
+ 'async' => false, // specific to Predis and ignored by the native Redis extension
+ 'persistent' => false,
+ 'database' => 0,
+ ];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Available Cache Handlers
+ * --------------------------------------------------------------------------
+ *
+ * This is an array of cache engine alias' and class names. Only engines
+ * that are listed here are allowed to be used.
+ *
+ * @var array<string, class-string<CacheInterface>>
+ */
+ public array $validHandlers = [
+ 'apcu' => ApcuHandler::class,
+ 'dummy' => DummyHandler::class,
+ 'file' => FileHandler::class,
+ 'memcached' => MemcachedHandler::class,
+ 'predis' => PredisHandler::class,
+ '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<string>
+ */
+ public $cacheQueryString = false;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Web Page Caching: Cache Status Codes
+ * --------------------------------------------------------------------------
+ *
+ * HTTP status codes that are allowed to be cached. Only responses with
+ * these status codes will be cached by the PageCache filter.
+ *
+ * Default: [] - Cache all status codes (backward compatible)
+ *
+ * Recommended: [200] - Only cache successful responses
+ *
+ * You can also use status codes like:
+ * [200, 404, 410] - Cache successful responses and specific error codes
+ * [200, 201, 202, 203, 204] - All 2xx successful responses
+ *
+ * WARNING: Using [] may cache temporary error pages (404, 500, etc).
+ * Consider restricting to [200] for production applications to avoid
+ * caching errors that should be temporary.
+ *
+ * @var list<int>
+ */
+ public array $cacheStatusCodes = [];
+}
diff --git a/app/Config/Constants.php b/app/Config/Constants.php
new file mode 100644
index 0000000..fb56bb1
--- /dev/null
+++ b/app/Config/Constants.php
@@ -0,0 +1,79 @@
+<?php
+
+/*
+ | --------------------------------------------------------------------
+ | App Namespace
+ | --------------------------------------------------------------------
+ |
+ | This defines the default Namespace that is used throughout
+ | CodeIgniter to refer to the Application directory. Change
+ | this constant to change the namespace that all application
+ | classes should use.
+ |
+ | NOTE: changing this will require manually modifying the
+ | existing namespaces of App\* namespaced-classes.
+ */
+defined('APP_NAMESPACE') || define('APP_NAMESPACE', 'App');
+
+/*
+ | --------------------------------------------------------------------------
+ | Composer Path
+ | --------------------------------------------------------------------------
+ |
+ | The path that Composer's autoload file is expected to live. By default,
+ | the vendor folder is in the Root directory, but you can customize that here.
+ */
+defined('COMPOSER_PATH') || define('COMPOSER_PATH', ROOTPATH . 'vendor/autoload.php');
+
+/*
+ |--------------------------------------------------------------------------
+ | Timing Constants
+ |--------------------------------------------------------------------------
+ |
+ | Provide simple ways to work with the myriad of PHP functions that
+ | require information to be in seconds.
+ */
+defined('SECOND') || define('SECOND', 1);
+defined('MINUTE') || define('MINUTE', 60);
+defined('HOUR') || define('HOUR', 3600);
+defined('DAY') || define('DAY', 86400);
+defined('WEEK') || define('WEEK', 604800);
+defined('MONTH') || define('MONTH', 2_592_000);
+defined('YEAR') || define('YEAR', 31_536_000);
+defined('DECADE') || define('DECADE', 315_360_000);
+
+/*
+ | --------------------------------------------------------------------------
+ | Exit Status Codes
+ | --------------------------------------------------------------------------
+ |
+ | Used to indicate the conditions under which the script is exit()ing.
+ | While there is no universal standard for error codes, there are some
+ | broad conventions. Three such conventions are mentioned below, for
+ | those who wish to make use of them. The CodeIgniter defaults were
+ | chosen for the least overlap with these conventions, while still
+ | leaving room for others to be defined in future versions and user
+ | applications.
+ |
+ | The three main conventions used for determining exit status codes
+ | are as follows:
+ |
+ | Standard C/C++ Library (stdlibc):
+ | http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
+ | (This link also contains other GNU-specific conventions)
+ | BSD sysexits.h:
+ | http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits
+ | Bash scripting:
+ | http://tldp.org/LDP/abs/html/exitcodes.html
+ |
+ */
+defined('EXIT_SUCCESS') || define('EXIT_SUCCESS', 0); // no errors
+defined('EXIT_ERROR') || define('EXIT_ERROR', 1); // generic error
+defined('EXIT_CONFIG') || define('EXIT_CONFIG', 3); // configuration error
+defined('EXIT_UNKNOWN_FILE') || define('EXIT_UNKNOWN_FILE', 4); // file not found
+defined('EXIT_UNKNOWN_CLASS') || define('EXIT_UNKNOWN_CLASS', 5); // unknown class
+defined('EXIT_UNKNOWN_METHOD') || define('EXIT_UNKNOWN_METHOD', 6); // unknown class member
+defined('EXIT_USER_INPUT') || define('EXIT_USER_INPUT', 7); // invalid user input
+defined('EXIT_DATABASE') || define('EXIT_DATABASE', 8); // database error
+defined('EXIT__AUTO_MIN') || define('EXIT__AUTO_MIN', 9); // lowest automatically-assigned error code
+defined('EXIT__AUTO_MAX') || define('EXIT__AUTO_MAX', 125); // highest automatically-assigned error code
diff --git a/app/Config/ContentSecurityPolicy.php b/app/Config/ContentSecurityPolicy.php
new file mode 100644
index 0000000..f64a9af
--- /dev/null
+++ b/app/Config/ContentSecurityPolicy.php
@@ -0,0 +1,216 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Stores the default settings for the ContentSecurityPolicy, if you
+ * choose to use it. The values here will be read in and set as defaults
+ * for the site. If needed, they can be overridden on a page-by-page basis.
+ *
+ * Suggested reference for explanations:
+ *
+ * @see https://www.html5rocks.com/en/tutorials/security/content-security-policy/
+ */
+class ContentSecurityPolicy extends BaseConfig
+{
+ // -------------------------------------------------------------------------
+ // Broadbrush CSP management
+ // -------------------------------------------------------------------------
+
+ /**
+ * Default CSP report context
+ */
+ public bool $reportOnly = false;
+
+ /**
+ * Specifies a URL where a browser will send reports
+ * when a content security policy is violated.
+ */
+ public ?string $reportURI = null;
+
+ /**
+ * Specifies a reporting endpoint to which violation reports ought to be sent.
+ */
+ public ?string $reportTo = null;
+
+ /**
+ * Instructs user agents to rewrite URL schemes, changing
+ * HTTP to HTTPS. This directive is for websites with
+ * large numbers of old URLs that need to be rewritten.
+ */
+ public bool $upgradeInsecureRequests = false;
+
+ // -------------------------------------------------------------------------
+ // CSP DIRECTIVES SETTINGS
+ // NOTE: once you set a policy to 'none', it cannot be further restricted
+ // -------------------------------------------------------------------------
+
+ /**
+ * Will default to `'self'` if not overridden
+ *
+ * @var list<string>|string|null
+ */
+ public $defaultSrc;
+
+ /**
+ * Lists allowed scripts' URLs.
+ *
+ * @var list<string>|string
+ */
+ public $scriptSrc = 'self';
+
+ /**
+ * Specifies valid sources for JavaScript <script> elements.
+ *
+ * @var list<string>|string
+ */
+ public array|string $scriptSrcElem = 'self';
+
+ /**
+ * Specifies valid sources for JavaScript inline event
+ * handlers and JavaScript URLs.
+ *
+ * @var list<string>|string
+ */
+ public array|string $scriptSrcAttr = 'self';
+
+ /**
+ * Lists allowed stylesheets' URLs.
+ *
+ * @var list<string>|string
+ */
+ public $styleSrc = 'self';
+
+ /**
+ * Specifies valid sources for stylesheets <link> elements.
+ *
+ * @var list<string>|string
+ */
+ public array|string $styleSrcElem = 'self';
+
+ /**
+ * Specifies valid sources for stylesheets inline
+ * style attributes and `<style>` elements.
+ *
+ * @var list<string>|string
+ */
+ public array|string $styleSrcAttr = 'self';
+
+ /**
+ * Defines the origins from which images can be loaded.
+ *
+ * @var list<string>|string
+ */
+ public $imageSrc = 'self';
+
+ /**
+ * Restricts the URLs that can appear in a page's `<base>` element.
+ *
+ * Will default to self if not overridden
+ *
+ * @var list<string>|string|null
+ */
+ public $baseURI;
+
+ /**
+ * Lists the URLs for workers and embedded frame contents
+ *
+ * @var list<string>|string
+ */
+ public $childSrc = 'self';
+
+ /**
+ * Limits the origins that you can connect to (via XHR,
+ * WebSockets, and EventSource).
+ *
+ * @var list<string>|string
+ */
+ public $connectSrc = 'self';
+
+ /**
+ * Specifies the origins that can serve web fonts.
+ *
+ * @var list<string>|string
+ */
+ public $fontSrc;
+
+ /**
+ * Lists valid endpoints for submission from `<form>` tags.
+ *
+ * @var list<string>|string
+ */
+ public $formAction = 'self';
+
+ /**
+ * Specifies the sources that can embed the current page.
+ * This directive applies to `<frame>`, `<iframe>`, `<embed>`,
+ * and `<applet>` tags. This directive can't be used in
+ * `<meta>` tags and applies only to non-HTML resources.
+ *
+ * @var list<string>|string|null
+ */
+ public $frameAncestors;
+
+ /**
+ * The frame-src directive restricts the URLs which may
+ * be loaded into nested browsing contexts.
+ *
+ * @var list<string>|string|null
+ */
+ public $frameSrc;
+
+ /**
+ * Restricts the origins allowed to deliver video and audio.
+ *
+ * @var list<string>|string|null
+ */
+ public $mediaSrc;
+
+ /**
+ * Allows control over Flash and other plugins.
+ *
+ * @var list<string>|string
+ */
+ public $objectSrc = 'self';
+
+ /**
+ * @var list<string>|string|null
+ */
+ public $manifestSrc;
+
+ /**
+ * @var list<string>|string
+ */
+ public array|string $workerSrc = [];
+
+ /**
+ * Limits the kinds of plugins a page may invoke.
+ *
+ * @var list<string>|string|null
+ */
+ public $pluginTypes;
+
+ /**
+ * List of actions allowed.
+ *
+ * @var list<string>|string|null
+ */
+ public $sandbox;
+
+ /**
+ * Nonce placeholder for style tags.
+ */
+ public string $styleNonceTag = '{csp-style-nonce}';
+
+ /**
+ * Nonce placeholder for script tags.
+ */
+ public string $scriptNonceTag = '{csp-script-nonce}';
+
+ /**
+ * Replace nonce tag automatically?
+ */
+ public bool $autoNonce = true;
+}
diff --git a/app/Config/Cookie.php b/app/Config/Cookie.php
new file mode 100644
index 0000000..3bad184
--- /dev/null
+++ b/app/Config/Cookie.php
@@ -0,0 +1,107 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use DateTimeInterface;
+
+class Cookie extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Cookie Prefix
+ * --------------------------------------------------------------------------
+ *
+ * Set a cookie name prefix if you need to avoid collisions.
+ */
+ public string $prefix = '';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Cookie Expires Timestamp
+ * --------------------------------------------------------------------------
+ *
+ * Default expires timestamp for cookies. Setting this to `0` will mean the
+ * cookie will not have the `Expires` attribute and will behave as a session
+ * cookie.
+ *
+ * @var DateTimeInterface|int|string
+ */
+ public $expires = 0;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Cookie Path
+ * --------------------------------------------------------------------------
+ *
+ * Typically will be a forward slash.
+ */
+ public string $path = '/';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Cookie Domain
+ * --------------------------------------------------------------------------
+ *
+ * Set to `.your-domain.com` for site-wide cookies.
+ */
+ public string $domain = '';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Cookie Secure
+ * --------------------------------------------------------------------------
+ *
+ * Cookie will only be set if a secure HTTPS connection exists.
+ */
+ public bool $secure = false;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Cookie HTTPOnly
+ * --------------------------------------------------------------------------
+ *
+ * Cookie will only be accessible via HTTP(S) (no JavaScript).
+ */
+ public bool $httponly = true;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Cookie SameSite
+ * --------------------------------------------------------------------------
+ *
+ * Configure cookie SameSite setting. Allowed values are:
+ * - None
+ * - Lax
+ * - Strict
+ * - ''
+ *
+ * Alternatively, you can use the constant names:
+ * - `Cookie::SAMESITE_NONE`
+ * - `Cookie::SAMESITE_LAX`
+ * - `Cookie::SAMESITE_STRICT`
+ *
+ * Defaults to `Lax` for compatibility with modern browsers. Setting `''`
+ * (empty string) means default SameSite attribute set by browsers (`Lax`)
+ * will be set on cookies. If set to `None`, `$secure` must also be set.
+ *
+ * @var ''|'Lax'|'None'|'Strict'
+ */
+ public string $samesite = 'Lax';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Cookie Raw
+ * --------------------------------------------------------------------------
+ *
+ * This flag allows setting a "raw" cookie, i.e., its name and value are
+ * not URL encoded using `rawurlencode()`.
+ *
+ * If this is set to `true`, cookie names should be compliant of RFC 2616's
+ * list of allowed characters.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes
+ * @see https://tools.ietf.org/html/rfc2616#section-2.2
+ */
+ public bool $raw = false;
+}
diff --git a/app/Config/Cors.php b/app/Config/Cors.php
new file mode 100644
index 0000000..2b4edf6
--- /dev/null
+++ b/app/Config/Cors.php
@@ -0,0 +1,105 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Cross-Origin Resource Sharing (CORS) Configuration
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
+ */
+class Cors extends BaseConfig
+{
+ /**
+ * The default CORS configuration.
+ *
+ * @var array{
+ * allowedOrigins: list<string>,
+ * allowedOriginsPatterns: list<string>,
+ * supportsCredentials: bool,
+ * allowedHeaders: list<string>,
+ * exposedHeaders: list<string>,
+ * allowedMethods: list<string>,
+ * maxAge: int,
+ * }
+ */
+ public array $default = [
+ /**
+ * Origins for the `Access-Control-Allow-Origin` header.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
+ *
+ * E.g.:
+ * - ['http://localhost:8080']
+ * - ['https://www.example.com']
+ */
+ 'allowedOrigins' => [],
+
+ /**
+ * Origin regex patterns for the `Access-Control-Allow-Origin` header.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
+ *
+ * NOTE: A pattern specified here is part of a regular expression. It will
+ * be actually `#\A<pattern>\z#`.
+ *
+ * E.g.:
+ * - ['https://\w+\.example\.com']
+ */
+ 'allowedOriginsPatterns' => [],
+
+ /**
+ * Weather to send the `Access-Control-Allow-Credentials` header.
+ *
+ * The Access-Control-Allow-Credentials response header tells browsers whether
+ * the server allows cross-origin HTTP requests to include credentials.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
+ */
+ 'supportsCredentials' => false,
+
+ /**
+ * Set headers to allow.
+ *
+ * The Access-Control-Allow-Headers response header is used in response to
+ * a preflight request which includes the Access-Control-Request-Headers to
+ * indicate which HTTP headers can be used during the actual request.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
+ */
+ 'allowedHeaders' => [],
+
+ /**
+ * Set headers to expose.
+ *
+ * The Access-Control-Expose-Headers response header allows a server to
+ * indicate which response headers should be made available to scripts running
+ * in the browser, in response to a cross-origin request.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
+ */
+ 'exposedHeaders' => [],
+
+ /**
+ * Set methods to allow.
+ *
+ * The Access-Control-Allow-Methods response header specifies one or more
+ * methods allowed when accessing a resource in response to a preflight
+ * request.
+ *
+ * E.g.:
+ * - ['GET', 'POST', 'PUT', 'DELETE']
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
+ */
+ 'allowedMethods' => [],
+
+ /**
+ * Set how many seconds the results of a preflight request can be cached.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
+ */
+ 'maxAge' => 7200,
+ ];
+}
diff --git a/app/Config/Database.php b/app/Config/Database.php
new file mode 100644
index 0000000..060781e
--- /dev/null
+++ b/app/Config/Database.php
@@ -0,0 +1,204 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Database\Config;
+
+/**
+ * Database Configuration
+ */
+class Database extends Config
+{
+ /**
+ * The directory that holds the Migrations and Seeds directories.
+ */
+ public string $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR;
+
+ /**
+ * Lets you choose which connection group to use if no other is specified.
+ */
+ public string $defaultGroup = 'default';
+
+ /**
+ * The default database connection.
+ *
+ * @var array<string, mixed>
+ */
+ public array $default = [
+ 'DSN' => '',
+ 'hostname' => 'localhost',
+ 'username' => '',
+ 'password' => '',
+ 'database' => '',
+ 'DBDriver' => 'MySQLi',
+ 'DBPrefix' => '',
+ 'pConnect' => false,
+ 'DBDebug' => true,
+ 'charset' => 'utf8mb4',
+ 'DBCollat' => 'utf8mb4_general_ci',
+ 'swapPre' => '',
+ 'encrypt' => false,
+ 'compress' => false,
+ 'strictOn' => false,
+ 'failover' => [],
+ 'port' => 3306,
+ 'numberNative' => false,
+ 'foundRows' => false,
+ 'dateFormat' => [
+ 'date' => 'Y-m-d',
+ 'datetime' => 'Y-m-d H:i:s',
+ 'time' => 'H:i:s',
+ ],
+ ];
+
+ // /**
+ // * Sample database connection for SQLite3.
+ // *
+ // * @var array<string, mixed>
+ // */
+ // public array $default = [
+ // 'database' => 'database.db',
+ // 'DBDriver' => 'SQLite3',
+ // 'DBPrefix' => '',
+ // 'DBDebug' => true,
+ // 'swapPre' => '',
+ // 'failover' => [],
+ // 'foreignKeys' => true,
+ // 'busyTimeout' => 1000,
+ // 'synchronous' => null,
+ // 'dateFormat' => [
+ // 'date' => 'Y-m-d',
+ // 'datetime' => 'Y-m-d H:i:s',
+ // 'time' => 'H:i:s',
+ // ],
+ // ];
+
+ // /**
+ // * Sample database connection for Postgre.
+ // *
+ // * @var array<string, mixed>
+ // */
+ // public array $default = [
+ // 'DSN' => '',
+ // 'hostname' => 'localhost',
+ // 'username' => 'root',
+ // 'password' => 'root',
+ // 'database' => 'ci4',
+ // 'schema' => 'public',
+ // 'DBDriver' => 'Postgre',
+ // 'DBPrefix' => '',
+ // 'pConnect' => false,
+ // 'DBDebug' => true,
+ // 'charset' => 'utf8',
+ // 'swapPre' => '',
+ // 'failover' => [],
+ // 'port' => 5432,
+ // 'dateFormat' => [
+ // 'date' => 'Y-m-d',
+ // 'datetime' => 'Y-m-d H:i:s',
+ // 'time' => 'H:i:s',
+ // ],
+ // ];
+
+ // /**
+ // * Sample database connection for SQLSRV.
+ // *
+ // * @var array<string, mixed>
+ // */
+ // public array $default = [
+ // 'DSN' => '',
+ // 'hostname' => 'localhost',
+ // 'username' => 'root',
+ // 'password' => 'root',
+ // 'database' => 'ci4',
+ // 'schema' => 'dbo',
+ // 'DBDriver' => 'SQLSRV',
+ // 'DBPrefix' => '',
+ // 'pConnect' => false,
+ // 'DBDebug' => true,
+ // 'charset' => 'utf8',
+ // 'swapPre' => '',
+ // 'encrypt' => false,
+ // 'failover' => [],
+ // 'port' => 1433,
+ // 'dateFormat' => [
+ // 'date' => 'Y-m-d',
+ // 'datetime' => 'Y-m-d H:i:s',
+ // 'time' => 'H:i:s',
+ // ],
+ // ];
+
+ // /**
+ // * Sample database connection for OCI8.
+ // *
+ // * You may need the following environment variables:
+ // * NLS_LANG = 'AMERICAN_AMERICA.UTF8'
+ // * NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'
+ // * NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS'
+ // * NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS'
+ // *
+ // * @var array<string, mixed>
+ // */
+ // public array $default = [
+ // 'DSN' => 'localhost:1521/FREEPDB1',
+ // 'username' => 'root',
+ // 'password' => 'root',
+ // 'DBDriver' => 'OCI8',
+ // 'DBPrefix' => '',
+ // 'pConnect' => false,
+ // 'DBDebug' => true,
+ // 'charset' => 'AL32UTF8',
+ // 'swapPre' => '',
+ // 'failover' => [],
+ // 'dateFormat' => [
+ // 'date' => 'Y-m-d',
+ // 'datetime' => 'Y-m-d H:i:s',
+ // 'time' => 'H:i:s',
+ // ],
+ // ];
+
+ /**
+ * This database connection is used when running PHPUnit database tests.
+ *
+ * @var array<string, mixed>
+ */
+ public array $tests = [
+ 'DSN' => '',
+ 'hostname' => '127.0.0.1',
+ 'username' => '',
+ 'password' => '',
+ 'database' => ':memory:',
+ 'DBDriver' => 'SQLite3',
+ 'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS
+ 'pConnect' => false,
+ 'DBDebug' => true,
+ 'charset' => 'utf8',
+ 'DBCollat' => '',
+ 'swapPre' => '',
+ 'encrypt' => false,
+ 'compress' => false,
+ 'strictOn' => true,
+ 'failover' => [],
+ 'port' => 3306,
+ 'foreignKeys' => true,
+ 'busyTimeout' => 1000,
+ 'synchronous' => null,
+ 'dateFormat' => [
+ 'date' => 'Y-m-d',
+ 'datetime' => 'Y-m-d H:i:s',
+ 'time' => 'H:i:s',
+ ],
+ ];
+
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Ensure that we always set the database group to 'tests' if
+ // we are currently running an automated test suite, so that
+ // we don't overwrite live data on accident.
+ if (ENVIRONMENT === 'testing') {
+ $this->defaultGroup = 'tests';
+ }
+ }
+}
diff --git a/app/Config/DocTypes.php b/app/Config/DocTypes.php
new file mode 100644
index 0000000..788d68f
--- /dev/null
+++ b/app/Config/DocTypes.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Config;
+
+class DocTypes
+{
+ /**
+ * List of valid document types.
+ *
+ * @var array<string, string>
+ */
+ public array $list = [
+ 'xhtml11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
+ 'xhtml1-strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
+ 'xhtml1-trans' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
+ 'xhtml1-frame' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
+ 'xhtml-basic11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
+ 'html5' => '<!DOCTYPE html>',
+ 'html4-strict' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
+ 'html4-trans' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
+ 'html4-frame' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
+ 'mathml1' => '<!DOCTYPE math SYSTEM "http://www.w3.org/Math/DTD/mathml1/mathml.dtd">',
+ 'mathml2' => '<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">',
+ 'svg10' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">',
+ 'svg11' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">',
+ 'svg11-basic' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd">',
+ 'svg11-tiny' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">',
+ 'xhtml-math-svg-xh' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">',
+ 'xhtml-math-svg-sh' => '<!DOCTYPE svg:svg PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">',
+ 'xhtml-rdfa-1' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">',
+ 'xhtml-rdfa-2' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.1//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd">',
+ ];
+
+ /**
+ * Whether to remove the solidus (`/`) character for void HTML elements (e.g. `<input>`)
+ * for HTML5 compatibility.
+ *
+ * Set to:
+ * `true` - to be HTML5 compatible
+ * `false` - to be XHTML compatible
+ */
+ public bool $html5 = true;
+}
diff --git a/app/Config/Email.php b/app/Config/Email.php
new file mode 100644
index 0000000..77c573a
--- /dev/null
+++ b/app/Config/Email.php
@@ -0,0 +1,126 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Email extends BaseConfig
+{
+ public string $fromEmail = '';
+ public string $fromName = '';
+ public string $recipients = '';
+
+ /**
+ * The "user agent"
+ */
+ public string $userAgent = 'CodeIgniter';
+
+ /**
+ * The mail sending protocol: mail, sendmail, smtp
+ */
+ public string $protocol = 'mail';
+
+ /**
+ * The server path to Sendmail.
+ */
+ public string $mailPath = '/usr/sbin/sendmail';
+
+ /**
+ * SMTP Server Hostname
+ */
+ public string $SMTPHost = '';
+
+ /**
+ * Which SMTP authentication method to use: login, plain
+ */
+ public string $SMTPAuthMethod = 'login';
+
+ /**
+ * SMTP Username
+ */
+ public string $SMTPUser = '';
+
+ /**
+ * SMTP Password
+ */
+ public string $SMTPPass = '';
+
+ /**
+ * SMTP Port
+ */
+ public int $SMTPPort = 25;
+
+ /**
+ * SMTP Timeout (in seconds)
+ */
+ public int $SMTPTimeout = 5;
+
+ /**
+ * Enable persistent SMTP connections
+ */
+ public bool $SMTPKeepAlive = false;
+
+ /**
+ * SMTP Encryption.
+ *
+ * @var string '', 'tls' or 'ssl'. 'tls' will issue a STARTTLS command
+ * to the server. 'ssl' means implicit SSL. Connection on port
+ * 465 should set this to ''.
+ */
+ public string $SMTPCrypto = 'tls';
+
+ /**
+ * Enable word-wrap
+ */
+ public bool $wordWrap = true;
+
+ /**
+ * Character count to wrap at
+ */
+ public int $wrapChars = 76;
+
+ /**
+ * Type of mail, either 'text' or 'html'
+ */
+ public string $mailType = 'text';
+
+ /**
+ * Character set (utf-8, iso-8859-1, etc.)
+ */
+ public string $charset = 'UTF-8';
+
+ /**
+ * Whether to validate the email address
+ */
+ public bool $validate = false;
+
+ /**
+ * Email Priority. 1 = highest. 5 = lowest. 3 = normal
+ */
+ public int $priority = 3;
+
+ /**
+ * Newline character. (Use “\r\n” to comply with RFC 822)
+ */
+ public string $CRLF = "\r\n";
+
+ /**
+ * Newline character. (Use “\r\n” to comply with RFC 822)
+ */
+ public string $newline = "\r\n";
+
+ /**
+ * Enable BCC Batch Mode.
+ */
+ public bool $BCCBatchMode = false;
+
+ /**
+ * Number of emails in each BCC batch
+ */
+ public int $BCCBatchSize = 200;
+
+ /**
+ * Enable notify message from server
+ */
+ public bool $DSN = false;
+}
diff --git a/app/Config/Encryption.php b/app/Config/Encryption.php
new file mode 100644
index 0000000..c6b8aad
--- /dev/null
+++ b/app/Config/Encryption.php
@@ -0,0 +1,109 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Encryption configuration.
+ *
+ * These are the settings used for encryption, if you don't pass a parameter
+ * array to the encrypter for creation/initialization.
+ */
+class Encryption extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Encryption Key Starter
+ * --------------------------------------------------------------------------
+ *
+ * If you use the Encryption class you must set an encryption key (seed).
+ * You need to ensure it is long enough for the cipher and mode you plan to use.
+ * See the user guide for more info.
+ */
+ public string $key = '';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Previous Encryption Keys
+ * --------------------------------------------------------------------------
+ *
+ * When rotating encryption keys, add old keys here to maintain ability
+ * to decrypt data encrypted with previous keys. Encryption always uses
+ * the current $key. Decryption tries current key first, then falls back
+ * to previous keys if decryption fails.
+ *
+ * In .env file, use comma-separated string:
+ * encryption.previousKeys = hex2bin:9be8c64fcea509867...,hex2bin:3f5a1d8e9c2b7a4f6...
+ *
+ * @var list<string>|string
+ */
+ public array|string $previousKeys = '';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Encryption Driver to Use
+ * --------------------------------------------------------------------------
+ *
+ * One of the supported encryption drivers.
+ *
+ * Available drivers:
+ * - OpenSSL
+ * - Sodium
+ */
+ public string $driver = 'OpenSSL';
+
+ /**
+ * --------------------------------------------------------------------------
+ * SodiumHandler's Padding Length in Bytes
+ * --------------------------------------------------------------------------
+ *
+ * This is the number of bytes that will be padded to the plaintext message
+ * before it is encrypted. This value should be greater than zero.
+ *
+ * See the user guide for more information on padding.
+ */
+ public int $blockSize = 16;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Encryption digest
+ * --------------------------------------------------------------------------
+ *
+ * HMAC digest to use, e.g. 'SHA512' or 'SHA256'. Default value is 'SHA512'.
+ */
+ public string $digest = 'SHA512';
+
+ /**
+ * Whether the cipher-text should be raw. If set to false, then it will be base64 encoded.
+ * This setting is only used by OpenSSLHandler.
+ *
+ * Set to false for CI3 Encryption compatibility.
+ */
+ public bool $rawData = true;
+
+ /**
+ * Encryption key info.
+ * This setting is only used by OpenSSLHandler.
+ *
+ * Set to 'encryption' for CI3 Encryption compatibility.
+ */
+ public string $encryptKeyInfo = '';
+
+ /**
+ * Authentication key info.
+ * This setting is only used by OpenSSLHandler.
+ *
+ * Set to 'authentication' for CI3 Encryption compatibility.
+ */
+ public string $authKeyInfo = '';
+
+ /**
+ * Cipher to use.
+ * This setting is only used by OpenSSLHandler.
+ *
+ * Set to 'AES-128-CBC' to decrypt encrypted data that encrypted
+ * by CI3 Encryption default configuration.
+ */
+ public string $cipher = 'AES-256-CTR';
+}
diff --git a/app/Config/Events.php b/app/Config/Events.php
new file mode 100644
index 0000000..7dc9507
--- /dev/null
+++ b/app/Config/Events.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Events\Events;
+use CodeIgniter\Exceptions\FrameworkException;
+use CodeIgniter\HotReloader\HotReloader;
+
+/*
+ * --------------------------------------------------------------------
+ * Application Events
+ * --------------------------------------------------------------------
+ * Events allow you to tap into the execution of the program without
+ * modifying or extending core files. This file provides a central
+ * location to define your events, though they can always be added
+ * at run-time, also, if needed.
+ *
+ * You create code that can execute by subscribing to events with
+ * the 'on()' method. This accepts any form of callable, including
+ * Closures, that will be executed when the event is triggered.
+ *
+ * Example:
+ * Events::on('create', [$myInstance, 'myMethod']);
+ */
+
+Events::on('pre_system', static function (): void {
+ if (ENVIRONMENT !== 'testing') {
+ $value = ini_get('zlib.output_compression');
+
+ if (filter_var($value, FILTER_VALIDATE_BOOLEAN) || (int) $value > 0) {
+ throw FrameworkException::forEnabledZlibOutputCompression();
+ }
+
+ while (ob_get_level() > 0) {
+ ob_end_flush();
+ }
+
+ ob_start(static fn ($buffer) => $buffer);
+ }
+
+ /*
+ * --------------------------------------------------------------------
+ * Debug Toolbar Listeners.
+ * --------------------------------------------------------------------
+ * If you delete, they will no longer be collected.
+ */
+ if (CI_DEBUG && ! is_cli()) {
+ Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect');
+ service('toolbar')->respond();
+ // Hot Reload route - for framework use on the hot reloader.
+ if (ENVIRONMENT === 'development') {
+ service('routes')->get('__hot-reload', static function (): void {
+ (new HotReloader())->run();
+ });
+ }
+ }
+});
diff --git a/app/Config/Exceptions.php b/app/Config/Exceptions.php
new file mode 100644
index 0000000..4e33963
--- /dev/null
+++ b/app/Config/Exceptions.php
@@ -0,0 +1,106 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Debug\ExceptionHandler;
+use CodeIgniter\Debug\ExceptionHandlerInterface;
+use Psr\Log\LogLevel;
+use Throwable;
+
+/**
+ * Setup how the exception handler works.
+ */
+class Exceptions extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * LOG EXCEPTIONS?
+ * --------------------------------------------------------------------------
+ * If true, then exceptions will be logged
+ * through Services::Log.
+ *
+ * Default: true
+ */
+ public bool $log = true;
+
+ /**
+ * --------------------------------------------------------------------------
+ * DO NOT LOG STATUS CODES
+ * --------------------------------------------------------------------------
+ * Any status codes here will NOT be logged if logging is turned on.
+ * By default, only 404 (Page Not Found) exceptions are ignored.
+ *
+ * @var list<int>
+ */
+ public array $ignoreCodes = [404];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Error Views Path
+ * --------------------------------------------------------------------------
+ * This is the path to the directory that contains the 'cli' and 'html'
+ * directories that hold the views used to generate errors.
+ *
+ * Default: APPPATH.'Views/errors'
+ */
+ public string $errorViewPath = APPPATH . 'Views/errors';
+
+ /**
+ * --------------------------------------------------------------------------
+ * HIDE FROM DEBUG TRACE
+ * --------------------------------------------------------------------------
+ * Any data that you would like to hide from the debug trace.
+ * In order to specify 2 levels, use "/" to separate.
+ * ex. ['server', 'setup/password', 'secret_token']
+ *
+ * @var list<string>
+ */
+ public array $sensitiveDataInTrace = [];
+
+ /**
+ * --------------------------------------------------------------------------
+ * WHETHER TO THROW AN EXCEPTION ON DEPRECATED ERRORS
+ * --------------------------------------------------------------------------
+ * If set to `true`, DEPRECATED errors are only logged and no exceptions are
+ * thrown. This option also works for user deprecations.
+ */
+ public bool $logDeprecations = true;
+
+ /**
+ * --------------------------------------------------------------------------
+ * LOG LEVEL THRESHOLD FOR DEPRECATIONS
+ * --------------------------------------------------------------------------
+ * If `$logDeprecations` is set to `true`, this sets the log level
+ * to which the deprecation will be logged. This should be one of the log
+ * levels recognized by PSR-3.
+ *
+ * The related `Config\Logger::$threshold` should be adjusted, if needed,
+ * to capture logging the deprecations.
+ */
+ public string $deprecationLogLevel = LogLevel::WARNING;
+
+ /*
+ * DEFINE THE HANDLERS USED
+ * --------------------------------------------------------------------------
+ * Given the HTTP status code, returns exception handler that
+ * should be used to deal with this error. By default, it will run CodeIgniter's
+ * default handler and display the error information in the expected format
+ * for CLI, HTTP, or AJAX requests, as determined by is_cli() and the expected
+ * response format.
+ *
+ * Custom handlers can be returned if you want to handle one or more specific
+ * error codes yourself like:
+ *
+ * if (in_array($statusCode, [400, 404, 500])) {
+ * return new \App\Libraries\MyExceptionHandler();
+ * }
+ * if ($exception instanceOf PageNotFoundException) {
+ * return new \App\Libraries\MyExceptionHandler();
+ * }
+ */
+ public function handler(int $statusCode, Throwable $exception): ExceptionHandlerInterface
+ {
+ return new ExceptionHandler($this);
+ }
+}
diff --git a/app/Config/Feature.php b/app/Config/Feature.php
new file mode 100644
index 0000000..ec1435a
--- /dev/null
+++ b/app/Config/Feature.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * Enable/disable backward compatibility breaking features.
+ */
+class Feature extends BaseConfig
+{
+ /**
+ * Use improved new auto routing instead of the legacy version.
+ */
+ public bool $autoRoutesImproved = true;
+
+ /**
+ * Use filter execution order in 4.4 or before.
+ */
+ public bool $oldFilterOrder = false;
+
+ /**
+ * The behavior of `limit(0)` in Query Builder.
+ *
+ * If true, `limit(0)` returns all records. (the behavior of 4.4.x or before in version 4.x.)
+ * If false, `limit(0)` returns no records. (the behavior of 3.1.9 or later in version 3.x.)
+ */
+ public bool $limitZeroAsAll = true;
+
+ /**
+ * Use strict location negotiation.
+ *
+ * By default, the locale is selected based on a loose comparison of the language code (ISO 639-1)
+ * Enabling strict comparison will also consider the region code (ISO 3166-1 alpha-2).
+ */
+ public bool $strictLocaleNegotiation = false;
+}
diff --git a/app/Config/Filters.php b/app/Config/Filters.php
new file mode 100644
index 0000000..9c83ae9
--- /dev/null
+++ b/app/Config/Filters.php
@@ -0,0 +1,110 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\Filters as BaseFilters;
+use CodeIgniter\Filters\Cors;
+use CodeIgniter\Filters\CSRF;
+use CodeIgniter\Filters\DebugToolbar;
+use CodeIgniter\Filters\ForceHTTPS;
+use CodeIgniter\Filters\Honeypot;
+use CodeIgniter\Filters\InvalidChars;
+use CodeIgniter\Filters\PageCache;
+use CodeIgniter\Filters\PerformanceMetrics;
+use CodeIgniter\Filters\SecureHeaders;
+
+class Filters extends BaseFilters
+{
+ /**
+ * Configures aliases for Filter classes to
+ * make reading things nicer and simpler.
+ *
+ * @var array<string, class-string|list<class-string>>
+ *
+ * [filter_name => classname]
+ * or [filter_name => [classname1, classname2, ...]]
+ */
+ public array $aliases = [
+ 'csrf' => CSRF::class,
+ 'toolbar' => DebugToolbar::class,
+ 'honeypot' => Honeypot::class,
+ 'invalidchars' => InvalidChars::class,
+ 'secureheaders' => SecureHeaders::class,
+ 'cors' => Cors::class,
+ 'forcehttps' => ForceHTTPS::class,
+ 'pagecache' => PageCache::class,
+ 'performance' => PerformanceMetrics::class,
+ ];
+
+ /**
+ * List of special required filters.
+ *
+ * The filters listed here are special. They are applied before and after
+ * other kinds of filters, and always applied even if a route does not exist.
+ *
+ * Filters set by default provide framework functionality. If removed,
+ * those functions will no longer work.
+ *
+ * @see https://codeigniter.com/user_guide/incoming/filters.html#provided-filters
+ *
+ * @var array{before: list<string>, after: list<string>}
+ */
+ public array $required = [
+ 'before' => [
+ 'forcehttps', // Force Global Secure Requests
+ 'pagecache', // Web Page Caching
+ ],
+ 'after' => [
+ 'pagecache', // Web Page Caching
+ 'performance', // Performance Metrics
+ 'toolbar', // Debug Toolbar
+ ],
+ ];
+
+ /**
+ * List of filter aliases that are always
+ * applied before and after every request.
+ *
+ * @var array{
+ * before: array<string, array{except: list<string>|string}>|list<string>,
+ * after: array<string, array{except: list<string>|string}>|list<string>
+ * }
+ */
+ public array $globals = [
+ 'before' => [
+ // 'honeypot',
+ // 'csrf',
+ // 'invalidchars',
+ ],
+ 'after' => [
+ // 'honeypot',
+ // 'secureheaders',
+ ],
+ ];
+
+ /**
+ * List of filter aliases that works on a
+ * particular HTTP method (GET, POST, etc.).
+ *
+ * Example:
+ * 'POST' => ['foo', 'bar']
+ *
+ * If you use this, you should disable auto-routing because auto-routing
+ * permits any HTTP method to access a controller. Accessing the controller
+ * with a method you don't expect could bypass the filter.
+ *
+ * @var array<string, list<string>>
+ */
+ public array $methods = [];
+
+ /**
+ * List of filter aliases that should run on any
+ * before or after URI patterns.
+ *
+ * Example:
+ * 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
+ *
+ * @var array<string, array<string, list<string>>>
+ */
+ public array $filters = [];
+}
diff --git a/app/Config/ForeignCharacters.php b/app/Config/ForeignCharacters.php
new file mode 100644
index 0000000..f1a9572
--- /dev/null
+++ b/app/Config/ForeignCharacters.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\ForeignCharacters as BaseForeignCharacters;
+
+/**
+ * @immutable
+ */
+class ForeignCharacters extends BaseForeignCharacters
+{
+}
diff --git a/app/Config/Format.php b/app/Config/Format.php
new file mode 100644
index 0000000..5bf56c2
--- /dev/null
+++ b/app/Config/Format.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Format\JSONFormatter;
+use CodeIgniter\Format\XMLFormatter;
+
+class Format extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Available Response Formats
+ * --------------------------------------------------------------------------
+ *
+ * When you perform content negotiation with the request, these are the
+ * available formats that your application supports. This is currently
+ * only used with the API\ResponseTrait. A valid Formatter must exist
+ * for the specified format.
+ *
+ * These formats are only checked when the data passed to the respond()
+ * method is an array.
+ *
+ * @var list<string>
+ */
+ public array $supportedResponseFormats = [
+ 'application/json',
+ 'application/xml', // machine-readable XML
+ 'text/xml', // human-readable XML
+ ];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Formatters
+ * --------------------------------------------------------------------------
+ *
+ * Lists the class to use to format responses with of a particular type.
+ * For each mime type, list the class that should be used. Formatters
+ * can be retrieved through the getFormatter() method.
+ *
+ * @var array<string, string>
+ */
+ public array $formatters = [
+ 'application/json' => JSONFormatter::class,
+ 'application/xml' => XMLFormatter::class,
+ 'text/xml' => XMLFormatter::class,
+ ];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Formatters Options
+ * --------------------------------------------------------------------------
+ *
+ * Additional Options to adjust default formatters behaviour.
+ * For each mime type, list the additional options that should be used.
+ *
+ * @var array<string, int>
+ */
+ public array $formatterOptions = [
+ 'application/json' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
+ 'application/xml' => 0,
+ 'text/xml' => 0,
+ ];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Maximum depth for JSON encoding.
+ * --------------------------------------------------------------------------
+ *
+ * This value determines how deep the JSON encoder will traverse nested structures.
+ */
+ public int $jsonEncodeDepth = 512;
+}
diff --git a/app/Config/Generators.php b/app/Config/Generators.php
new file mode 100644
index 0000000..cc92c7a
--- /dev/null
+++ b/app/Config/Generators.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Generators extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Generator Commands' Views
+ * --------------------------------------------------------------------------
+ *
+ * This array defines the mapping of generator commands to the view files
+ * they are using. If you need to customize them for your own, copy these
+ * view files in your own folder and indicate the location here.
+ *
+ * You will notice that the views have special placeholders enclosed in
+ * curly braces `{...}`. These placeholders are used internally by the
+ * generator commands in processing replacements, thus you are warned
+ * not to delete them or modify the names. If you will do so, you may
+ * end up disrupting the scaffolding process and throw errors.
+ *
+ * YOU HAVE BEEN WARNED!
+ *
+ * @var array<string, array<string, string>|string>
+ */
+ public array $views = [
+ 'make:cell' => [
+ 'class' => 'CodeIgniter\Commands\Generators\Views\cell.tpl.php',
+ 'view' => 'CodeIgniter\Commands\Generators\Views\cell_view.tpl.php',
+ ],
+ 'make:command' => 'CodeIgniter\Commands\Generators\Views\command.tpl.php',
+ 'make:config' => 'CodeIgniter\Commands\Generators\Views\config.tpl.php',
+ 'make:controller' => 'CodeIgniter\Commands\Generators\Views\controller.tpl.php',
+ 'make:entity' => 'CodeIgniter\Commands\Generators\Views\entity.tpl.php',
+ 'make:filter' => 'CodeIgniter\Commands\Generators\Views\filter.tpl.php',
+ 'make:migration' => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php',
+ 'make:model' => 'CodeIgniter\Commands\Generators\Views\model.tpl.php',
+ 'make:seeder' => 'CodeIgniter\Commands\Generators\Views\seeder.tpl.php',
+ 'make:validation' => 'CodeIgniter\Commands\Generators\Views\validation.tpl.php',
+ 'session:migration' => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php',
+ ];
+}
diff --git a/app/Config/Honeypot.php b/app/Config/Honeypot.php
new file mode 100644
index 0000000..67ebcb0
--- /dev/null
+++ b/app/Config/Honeypot.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Honeypot extends BaseConfig
+{
+ /**
+ * Makes Honeypot visible or not to human
+ */
+ public bool $hidden = true;
+
+ /**
+ * Honeypot Label Content
+ */
+ public string $label = 'Fill This Field';
+
+ /**
+ * Honeypot Field Name
+ */
+ public string $name = 'honeypot';
+
+ /**
+ * Honeypot HTML Template
+ */
+ public string $template = '<label>{label}</label><input type="text" name="{name}" value="">';
+
+ /**
+ * Honeypot container
+ *
+ * If you enabled CSP, you can remove `style="display:none"`.
+ */
+ public string $container = '<div style="display:none">{template}</div>';
+
+ /**
+ * The id attribute for Honeypot container tag
+ *
+ * Used when CSP is enabled.
+ */
+ public string $containerId = 'hpc';
+}
diff --git a/app/Config/Hostnames.php b/app/Config/Hostnames.php
new file mode 100644
index 0000000..1b4c722
--- /dev/null
+++ b/app/Config/Hostnames.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Config;
+
+class Hostnames
+{
+ // List of known two-part TLDs for subdomain extraction
+ public const TWO_PART_TLDS = [
+ 'co.uk', 'org.uk', 'gov.uk', 'ac.uk', 'sch.uk', 'ltd.uk', 'plc.uk',
+ 'com.au', 'net.au', 'org.au', 'edu.au', 'gov.au', 'asn.au', 'id.au',
+ 'co.jp', 'ac.jp', 'go.jp', 'or.jp', 'ne.jp', 'gr.jp',
+ 'co.nz', 'org.nz', 'govt.nz', 'ac.nz', 'net.nz', 'geek.nz', 'maori.nz', 'school.nz',
+ 'co.in', 'net.in', 'org.in', 'ind.in', 'ac.in', 'gov.in', 'res.in',
+ 'com.cn', 'net.cn', 'org.cn', 'gov.cn', 'edu.cn',
+ 'com.sg', 'net.sg', 'org.sg', 'gov.sg', 'edu.sg', 'per.sg',
+ 'co.za', 'org.za', 'gov.za', 'ac.za', 'net.za',
+ 'co.kr', 'or.kr', 'go.kr', 'ac.kr', 'ne.kr', 'pe.kr',
+ 'co.th', 'or.th', 'go.th', 'ac.th', 'net.th', 'in.th',
+ 'com.my', 'net.my', 'org.my', 'edu.my', 'gov.my', 'mil.my', 'name.my',
+ 'com.mx', 'org.mx', 'net.mx', 'edu.mx', 'gob.mx',
+ 'com.br', 'net.br', 'org.br', 'gov.br', 'edu.br', 'art.br', 'eng.br',
+ 'co.il', 'org.il', 'ac.il', 'gov.il', 'net.il', 'muni.il',
+ 'co.id', 'or.id', 'ac.id', 'go.id', 'net.id', 'web.id', 'my.id',
+ 'com.hk', 'edu.hk', 'gov.hk', 'idv.hk', 'net.hk', 'org.hk',
+ 'com.tw', 'net.tw', 'org.tw', 'edu.tw', 'gov.tw', 'idv.tw',
+ 'com.sa', 'net.sa', 'org.sa', 'gov.sa', 'edu.sa', 'sch.sa', 'med.sa',
+ 'co.ae', 'net.ae', 'org.ae', 'gov.ae', 'ac.ae', 'sch.ae',
+ 'com.tr', 'net.tr', 'org.tr', 'gov.tr', 'edu.tr', 'av.tr', 'gen.tr',
+ 'co.ke', 'or.ke', 'go.ke', 'ac.ke', 'sc.ke', 'me.ke', 'mobi.ke', 'info.ke',
+ 'com.ng', 'org.ng', 'gov.ng', 'edu.ng', 'net.ng', 'sch.ng', 'name.ng',
+ 'com.pk', 'net.pk', 'org.pk', 'gov.pk', 'edu.pk', 'fam.pk',
+ 'com.eg', 'edu.eg', 'gov.eg', 'org.eg', 'net.eg',
+ 'com.cy', 'net.cy', 'org.cy', 'gov.cy', 'ac.cy',
+ 'com.lk', 'org.lk', 'edu.lk', 'gov.lk', 'net.lk', 'int.lk',
+ 'com.bd', 'net.bd', 'org.bd', 'ac.bd', 'gov.bd', 'mil.bd',
+ 'com.ar', 'net.ar', 'org.ar', 'gov.ar', 'edu.ar', 'mil.ar',
+ 'gob.cl', 'com.pl', 'net.pl', 'org.pl', 'gov.pl', 'edu.pl',
+ 'co.ir', 'ac.ir', 'org.ir', 'id.ir', 'gov.ir', 'sch.ir', 'net.ir',
+ ];
+}
diff --git a/app/Config/Images.php b/app/Config/Images.php
new file mode 100644
index 0000000..68e415e
--- /dev/null
+++ b/app/Config/Images.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Images\Handlers\GDHandler;
+use CodeIgniter\Images\Handlers\ImageMagickHandler;
+
+class Images extends BaseConfig
+{
+ /**
+ * Default handler used if no other handler is specified.
+ */
+ public string $defaultHandler = 'gd';
+
+ /**
+ * The path to the image library.
+ * Required for ImageMagick, GraphicsMagick, or NetPBM.
+ *
+ * @deprecated 4.7.0 No longer used.
+ */
+ public string $libraryPath = '/usr/local/bin/convert';
+
+ /**
+ * The available handler classes.
+ *
+ * @var array<string, string>
+ */
+ public array $handlers = [
+ 'gd' => GDHandler::class,
+ 'imagick' => ImageMagickHandler::class,
+ ];
+}
diff --git a/app/Config/Kint.php b/app/Config/Kint.php
new file mode 100644
index 0000000..931ad47
--- /dev/null
+++ b/app/Config/Kint.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Config;
+
+use Kint\Parser\ConstructablePluginInterface;
+use Kint\Renderer\Rich\TabPluginInterface;
+use Kint\Renderer\Rich\ValuePluginInterface;
+
+/**
+ * --------------------------------------------------------------------------
+ * Kint
+ * --------------------------------------------------------------------------
+ *
+ * We use Kint's `RichRenderer` and `CLIRenderer`. This area contains options
+ * that you can set to customize how Kint works for you.
+ *
+ * @see https://kint-php.github.io/kint/ for details on these settings.
+ */
+class Kint
+{
+ /*
+ |--------------------------------------------------------------------------
+ | Global Settings
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * @var list<class-string<ConstructablePluginInterface>|ConstructablePluginInterface>|null
+ */
+ public $plugins;
+
+ public int $maxDepth = 6;
+ public bool $displayCalledFrom = true;
+ public bool $expanded = false;
+
+ /*
+ |--------------------------------------------------------------------------
+ | RichRenderer Settings
+ |--------------------------------------------------------------------------
+ */
+ public string $richTheme = 'aante-light.css';
+ public bool $richFolder = false;
+
+ /**
+ * @var array<string, class-string<ValuePluginInterface>>|null
+ */
+ public $richObjectPlugins;
+
+ /**
+ * @var array<string, class-string<TabPluginInterface>>|null
+ */
+ public $richTabPlugins;
+
+ /*
+ |--------------------------------------------------------------------------
+ | CLI Settings
+ |--------------------------------------------------------------------------
+ */
+ public bool $cliColors = true;
+ public bool $cliForceUTF8 = false;
+ public bool $cliDetectWidth = true;
+ public int $cliMinWidth = 40;
+}
diff --git a/app/Config/Logger.php b/app/Config/Logger.php
new file mode 100644
index 0000000..799dc2c
--- /dev/null
+++ b/app/Config/Logger.php
@@ -0,0 +1,151 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Log\Handlers\FileHandler;
+use CodeIgniter\Log\Handlers\HandlerInterface;
+
+class Logger extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Error Logging Threshold
+ * --------------------------------------------------------------------------
+ *
+ * You can enable error logging by setting a threshold over zero. The
+ * threshold determines what gets logged. Any values below or equal to the
+ * threshold will be logged.
+ *
+ * Threshold options are:
+ *
+ * - 0 = Disables logging, Error logging TURNED OFF
+ * - 1 = Emergency Messages - System is unusable
+ * - 2 = Alert Messages - Action Must Be Taken Immediately
+ * - 3 = Critical Messages - Application component unavailable, unexpected exception.
+ * - 4 = Runtime Errors - Don't need immediate action, but should be monitored.
+ * - 5 = Warnings - Exceptional occurrences that are not errors.
+ * - 6 = Notices - Normal but significant events.
+ * - 7 = Info - Interesting events, like user logging in, etc.
+ * - 8 = Debug - Detailed debug information.
+ * - 9 = All Messages
+ *
+ * You can also pass an array with threshold levels to show individual error types
+ *
+ * array(1, 2, 3, 8) = Emergency, Alert, Critical, and Debug messages
+ *
+ * For a live site you'll usually enable Critical or higher (3) to be logged otherwise
+ * your log files will fill up very fast.
+ *
+ * @var int|list<int>
+ */
+ public $threshold = (ENVIRONMENT === 'production') ? 4 : 9;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Date Format for Logs
+ * --------------------------------------------------------------------------
+ *
+ * Each item that is logged has an associated date. You can use PHP date
+ * codes to set your own date formatting
+ */
+ public string $dateFormat = 'Y-m-d H:i:s';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Log Handlers
+ * --------------------------------------------------------------------------
+ *
+ * The logging system supports multiple actions to be taken when something
+ * is logged. This is done by allowing for multiple Handlers, special classes
+ * designed to write the log to their chosen destinations, whether that is
+ * a file on the getServer, a cloud-based service, or even taking actions such
+ * as emailing the dev team.
+ *
+ * Each handler is defined by the class name used for that handler, and it
+ * MUST implement the `CodeIgniter\Log\Handlers\HandlerInterface` interface.
+ *
+ * The value of each key is an array of configuration items that are sent
+ * to the constructor of each handler. The only required configuration item
+ * is the 'handles' element, which must be an array of integer log levels.
+ * This is most easily handled by using the constants defined in the
+ * `Psr\Log\LogLevel` class.
+ *
+ * Handlers are executed in the order defined in this array, starting with
+ * the handler on top and continuing down.
+ *
+ * @var array<class-string<HandlerInterface>, array<string, int|list<string>|string>>
+ */
+ public array $handlers = [
+ /*
+ * --------------------------------------------------------------------
+ * File Handler
+ * --------------------------------------------------------------------
+ */
+ FileHandler::class => [
+ // The log levels that this handler will handle.
+ 'handles' => [
+ 'critical',
+ 'alert',
+ 'emergency',
+ 'debug',
+ 'error',
+ 'info',
+ 'notice',
+ 'warning',
+ ],
+
+ /*
+ * The default filename extension for log files.
+ * An extension of 'php' allows for protecting the log files via basic
+ * scripting, when they are to be stored under a publicly accessible directory.
+ *
+ * NOTE: Leaving it blank will default to 'log'.
+ */
+ 'fileExtension' => '',
+
+ /*
+ * The file system permissions to be applied on newly created log files.
+ *
+ * IMPORTANT: This MUST be an integer (no quotes) and you MUST use octal
+ * integer notation (i.e. 0700, 0644, etc.)
+ */
+ 'filePermissions' => 0644,
+
+ /*
+ * Logging Directory Path
+ *
+ * By default, logs are written to WRITEPATH . 'logs/'
+ * Specify a different destination here, if desired.
+ */
+ 'path' => '',
+ ],
+
+ /*
+ * The ChromeLoggerHandler requires the use of the Chrome web browser
+ * and the ChromeLogger extension. Uncomment this block to use it.
+ */
+ // 'CodeIgniter\Log\Handlers\ChromeLoggerHandler' => [
+ // /*
+ // * The log levels that this handler will handle.
+ // */
+ // 'handles' => ['critical', 'alert', 'emergency', 'debug',
+ // 'error', 'info', 'notice', 'warning'],
+ // ],
+
+ /*
+ * The ErrorlogHandler writes the logs to PHP's native `error_log()` function.
+ * Uncomment this block to use it.
+ */
+ // 'CodeIgniter\Log\Handlers\ErrorlogHandler' => [
+ // /* The log levels this handler can handle. */
+ // 'handles' => ['critical', 'alert', 'emergency', 'debug', 'error', 'info', 'notice', 'warning'],
+ //
+ // /*
+ // * The message type where the error should go. Can be 0 or 4, or use the
+ // * class constants: `ErrorlogHandler::TYPE_OS` (0) or `ErrorlogHandler::TYPE_SAPI` (4)
+ // */
+ // 'messageType' => 0,
+ // ],
+ ];
+}
diff --git a/app/Config/Migrations.php b/app/Config/Migrations.php
new file mode 100644
index 0000000..eb45e72
--- /dev/null
+++ b/app/Config/Migrations.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Migrations extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Enable/Disable Migrations
+ * --------------------------------------------------------------------------
+ *
+ * Migrations are enabled by default.
+ *
+ * You should enable migrations whenever you intend to do a schema migration
+ * and disable it back when you're done.
+ */
+ public bool $enabled = true;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Migrations Table
+ * --------------------------------------------------------------------------
+ *
+ * This is the name of the table that will store the current migrations state.
+ * When migrations runs it will store in a database table which migration
+ * files have already been run.
+ */
+ public string $table = 'migrations';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Timestamp Format
+ * --------------------------------------------------------------------------
+ *
+ * This is the format that will be used when creating new migrations
+ * using the CLI command:
+ * > php spark make:migration
+ *
+ * NOTE: if you set an unsupported format, migration runner will not find
+ * your migration files.
+ *
+ * Supported formats:
+ * - YmdHis_
+ * - Y-m-d-His_
+ * - Y_m_d_His_
+ */
+ public string $timestampFormat = 'Y-m-d-His_';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Enable/Disable Migration Lock
+ * --------------------------------------------------------------------------
+ *
+ * Locking is disabled by default.
+ *
+ * When enabled, it will prevent multiple migration processes
+ * from running at the same time by using a lock mechanism.
+ *
+ * This is useful in production environments to avoid conflicts
+ * or race conditions during concurrent deployments.
+ */
+ public bool $lock = false;
+}
diff --git a/app/Config/Mimes.php b/app/Config/Mimes.php
new file mode 100644
index 0000000..c2db734
--- /dev/null
+++ b/app/Config/Mimes.php
@@ -0,0 +1,534 @@
+<?php
+
+namespace Config;
+
+/**
+ * This file contains an array of mime types. It is used by the
+ * Upload class to help identify allowed file types.
+ *
+ * When more than one variation for an extension exist (like jpg, jpeg, etc)
+ * the most common one should be first in the array to aid the guess*
+ * methods. The same applies when more than one mime-type exists for a
+ * single extension.
+ *
+ * When working with mime types, please make sure you have the ´fileinfo´
+ * extension enabled to reliably detect the media types.
+ */
+class Mimes
+{
+ /**
+ * Map of extensions to mime types.
+ *
+ * @var array<string, list<string>|string>
+ */
+ public static array $mimes = [
+ 'hqx' => [
+ 'application/mac-binhex40',
+ 'application/mac-binhex',
+ 'application/x-binhex40',
+ 'application/x-mac-binhex40',
+ ],
+ 'cpt' => 'application/mac-compactpro',
+ 'csv' => [
+ 'text/csv',
+ 'text/x-comma-separated-values',
+ 'text/comma-separated-values',
+ 'application/vnd.ms-excel',
+ 'application/x-csv',
+ 'text/x-csv',
+ 'application/csv',
+ 'application/excel',
+ 'application/vnd.msexcel',
+ 'text/plain',
+ ],
+ 'bin' => [
+ 'application/macbinary',
+ 'application/mac-binary',
+ 'application/octet-stream',
+ 'application/x-binary',
+ 'application/x-macbinary',
+ ],
+ 'dms' => 'application/octet-stream',
+ 'lha' => 'application/octet-stream',
+ 'lzh' => 'application/octet-stream',
+ 'exe' => [
+ 'application/octet-stream',
+ 'application/vnd.microsoft.portable-executable',
+ 'application/x-dosexec',
+ 'application/x-msdownload',
+ ],
+ 'class' => 'application/octet-stream',
+ 'psd' => [
+ 'application/x-photoshop',
+ 'image/vnd.adobe.photoshop',
+ ],
+ 'so' => 'application/octet-stream',
+ 'sea' => 'application/octet-stream',
+ 'dll' => 'application/octet-stream',
+ 'oda' => 'application/oda',
+ 'pdf' => [
+ 'application/pdf',
+ 'application/force-download',
+ 'application/x-download',
+ ],
+ 'ai' => [
+ 'application/pdf',
+ 'application/postscript',
+ ],
+ 'eps' => 'application/postscript',
+ 'ps' => 'application/postscript',
+ 'smi' => 'application/smil',
+ 'smil' => 'application/smil',
+ 'mif' => 'application/vnd.mif',
+ 'xls' => [
+ 'application/vnd.ms-excel',
+ 'application/msexcel',
+ 'application/x-msexcel',
+ 'application/x-ms-excel',
+ 'application/x-excel',
+ 'application/x-dos_ms_excel',
+ 'application/xls',
+ 'application/x-xls',
+ 'application/excel',
+ 'application/download',
+ 'application/vnd.ms-office',
+ 'application/msword',
+ ],
+ 'ppt' => [
+ 'application/vnd.ms-powerpoint',
+ 'application/powerpoint',
+ 'application/vnd.ms-office',
+ 'application/msword',
+ ],
+ 'pptx' => [
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ ],
+ 'wbxml' => 'application/wbxml',
+ 'wmlc' => 'application/wmlc',
+ 'dcr' => 'application/x-director',
+ 'dir' => 'application/x-director',
+ 'dxr' => 'application/x-director',
+ 'dvi' => 'application/x-dvi',
+ 'gtar' => 'application/x-gtar',
+ 'gz' => 'application/x-gzip',
+ 'gzip' => 'application/x-gzip',
+ 'php' => [
+ 'application/x-php',
+ 'application/x-httpd-php',
+ 'application/php',
+ 'text/php',
+ 'text/x-php',
+ 'application/x-httpd-php-source',
+ ],
+ 'php4' => 'application/x-httpd-php',
+ 'php3' => 'application/x-httpd-php',
+ 'phtml' => 'application/x-httpd-php',
+ 'phps' => 'application/x-httpd-php-source',
+ 'js' => [
+ 'application/x-javascript',
+ 'text/plain',
+ ],
+ 'swf' => 'application/x-shockwave-flash',
+ 'sit' => 'application/x-stuffit',
+ 'tar' => 'application/x-tar',
+ 'tgz' => [
+ 'application/x-tar',
+ 'application/x-gzip-compressed',
+ ],
+ 'z' => 'application/x-compress',
+ 'xhtml' => 'application/xhtml+xml',
+ 'xht' => 'application/xhtml+xml',
+ 'zip' => [
+ 'application/x-zip',
+ 'application/zip',
+ 'application/x-zip-compressed',
+ 'application/s-compressed',
+ 'multipart/x-zip',
+ ],
+ 'rar' => [
+ 'application/vnd.rar',
+ 'application/x-rar',
+ 'application/rar',
+ 'application/x-rar-compressed',
+ ],
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mpga' => 'audio/mpeg',
+ 'mp2' => 'audio/mpeg',
+ 'mp3' => [
+ 'audio/mpeg',
+ 'audio/mpg',
+ 'audio/mpeg3',
+ 'audio/mp3',
+ ],
+ 'aif' => [
+ 'audio/x-aiff',
+ 'audio/aiff',
+ ],
+ 'aiff' => [
+ 'audio/x-aiff',
+ 'audio/aiff',
+ ],
+ 'aifc' => 'audio/x-aiff',
+ 'ram' => 'audio/x-pn-realaudio',
+ 'rm' => 'audio/x-pn-realaudio',
+ 'rpm' => 'audio/x-pn-realaudio-plugin',
+ 'ra' => 'audio/x-realaudio',
+ 'rv' => 'video/vnd.rn-realvideo',
+ 'wav' => [
+ 'audio/x-wav',
+ 'audio/wave',
+ 'audio/wav',
+ ],
+ 'bmp' => [
+ 'image/bmp',
+ 'image/x-bmp',
+ 'image/x-bitmap',
+ 'image/x-xbitmap',
+ 'image/x-win-bitmap',
+ 'image/x-windows-bmp',
+ 'image/ms-bmp',
+ 'image/x-ms-bmp',
+ 'application/bmp',
+ 'application/x-bmp',
+ 'application/x-win-bitmap',
+ ],
+ 'gif' => 'image/gif',
+ 'jpg' => [
+ 'image/jpeg',
+ 'image/pjpeg',
+ ],
+ 'jpeg' => [
+ 'image/jpeg',
+ 'image/pjpeg',
+ ],
+ 'jpe' => [
+ 'image/jpeg',
+ 'image/pjpeg',
+ ],
+ 'jp2' => [
+ 'image/jp2',
+ 'video/mj2',
+ 'image/jpx',
+ 'image/jpm',
+ ],
+ 'j2k' => [
+ 'image/jp2',
+ 'video/mj2',
+ 'image/jpx',
+ 'image/jpm',
+ ],
+ 'jpf' => [
+ 'image/jp2',
+ 'video/mj2',
+ 'image/jpx',
+ 'image/jpm',
+ ],
+ 'jpg2' => [
+ 'image/jp2',
+ 'video/mj2',
+ 'image/jpx',
+ 'image/jpm',
+ ],
+ 'jpx' => [
+ 'image/jp2',
+ 'video/mj2',
+ 'image/jpx',
+ 'image/jpm',
+ ],
+ 'jpm' => [
+ 'image/jp2',
+ 'video/mj2',
+ 'image/jpx',
+ 'image/jpm',
+ ],
+ 'mj2' => [
+ 'image/jp2',
+ 'video/mj2',
+ 'image/jpx',
+ 'image/jpm',
+ ],
+ 'mjp2' => [
+ 'image/jp2',
+ 'video/mj2',
+ 'image/jpx',
+ 'image/jpm',
+ ],
+ 'png' => [
+ 'image/png',
+ 'image/x-png',
+ ],
+ 'webp' => 'image/webp',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'css' => [
+ 'text/css',
+ 'text/plain',
+ ],
+ 'html' => [
+ 'text/html',
+ 'text/plain',
+ ],
+ 'htm' => [
+ 'text/html',
+ 'text/plain',
+ ],
+ 'shtml' => [
+ 'text/html',
+ 'text/plain',
+ ],
+ 'txt' => 'text/plain',
+ 'text' => 'text/plain',
+ 'log' => [
+ 'text/plain',
+ 'text/x-log',
+ ],
+ 'rtx' => 'text/richtext',
+ 'rtf' => 'text/rtf',
+ 'xml' => [
+ 'application/xml',
+ 'text/xml',
+ 'text/plain',
+ ],
+ 'xsl' => [
+ 'application/xml',
+ 'text/xsl',
+ 'text/xml',
+ ],
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpe' => 'video/mpeg',
+ 'qt' => 'video/quicktime',
+ 'mov' => 'video/quicktime',
+ 'avi' => [
+ 'video/x-msvideo',
+ 'video/msvideo',
+ 'video/avi',
+ 'application/x-troff-msvideo',
+ ],
+ 'movie' => 'video/x-sgi-movie',
+ 'doc' => [
+ 'application/msword',
+ 'application/vnd.ms-office',
+ ],
+ 'docx' => [
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'application/zip',
+ 'application/msword',
+ 'application/x-zip',
+ ],
+ 'dot' => [
+ 'application/msword',
+ 'application/vnd.ms-office',
+ ],
+ 'dotx' => [
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'application/zip',
+ 'application/msword',
+ ],
+ 'xlsx' => [
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'application/zip',
+ 'application/vnd.ms-excel',
+ 'application/msword',
+ 'application/x-zip',
+ ],
+ 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
+ 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
+ 'word' => [
+ 'application/msword',
+ 'application/octet-stream',
+ ],
+ 'xl' => 'application/excel',
+ 'eml' => 'message/rfc822',
+ 'json' => [
+ 'application/json',
+ 'text/json',
+ ],
+ 'pem' => [
+ 'application/x-x509-user-cert',
+ 'application/x-pem-file',
+ 'application/octet-stream',
+ ],
+ 'p10' => [
+ 'application/x-pkcs10',
+ 'application/pkcs10',
+ ],
+ 'p12' => 'application/x-pkcs12',
+ 'p7a' => 'application/x-pkcs7-signature',
+ 'p7c' => [
+ 'application/pkcs7-mime',
+ 'application/x-pkcs7-mime',
+ ],
+ 'p7m' => [
+ 'application/pkcs7-mime',
+ 'application/x-pkcs7-mime',
+ ],
+ 'p7r' => 'application/x-pkcs7-certreqresp',
+ 'p7s' => 'application/pkcs7-signature',
+ 'crt' => [
+ 'application/x-x509-ca-cert',
+ 'application/x-x509-user-cert',
+ 'application/pkix-cert',
+ ],
+ 'crl' => [
+ 'application/pkix-crl',
+ 'application/pkcs-crl',
+ ],
+ 'der' => 'application/x-x509-ca-cert',
+ 'kdb' => 'application/octet-stream',
+ 'pgp' => 'application/pgp',
+ 'gpg' => 'application/gpg-keys',
+ 'sst' => 'application/octet-stream',
+ 'csr' => 'application/octet-stream',
+ 'rsa' => 'application/x-pkcs7',
+ 'cer' => [
+ 'application/pkix-cert',
+ 'application/x-x509-ca-cert',
+ ],
+ '3g2' => 'video/3gpp2',
+ '3gp' => [
+ 'video/3gp',
+ 'video/3gpp',
+ ],
+ 'mp4' => 'video/mp4',
+ 'm4a' => 'audio/x-m4a',
+ 'f4v' => [
+ 'video/mp4',
+ 'video/x-f4v',
+ ],
+ 'flv' => 'video/x-flv',
+ 'webm' => 'video/webm',
+ 'aac' => 'audio/x-acc',
+ 'm4u' => 'application/vnd.mpegurl',
+ 'm3u' => 'text/plain',
+ 'xspf' => 'application/xspf+xml',
+ 'vlc' => 'application/videolan',
+ 'wmv' => [
+ 'video/x-ms-wmv',
+ 'video/x-ms-asf',
+ ],
+ 'au' => 'audio/x-au',
+ 'ac3' => 'audio/ac3',
+ 'flac' => 'audio/x-flac',
+ 'ogg' => [
+ 'audio/ogg',
+ 'video/ogg',
+ 'application/ogg',
+ ],
+ 'kmz' => [
+ 'application/vnd.google-earth.kmz',
+ 'application/zip',
+ 'application/x-zip',
+ ],
+ 'kml' => [
+ 'application/vnd.google-earth.kml+xml',
+ 'application/xml',
+ 'text/xml',
+ ],
+ 'ics' => 'text/calendar',
+ 'ical' => 'text/calendar',
+ 'zsh' => 'text/x-scriptzsh',
+ '7zip' => [
+ 'application/x-compressed',
+ 'application/x-zip-compressed',
+ 'application/zip',
+ 'multipart/x-zip',
+ ],
+ 'cdr' => [
+ 'application/cdr',
+ 'application/coreldraw',
+ 'application/x-cdr',
+ 'application/x-coreldraw',
+ 'image/cdr',
+ 'image/x-cdr',
+ 'zz-application/zz-winassoc-cdr',
+ ],
+ 'wma' => [
+ 'audio/x-ms-wma',
+ 'video/x-ms-asf',
+ ],
+ 'jar' => [
+ 'application/java-archive',
+ 'application/x-java-application',
+ 'application/x-jar',
+ 'application/x-compressed',
+ ],
+ 'svg' => [
+ 'image/svg+xml',
+ 'image/svg',
+ 'application/xml',
+ 'text/xml',
+ ],
+ 'vcf' => 'text/x-vcard',
+ 'srt' => [
+ 'text/srt',
+ 'text/plain',
+ ],
+ 'vtt' => [
+ 'text/vtt',
+ 'text/plain',
+ ],
+ 'ico' => [
+ 'image/x-icon',
+ 'image/x-ico',
+ 'image/vnd.microsoft.icon',
+ ],
+ 'stl' => [
+ 'application/sla',
+ 'application/vnd.ms-pki.stl',
+ 'application/x-navistyle',
+ 'model/stl',
+ 'application/octet-stream',
+ ],
+ ];
+
+ /**
+ * Attempts to determine the best mime type for the given file extension.
+ *
+ * @return string|null The mime type found, or none if unable to determine.
+ */
+ public static function guessTypeFromExtension(string $extension)
+ {
+ $extension = trim(strtolower($extension), '. ');
+
+ if (! array_key_exists($extension, static::$mimes)) {
+ return null;
+ }
+
+ return is_array(static::$mimes[$extension]) ? static::$mimes[$extension][0] : static::$mimes[$extension];
+ }
+
+ /**
+ * Attempts to determine the best file extension for a given mime type.
+ *
+ * @param string|null $proposedExtension - default extension (in case there is more than one with the same mime type)
+ *
+ * @return string|null The extension determined, or null if unable to match.
+ */
+ public static function guessExtensionFromType(string $type, ?string $proposedExtension = null)
+ {
+ $type = trim(strtolower($type), '. ');
+
+ $proposedExtension = trim(strtolower($proposedExtension ?? ''));
+
+ if (
+ $proposedExtension !== ''
+ && array_key_exists($proposedExtension, static::$mimes)
+ && in_array($type, (array) static::$mimes[$proposedExtension], true)
+ ) {
+ // The detected mime type matches with the proposed extension.
+ return $proposedExtension;
+ }
+
+ // Reverse check the mime type list if no extension was proposed.
+ // This search is order sensitive!
+ foreach (static::$mimes as $ext => $types) {
+ if (in_array($type, (array) $types, true)) {
+ return $ext;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/app/Config/Modules.php b/app/Config/Modules.php
new file mode 100644
index 0000000..9e03fa4
--- /dev/null
+++ b/app/Config/Modules.php
@@ -0,0 +1,82 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Modules\Modules as BaseModules;
+
+/**
+ * Modules Configuration.
+ *
+ * NOTE: This class is required prior to Autoloader instantiation,
+ * and does not extend BaseConfig.
+ */
+class Modules extends BaseModules
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Enable Auto-Discovery?
+ * --------------------------------------------------------------------------
+ *
+ * If true, then auto-discovery will happen across all elements listed in
+ * $aliases below. If false, no auto-discovery will happen at all,
+ * giving a slight performance boost.
+ *
+ * @var bool
+ */
+ public $enabled = true;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Enable Auto-Discovery Within Composer Packages?
+ * --------------------------------------------------------------------------
+ *
+ * If true, then auto-discovery will happen across all namespaces loaded
+ * by Composer, as well as the namespaces configured locally.
+ *
+ * @var bool
+ */
+ public $discoverInComposer = true;
+
+ /**
+ * The Composer package list for Auto-Discovery
+ * This setting is optional.
+ *
+ * E.g.:
+ * [
+ * 'only' => [
+ * // List up all packages to auto-discover
+ * 'codeigniter4/shield',
+ * ],
+ * ]
+ * or
+ * [
+ * 'exclude' => [
+ * // List up packages to exclude.
+ * 'pestphp/pest',
+ * ],
+ * ]
+ *
+ * @var array{only?: list<string>, exclude?: list<string>}
+ */
+ public $composerPackages = [];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Auto-Discovery Rules
+ * --------------------------------------------------------------------------
+ *
+ * Aliases list of all discovery classes that will be active and used during
+ * the current application request.
+ *
+ * If it is not listed, only the base application elements will be used.
+ *
+ * @var list<string>
+ */
+ public $aliases = [
+ 'events',
+ 'filters',
+ 'registrars',
+ 'routes',
+ 'services',
+ ];
+}
diff --git a/app/Config/Optimize.php b/app/Config/Optimize.php
new file mode 100644
index 0000000..8b93eb1
--- /dev/null
+++ b/app/Config/Optimize.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Config;
+
+/**
+ * Optimization Configuration.
+ *
+ * NOTE: This class does not extend BaseConfig for performance reasons.
+ * So you cannot replace the property values with Environment Variables.
+ *
+ * WARNING: Do not use these options when running the app in the Worker Mode.
+ */
+class Optimize
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Config Caching
+ * --------------------------------------------------------------------------
+ *
+ * @see https://codeigniter.com/user_guide/concepts/factories.html#config-caching
+ */
+ public bool $configCacheEnabled = false;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Config Caching
+ * --------------------------------------------------------------------------
+ *
+ * @see https://codeigniter.com/user_guide/concepts/autoloader.html#file-locator-caching
+ */
+ public bool $locatorCacheEnabled = false;
+}
diff --git a/app/Config/Pager.php b/app/Config/Pager.php
new file mode 100644
index 0000000..e341f4d
--- /dev/null
+++ b/app/Config/Pager.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Pager extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Templates
+ * --------------------------------------------------------------------------
+ *
+ * Pagination links are rendered out using views to configure their
+ * appearance. This array contains aliases and the view names to
+ * use when rendering the links.
+ *
+ * Within each view, the Pager object will be available as $pager,
+ * and the desired group as $pagerGroup;
+ *
+ * @var array<string, string>
+ */
+ public array $templates = [
+ 'default_full' => 'CodeIgniter\Pager\Views\default_full',
+ 'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
+ 'default_head' => 'CodeIgniter\Pager\Views\default_head',
+ ];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Items Per Page
+ * --------------------------------------------------------------------------
+ *
+ * The default number of results shown in a single page.
+ */
+ public int $perPage = 20;
+}
diff --git a/app/Config/Paths.php b/app/Config/Paths.php
new file mode 100644
index 0000000..ee2d7ff
--- /dev/null
+++ b/app/Config/Paths.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Config;
+
+/**
+ * Paths
+ *
+ * Holds the paths that are used by the system to
+ * locate the main directories, app, system, etc.
+ *
+ * Modifying these allows you to restructure your application,
+ * share a system folder between multiple applications, and more.
+ *
+ * All paths are relative to the project's root folder.
+ *
+ * NOTE: This class is required prior to Autoloader instantiation,
+ * and does not extend BaseConfig.
+ */
+class Paths
+{
+ /**
+ * ---------------------------------------------------------------
+ * SYSTEM FOLDER NAME
+ * ---------------------------------------------------------------
+ *
+ * This must contain the name of your "system" folder. Include
+ * the path if the folder is not in the same directory as this file.
+ */
+ public string $systemDirectory = __DIR__ . '/../../vendor/codeigniter4/framework/system';
+
+ /**
+ * ---------------------------------------------------------------
+ * APPLICATION FOLDER NAME
+ * ---------------------------------------------------------------
+ *
+ * If you want this front controller to use a different "app"
+ * folder than the default one you can set its name here. The folder
+ * can also be renamed or relocated anywhere on your server. If
+ * you do, use a full server path.
+ *
+ * @see http://codeigniter.com/user_guide/general/managing_apps.html
+ */
+ public string $appDirectory = __DIR__ . '/..';
+
+ /**
+ * ---------------------------------------------------------------
+ * WRITABLE DIRECTORY NAME
+ * ---------------------------------------------------------------
+ *
+ * This variable must contain the name of your "writable" directory.
+ * The writable directory allows you to group all directories that
+ * need write permission to a single place that can be tucked away
+ * for maximum security, keeping it out of the app and/or
+ * system directories.
+ */
+ public string $writableDirectory = __DIR__ . '/../../writable';
+
+ /**
+ * ---------------------------------------------------------------
+ * TESTS DIRECTORY NAME
+ * ---------------------------------------------------------------
+ *
+ * This variable must contain the name of your "tests" directory.
+ */
+ public string $testsDirectory = __DIR__ . '/../../tests';
+
+ /**
+ * ---------------------------------------------------------------
+ * VIEW DIRECTORY NAME
+ * ---------------------------------------------------------------
+ *
+ * This variable must contain the name of the directory that
+ * contains the view files used by your application. By
+ * default this is in `app/Views`. This value
+ * is used when no value is provided to `Services::renderer()`.
+ */
+ public string $viewDirectory = __DIR__ . '/../Views';
+
+ /**
+ * ---------------------------------------------------------------
+ * ENVIRONMENT DIRECTORY NAME
+ * ---------------------------------------------------------------
+ *
+ * This variable must contain the name of the directory where
+ * the .env file is located.
+ * Please consider security implications when changing this
+ * value - the directory should not be publicly accessible.
+ */
+ public string $envDirectory = __DIR__ . '/../../';
+}
diff --git a/app/Config/Publisher.php b/app/Config/Publisher.php
new file mode 100644
index 0000000..bf03be1
--- /dev/null
+++ b/app/Config/Publisher.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\Publisher as BasePublisher;
+
+/**
+ * Publisher Configuration
+ *
+ * Defines basic security restrictions for the Publisher class
+ * to prevent abuse by injecting malicious files into a project.
+ */
+class Publisher extends BasePublisher
+{
+ /**
+ * A list of allowed destinations with a (pseudo-)regex
+ * of allowed files for each destination.
+ * Attempts to publish to directories not in this list will
+ * result in a PublisherException. Files that do no fit the
+ * pattern will cause copy/merge to fail.
+ *
+ * @var array<string, string>
+ */
+ public $restrictions = [
+ ROOTPATH => '*',
+ FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|ttf|eot|woff2?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i',
+ ];
+}
diff --git a/app/Config/Routes.php b/app/Config/Routes.php
new file mode 100644
index 0000000..4cf109e
--- /dev/null
+++ b/app/Config/Routes.php
@@ -0,0 +1,6 @@
+<?php
+
+use CodeIgniter\Router\RouteCollection;
+
+/** @var RouteCollection $routes */
+$routes->get('/', 'Home::index');
diff --git a/app/Config/Routing.php b/app/Config/Routing.php
new file mode 100644
index 0000000..5aeee51
--- /dev/null
+++ b/app/Config/Routing.php
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * This file is part of CodeIgniter 4 framework.
+ *
+ * (c) CodeIgniter Foundation <[email protected]>
+ *
+ * For the full copyright and license information, please view
+ * the LICENSE file that was distributed with this source code.
+ */
+
+namespace Config;
+
+use CodeIgniter\Config\Routing as BaseRouting;
+
+/**
+ * Routing configuration
+ */
+class Routing extends BaseRouting
+{
+ /**
+ * For Defined Routes.
+ * An array of files that contain route definitions.
+ * Route files are read in order, with the first match
+ * found taking precedence.
+ *
+ * Default: APPPATH . 'Config/Routes.php'
+ *
+ * @var list<string>
+ */
+ public array $routeFiles = [
+ APPPATH . 'Config/Routes.php',
+ ];
+
+ /**
+ * For Defined Routes and Auto Routing.
+ * The default namespace to use for Controllers when no other
+ * namespace has been specified.
+ *
+ * Default: 'App\Controllers'
+ */
+ public string $defaultNamespace = 'App\Controllers';
+
+ /**
+ * For Auto Routing.
+ * The default controller to use when no other controller has been
+ * specified.
+ *
+ * Default: 'Home'
+ */
+ public string $defaultController = 'Home';
+
+ /**
+ * For Defined Routes and Auto Routing.
+ * The default method to call on the controller when no other
+ * method has been set in the route.
+ *
+ * Default: 'index'
+ */
+ public string $defaultMethod = 'index';
+
+ /**
+ * For Auto Routing.
+ * Whether to translate dashes in URIs for controller/method to underscores.
+ * Primarily useful when using the auto-routing.
+ *
+ * Default: false
+ */
+ public bool $translateURIDashes = false;
+
+ /**
+ * Sets the class/method that should be called if routing doesn't
+ * find a match. It can be the controller/method name like: Users::index
+ *
+ * This setting is passed to the Router class and handled there.
+ *
+ * If you want to use a closure, you will have to set it in the
+ * routes file by calling:
+ *
+ * $routes->set404Override(function() {
+ * // Do something here
+ * });
+ *
+ * Example:
+ * public $override404 = 'App\Errors::show404';
+ */
+ public ?string $override404 = null;
+
+ /**
+ * If TRUE, the system will attempt to match the URI against
+ * Controllers by matching each segment against folders/files
+ * in APPPATH/Controllers, when a match wasn't found against
+ * defined routes.
+ *
+ * If FALSE, will stop searching and do NO automatic routing.
+ */
+ public bool $autoRoute = false;
+
+ /**
+ * If TRUE, the system will look for attributes on controller
+ * class and methods that can run before and after the
+ * controller/method.
+ *
+ * If FALSE, will ignore any attributes.
+ */
+ public bool $useControllerAttributes = true;
+
+ /**
+ * For Defined Routes.
+ * If TRUE, will enable the use of the 'prioritize' option
+ * when defining routes.
+ *
+ * Default: false
+ */
+ public bool $prioritize = false;
+
+ /**
+ * For Defined Routes.
+ * If TRUE, matched multiple URI segments will be passed as one parameter.
+ *
+ * Default: false
+ */
+ public bool $multipleSegmentsOneParam = false;
+
+ /**
+ * For Auto Routing (Improved).
+ * Map of URI segments and namespaces.
+ *
+ * The key is the first URI segment. The value is the controller namespace.
+ * E.g.,
+ * [
+ * 'blog' => 'Acme\Blog\Controllers',
+ * ]
+ *
+ * @var array<string, string>
+ */
+ public array $moduleRoutes = [];
+
+ /**
+ * For Auto Routing (Improved).
+ * Whether to translate dashes in URIs for controller/method to CamelCase.
+ * E.g., blog-controller -> BlogController
+ *
+ * If you enable this, $translateURIDashes is ignored.
+ *
+ * Default: false
+ */
+ public bool $translateUriToCamelCase = true;
+}
diff --git a/app/Config/Security.php b/app/Config/Security.php
new file mode 100644
index 0000000..635f8b7
--- /dev/null
+++ b/app/Config/Security.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+class Security extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * CSRF Protection Method
+ * --------------------------------------------------------------------------
+ *
+ * Protection Method for Cross Site Request Forgery protection.
+ *
+ * @var string 'cookie' or 'session'
+ */
+ public string $csrfProtection = 'cookie';
+
+ /**
+ * --------------------------------------------------------------------------
+ * CSRF Token Randomization
+ * --------------------------------------------------------------------------
+ *
+ * Randomize the CSRF Token for added security.
+ */
+ public bool $tokenRandomize = false;
+
+ /**
+ * --------------------------------------------------------------------------
+ * CSRF Token Name
+ * --------------------------------------------------------------------------
+ *
+ * Token name for Cross Site Request Forgery protection.
+ */
+ public string $tokenName = 'csrf_test_name';
+
+ /**
+ * --------------------------------------------------------------------------
+ * CSRF Header Name
+ * --------------------------------------------------------------------------
+ *
+ * Header name for Cross Site Request Forgery protection.
+ */
+ public string $headerName = 'X-CSRF-TOKEN';
+
+ /**
+ * --------------------------------------------------------------------------
+ * CSRF Cookie Name
+ * --------------------------------------------------------------------------
+ *
+ * Cookie name for Cross Site Request Forgery protection.
+ */
+ public string $cookieName = 'csrf_cookie_name';
+
+ /**
+ * --------------------------------------------------------------------------
+ * CSRF Expires
+ * --------------------------------------------------------------------------
+ *
+ * Expiration time for Cross Site Request Forgery protection cookie.
+ *
+ * Defaults to two hours (in seconds).
+ */
+ public int $expires = 7200;
+
+ /**
+ * --------------------------------------------------------------------------
+ * CSRF Regenerate
+ * --------------------------------------------------------------------------
+ *
+ * Regenerate CSRF Token on every submission.
+ */
+ public bool $regenerate = true;
+
+ /**
+ * --------------------------------------------------------------------------
+ * CSRF Redirect
+ * --------------------------------------------------------------------------
+ *
+ * Redirect to previous page with error on failure.
+ *
+ * @see https://codeigniter4.github.io/userguide/libraries/security.html#redirection-on-failure
+ */
+ public bool $redirect = (ENVIRONMENT === 'production');
+}
diff --git a/app/Config/Services.php b/app/Config/Services.php
new file mode 100644
index 0000000..df7c8ad
--- /dev/null
+++ b/app/Config/Services.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseService;
+
+/**
+ * Services Configuration file.
+ *
+ * Services are simply other classes/libraries that the system uses
+ * to do its job. This is used by CodeIgniter to allow the core of the
+ * framework to be swapped out easily without affecting the usage within
+ * the rest of your application.
+ *
+ * This file holds any application-specific services, or service overrides
+ * that you might need. An example has been included with the general
+ * method format you should use for your service methods. For more examples,
+ * see the core Services file at system/Config/Services.php.
+ */
+class Services extends BaseService
+{
+ /*
+ * public static function example($getShared = true)
+ * {
+ * if ($getShared) {
+ * return static::getSharedInstance('example');
+ * }
+ *
+ * return new \CodeIgniter\Example();
+ * }
+ */
+}
diff --git a/app/Config/Session.php b/app/Config/Session.php
new file mode 100644
index 0000000..2491286
--- /dev/null
+++ b/app/Config/Session.php
@@ -0,0 +1,128 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Session\Handlers\BaseHandler;
+use CodeIgniter\Session\Handlers\FileHandler;
+
+class Session extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Session Driver
+ * --------------------------------------------------------------------------
+ *
+ * The session storage driver to use:
+ * - `CodeIgniter\Session\Handlers\ArrayHandler` (for testing)
+ * - `CodeIgniter\Session\Handlers\FileHandler`
+ * - `CodeIgniter\Session\Handlers\DatabaseHandler`
+ * - `CodeIgniter\Session\Handlers\MemcachedHandler`
+ * - `CodeIgniter\Session\Handlers\RedisHandler`
+ *
+ * @var class-string<BaseHandler>
+ */
+ public string $driver = FileHandler::class;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Session Cookie Name
+ * --------------------------------------------------------------------------
+ *
+ * The session cookie name, must contain only [0-9a-z_-] characters
+ */
+ public string $cookieName = 'ci_session';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Session Expiration
+ * --------------------------------------------------------------------------
+ *
+ * The number of SECONDS you want the session to last.
+ * Setting to 0 (zero) means expire when the browser is closed.
+ */
+ public int $expiration = 7200;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Session Save Path
+ * --------------------------------------------------------------------------
+ *
+ * The location to save sessions to and is driver dependent.
+ *
+ * For the 'files' driver, it's a path to a writable directory.
+ * WARNING: Only absolute paths are supported!
+ *
+ * For the 'database' driver, it's a table name.
+ * Please read up the manual for the format with other session drivers.
+ *
+ * IMPORTANT: You are REQUIRED to set a valid save path!
+ */
+ public string $savePath = WRITEPATH . 'session';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Session Match IP
+ * --------------------------------------------------------------------------
+ *
+ * Whether to match the user's IP address when reading the session data.
+ *
+ * WARNING: If you're using the database driver, don't forget to update
+ * your session table's PRIMARY KEY when changing this setting.
+ */
+ public bool $matchIP = false;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Session Time to Update
+ * --------------------------------------------------------------------------
+ *
+ * How many seconds between CI regenerating the session ID.
+ */
+ public int $timeToUpdate = 300;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Session Regenerate Destroy
+ * --------------------------------------------------------------------------
+ *
+ * Whether to destroy session data associated with the old session ID
+ * when auto-regenerating the session ID. When set to FALSE, the data
+ * will be later deleted by the garbage collector.
+ */
+ public bool $regenerateDestroy = false;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Session Database Group
+ * --------------------------------------------------------------------------
+ *
+ * DB Group for the database session.
+ */
+ public ?string $DBGroup = null;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Lock Retry Interval (microseconds)
+ * --------------------------------------------------------------------------
+ *
+ * This is used for RedisHandler.
+ *
+ * Time (microseconds) to wait if lock cannot be acquired.
+ * The default is 100,000 microseconds (= 0.1 seconds).
+ */
+ public int $lockRetryInterval = 100_000;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Lock Max Retries
+ * --------------------------------------------------------------------------
+ *
+ * This is used for RedisHandler.
+ *
+ * Maximum number of lock acquisition attempts.
+ * The default is 300 times. That is lock timeout is about 30 (0.1 * 300)
+ * seconds.
+ */
+ public int $lockMaxRetries = 300;
+}
diff --git a/app/Config/Toolbar.php b/app/Config/Toolbar.php
new file mode 100644
index 0000000..968653e
--- /dev/null
+++ b/app/Config/Toolbar.php
@@ -0,0 +1,147 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Debug\Toolbar\Collectors\Database;
+use CodeIgniter\Debug\Toolbar\Collectors\Events;
+use CodeIgniter\Debug\Toolbar\Collectors\Files;
+use CodeIgniter\Debug\Toolbar\Collectors\Logs;
+use CodeIgniter\Debug\Toolbar\Collectors\Routes;
+use CodeIgniter\Debug\Toolbar\Collectors\Timers;
+use CodeIgniter\Debug\Toolbar\Collectors\Views;
+
+/**
+ * --------------------------------------------------------------------------
+ * Debug Toolbar
+ * --------------------------------------------------------------------------
+ *
+ * The Debug Toolbar provides a way to see information about the performance
+ * and state of your application during that page display. By default it will
+ * NOT be displayed under production environments, and will only display if
+ * `CI_DEBUG` is true, since if it's not, there's not much to display anyway.
+ */
+class Toolbar extends BaseConfig
+{
+ /**
+ * --------------------------------------------------------------------------
+ * Toolbar Collectors
+ * --------------------------------------------------------------------------
+ *
+ * List of toolbar collectors that will be called when Debug Toolbar
+ * fires up and collects data from.
+ *
+ * @var list<class-string>
+ */
+ public array $collectors = [
+ Timers::class,
+ Database::class,
+ Logs::class,
+ Views::class,
+ // \CodeIgniter\Debug\Toolbar\Collectors\Cache::class,
+ Files::class,
+ Routes::class,
+ Events::class,
+ ];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Collect Var Data
+ * --------------------------------------------------------------------------
+ *
+ * If set to false var data from the views will not be collected. Useful to
+ * avoid high memory usage when there are lots of data passed to the view.
+ */
+ public bool $collectVarData = true;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Max History
+ * --------------------------------------------------------------------------
+ *
+ * `$maxHistory` sets a limit on the number of past requests that are stored,
+ * helping to conserve file space used to store them. You can set it to
+ * 0 (zero) to not have any history stored, or -1 for unlimited history.
+ */
+ public int $maxHistory = 20;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Toolbar Views Path
+ * --------------------------------------------------------------------------
+ *
+ * The full path to the the views that are used by the toolbar.
+ * This MUST have a trailing slash.
+ */
+ public string $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/';
+
+ /**
+ * --------------------------------------------------------------------------
+ * Max Queries
+ * --------------------------------------------------------------------------
+ *
+ * If the Database Collector is enabled, it will log every query that the
+ * the system generates so they can be displayed on the toolbar's timeline
+ * and in the query log. This can lead to memory issues in some instances
+ * with hundreds of queries.
+ *
+ * `$maxQueries` defines the maximum amount of queries that will be stored.
+ */
+ public int $maxQueries = 100;
+
+ /**
+ * --------------------------------------------------------------------------
+ * Watched Directories
+ * --------------------------------------------------------------------------
+ *
+ * Contains an array of directories that will be watched for changes and
+ * used to determine if the hot-reload feature should reload the page or not.
+ * We restrict the values to keep performance as high as possible.
+ *
+ * NOTE: The ROOTPATH will be prepended to all values.
+ *
+ * @var list<string>
+ */
+ public array $watchedDirectories = [
+ 'app',
+ ];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Watched File Extensions
+ * --------------------------------------------------------------------------
+ *
+ * Contains an array of file extensions that will be watched for changes and
+ * used to determine if the hot-reload feature should reload the page or not.
+ *
+ * @var list<string>
+ */
+ public array $watchedExtensions = [
+ 'php', 'css', 'js', 'html', 'svg', 'json', 'env',
+ ];
+
+ /**
+ * --------------------------------------------------------------------------
+ * Ignored HTTP Headers
+ * --------------------------------------------------------------------------
+ *
+ * CodeIgniter Debug Toolbar normally injects HTML and JavaScript into every
+ * HTML response. This is correct for full page loads, but it breaks requests
+ * that expect only a clean HTML fragment.
+ *
+ * Libraries like HTMX, Unpoly, and Hotwire (Turbo) update parts of the page or
+ * manage navigation on the client side. Injecting the Debug Toolbar into their
+ * responses can cause invalid HTML, duplicated scripts, or JavaScript errors
+ * (such as infinite loops or "Maximum call stack size exceeded").
+ *
+ * Any request containing one of the following headers is treated as a
+ * client-managed or partial request, and the Debug Toolbar injection is skipped.
+ *
+ * @var array<string, string|null>
+ */
+ public array $disableOnHeaders = [
+ 'X-Requested-With' => 'xmlhttprequest', // AJAX requests
+ 'HX-Request' => 'true', // HTMX requests
+ 'X-Up-Version' => null, // Unpoly partial requests
+ ];
+}
diff --git a/app/Config/UserAgents.php b/app/Config/UserAgents.php
new file mode 100644
index 0000000..8ddfa05
--- /dev/null
+++ b/app/Config/UserAgents.php
@@ -0,0 +1,262 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+
+/**
+ * -------------------------------------------------------------------
+ * User Agents
+ * -------------------------------------------------------------------
+ *
+ * This file contains four arrays of user agent data. It is used by the
+ * User Agent Class to help identify browser, platform, robot, and
+ * mobile device data. The array keys are used to identify the device
+ * and the array values are used to set the actual name of the item.
+ */
+class UserAgents extends BaseConfig
+{
+ /**
+ * -------------------------------------------------------------------
+ * OS Platforms
+ * -------------------------------------------------------------------
+ *
+ * @var array<string, string>
+ */
+ public array $platforms = [
+ 'windows nt 10.0' => 'Windows 10',
+ 'windows nt 6.3' => 'Windows 8.1',
+ 'windows nt 6.2' => 'Windows 8',
+ 'windows nt 6.1' => 'Windows 7',
+ 'windows nt 6.0' => 'Windows Vista',
+ 'windows nt 5.2' => 'Windows 2003',
+ 'windows nt 5.1' => 'Windows XP',
+ 'windows nt 5.0' => 'Windows 2000',
+ 'windows nt 4.0' => 'Windows NT 4.0',
+ 'winnt4.0' => 'Windows NT 4.0',
+ 'winnt 4.0' => 'Windows NT',
+ 'winnt' => 'Windows NT',
+ 'windows 98' => 'Windows 98',
+ 'win98' => 'Windows 98',
+ 'windows 95' => 'Windows 95',
+ 'win95' => 'Windows 95',
+ 'windows phone' => 'Windows Phone',
+ 'windows' => 'Unknown Windows OS',
+ 'android' => 'Android',
+ 'blackberry' => 'BlackBerry',
+ 'iphone' => 'iOS',
+ 'ipad' => 'iOS',
+ 'ipod' => 'iOS',
+ 'os x' => 'Mac OS X',
+ 'ppc mac' => 'Power PC Mac',
+ 'freebsd' => 'FreeBSD',
+ 'ppc' => 'Macintosh',
+ 'linux' => 'Linux',
+ 'debian' => 'Debian',
+ 'sunos' => 'Sun Solaris',
+ 'beos' => 'BeOS',
+ 'apachebench' => 'ApacheBench',
+ 'aix' => 'AIX',
+ 'irix' => 'Irix',
+ 'osf' => 'DEC OSF',
+ 'hp-ux' => 'HP-UX',
+ 'netbsd' => 'NetBSD',
+ 'bsdi' => 'BSDi',
+ 'openbsd' => 'OpenBSD',
+ 'gnu' => 'GNU/Linux',
+ 'unix' => 'Unknown Unix OS',
+ 'symbian' => 'Symbian OS',
+ ];
+
+ /**
+ * -------------------------------------------------------------------
+ * Browsers
+ * -------------------------------------------------------------------
+ *
+ * The order of this array should NOT be changed. Many browsers return
+ * multiple browser types so we want to identify the subtype first.
+ *
+ * @var array<string, string>
+ */
+ public array $browsers = [
+ 'OPR' => 'Opera',
+ 'Flock' => 'Flock',
+ 'Edge' => 'Spartan',
+ 'Edg' => 'Edge',
+ 'Chrome' => 'Chrome',
+ // Opera 10+ always reports Opera/9.80 and appends Version/<real version> to the user agent string
+ 'Opera.*?Version' => 'Opera',
+ 'Opera' => 'Opera',
+ 'MSIE' => 'Internet Explorer',
+ 'Internet Explorer' => 'Internet Explorer',
+ 'Trident.* rv' => 'Internet Explorer',
+ 'Shiira' => 'Shiira',
+ 'Firefox' => 'Firefox',
+ 'Chimera' => 'Chimera',
+ 'Phoenix' => 'Phoenix',
+ 'Firebird' => 'Firebird',
+ 'Camino' => 'Camino',
+ 'Netscape' => 'Netscape',
+ 'OmniWeb' => 'OmniWeb',
+ 'Safari' => 'Safari',
+ 'Mozilla' => 'Mozilla',
+ 'Konqueror' => 'Konqueror',
+ 'icab' => 'iCab',
+ 'Lynx' => 'Lynx',
+ 'Links' => 'Links',
+ 'hotjava' => 'HotJava',
+ 'amaya' => 'Amaya',
+ 'IBrowse' => 'IBrowse',
+ 'Maxthon' => 'Maxthon',
+ 'Ubuntu' => 'Ubuntu Web Browser',
+ 'Vivaldi' => 'Vivaldi',
+ ];
+
+ /**
+ * -------------------------------------------------------------------
+ * Mobiles
+ * -------------------------------------------------------------------
+ *
+ * @var array<string, string>
+ */
+ public array $mobiles = [
+ // legacy array, old values commented out
+ 'mobileexplorer' => 'Mobile Explorer',
+ // 'openwave' => 'Open Wave',
+ // 'opera mini' => 'Opera Mini',
+ // 'operamini' => 'Opera Mini',
+ // 'elaine' => 'Palm',
+ 'palmsource' => 'Palm',
+ // 'digital paths' => 'Palm',
+ // 'avantgo' => 'Avantgo',
+ // 'xiino' => 'Xiino',
+ 'palmscape' => 'Palmscape',
+ // 'nokia' => 'Nokia',
+ // 'ericsson' => 'Ericsson',
+ // 'blackberry' => 'BlackBerry',
+ // 'motorola' => 'Motorola'
+
+ // Phones and Manufacturers
+ 'motorola' => 'Motorola',
+ 'nokia' => 'Nokia',
+ 'palm' => 'Palm',
+ 'iphone' => 'Apple iPhone',
+ 'ipad' => 'iPad',
+ 'ipod' => 'Apple iPod Touch',
+ 'sony' => 'Sony Ericsson',
+ 'ericsson' => 'Sony Ericsson',
+ 'blackberry' => 'BlackBerry',
+ 'cocoon' => 'O2 Cocoon',
+ 'blazer' => 'Treo',
+ 'lg' => 'LG',
+ 'amoi' => 'Amoi',
+ 'xda' => 'XDA',
+ 'mda' => 'MDA',
+ 'vario' => 'Vario',
+ 'htc' => 'HTC',
+ 'samsung' => 'Samsung',
+ 'sharp' => 'Sharp',
+ 'sie-' => 'Siemens',
+ 'alcatel' => 'Alcatel',
+ 'benq' => 'BenQ',
+ 'ipaq' => 'HP iPaq',
+ 'mot-' => 'Motorola',
+ 'playstation portable' => 'PlayStation Portable',
+ 'playstation 3' => 'PlayStation 3',
+ 'playstation vita' => 'PlayStation Vita',
+ 'hiptop' => 'Danger Hiptop',
+ 'nec-' => 'NEC',
+ 'panasonic' => 'Panasonic',
+ 'philips' => 'Philips',
+ 'sagem' => 'Sagem',
+ 'sanyo' => 'Sanyo',
+ 'spv' => 'SPV',
+ 'zte' => 'ZTE',
+ 'sendo' => 'Sendo',
+ 'nintendo dsi' => 'Nintendo DSi',
+ 'nintendo ds' => 'Nintendo DS',
+ 'nintendo 3ds' => 'Nintendo 3DS',
+ 'wii' => 'Nintendo Wii',
+ 'open web' => 'Open Web',
+ 'openweb' => 'OpenWeb',
+
+ // Operating Systems
+ 'android' => 'Android',
+ 'symbian' => 'Symbian',
+ 'SymbianOS' => 'SymbianOS',
+ 'elaine' => 'Palm',
+ 'series60' => 'Symbian S60',
+ 'windows ce' => 'Windows CE',
+
+ // Browsers
+ 'obigo' => 'Obigo',
+ 'netfront' => 'Netfront Browser',
+ 'openwave' => 'Openwave Browser',
+ 'mobilexplorer' => 'Mobile Explorer',
+ 'operamini' => 'Opera Mini',
+ 'opera mini' => 'Opera Mini',
+ 'opera mobi' => 'Opera Mobile',
+ 'fennec' => 'Firefox Mobile',
+
+ // Other
+ 'digital paths' => 'Digital Paths',
+ 'avantgo' => 'AvantGo',
+ 'xiino' => 'Xiino',
+ 'novarra' => 'Novarra Transcoder',
+ 'vodafone' => 'Vodafone',
+ 'docomo' => 'NTT DoCoMo',
+ 'o2' => 'O2',
+
+ // Fallback
+ 'mobile' => 'Generic Mobile',
+ 'wireless' => 'Generic Mobile',
+ 'j2me' => 'Generic Mobile',
+ 'midp' => 'Generic Mobile',
+ 'cldc' => 'Generic Mobile',
+ 'up.link' => 'Generic Mobile',
+ 'up.browser' => 'Generic Mobile',
+ 'smartphone' => 'Generic Mobile',
+ 'cellphone' => 'Generic Mobile',
+ ];
+
+ /**
+ * -------------------------------------------------------------------
+ * Robots
+ * -------------------------------------------------------------------
+ *
+ * There are hundred of bots but these are the most common.
+ *
+ * @var array<string, string>
+ */
+ public array $robots = [
+ 'googlebot' => 'Googlebot',
+ 'google-pagerenderer' => 'Google Page Renderer',
+ 'google-read-aloud' => 'Google Read Aloud',
+ 'google-safety' => 'Google Safety Bot',
+ 'msnbot' => 'MSNBot',
+ 'baiduspider' => 'Baiduspider',
+ 'bingbot' => 'Bing',
+ 'bingpreview' => 'BingPreview',
+ 'slurp' => 'Inktomi Slurp',
+ 'yahoo' => 'Yahoo',
+ 'ask jeeves' => 'Ask Jeeves',
+ 'fastcrawler' => 'FastCrawler',
+ 'infoseek' => 'InfoSeek Robot 1.0',
+ 'lycos' => 'Lycos',
+ 'yandex' => 'YandexBot',
+ 'mediapartners-google' => 'MediaPartners Google',
+ 'CRAZYWEBCRAWLER' => 'Crazy Webcrawler',
+ 'adsbot-google' => 'AdsBot Google',
+ 'feedfetcher-google' => 'Feedfetcher Google',
+ 'curious george' => 'Curious George',
+ 'ia_archiver' => 'Alexa Crawler',
+ 'MJ12bot' => 'Majestic-12',
+ 'Uptimebot' => 'Uptimebot',
+ 'duckduckbot' => 'DuckDuckBot',
+ 'sogou' => 'Sogou Spider',
+ 'exabot' => 'Exabot',
+ 'bot' => 'Generic Bot',
+ 'crawler' => 'Generic Crawler',
+ 'spider' => 'Generic Spider',
+ ];
+}
diff --git a/app/Config/Validation.php b/app/Config/Validation.php
new file mode 100644
index 0000000..6342dbb
--- /dev/null
+++ b/app/Config/Validation.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\BaseConfig;
+use CodeIgniter\Validation\StrictRules\CreditCardRules;
+use CodeIgniter\Validation\StrictRules\FileRules;
+use CodeIgniter\Validation\StrictRules\FormatRules;
+use CodeIgniter\Validation\StrictRules\Rules;
+
+class Validation extends BaseConfig
+{
+ // --------------------------------------------------------------------
+ // Setup
+ // --------------------------------------------------------------------
+
+ /**
+ * Stores the classes that contain the
+ * rules that are available.
+ *
+ * @var list<string>
+ */
+ public array $ruleSets = [
+ Rules::class,
+ FormatRules::class,
+ FileRules::class,
+ CreditCardRules::class,
+ ];
+
+ /**
+ * Specifies the views that are used to display the
+ * errors.
+ *
+ * @var array<string, string>
+ */
+ public array $templates = [
+ 'list' => 'CodeIgniter\Validation\Views\list',
+ 'single' => 'CodeIgniter\Validation\Views\single',
+ ];
+
+ // --------------------------------------------------------------------
+ // Rules
+ // --------------------------------------------------------------------
+}
diff --git a/app/Config/View.php b/app/Config/View.php
new file mode 100644
index 0000000..b52d980
--- /dev/null
+++ b/app/Config/View.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace Config;
+
+use CodeIgniter\Config\View as BaseView;
+use CodeIgniter\View\ViewDecoratorInterface;
+
+class View extends BaseView
+{
+ /**
+ * When false, the view method will clear the data between each
+ * call. This keeps your data safe and ensures there is no accidental
+ * leaking between calls, so you would need to explicitly pass the data
+ * to each view. You might prefer to have the data stick around between
+ * calls so that it is available to all views. If that is the case,
+ * set $saveData to true.
+ *
+ * @var bool
+ */
+ public $saveData = true;
+
+ /**
+ * Parser Filters map a filter name with any PHP callable. When the
+ * Parser prepares a variable for display, it will chain it
+ * through the filters in the order defined, inserting any parameters.
+ * To prevent potential abuse, all filters MUST be defined here
+ * in order for them to be available for use within the Parser.
+ *
+ * Examples:
+ * { title|esc(js) }
+ * { created_on|date(Y-m-d)|esc(attr) }
+ *
+ * @var array<string, (callable(mixed): mixed)&string>
+ */
+ public $filters = [];
+
+ /**
+ * Parser Plugins provide a way to extend the functionality provided
+ * by the core Parser by creating aliases that will be replaced with
+ * any callable. Can be single or tag pair.
+ *
+ * @var array<string, (callable(mixed...): mixed)|((callable(mixed...): mixed)&string)|list<(callable(mixed...): mixed)&string>>
+ */
+ public $plugins = [];
+
+ /**
+ * View Decorators are class methods that will be run in sequence to
+ * have a chance to alter the generated output just prior to caching
+ * the results.
+ *
+ * All classes must implement CodeIgniter\View\ViewDecoratorInterface
+ *
+ * @var list<class-string<ViewDecoratorInterface>>
+ */
+ public array $decorators = [];
+
+ /**
+ * Subdirectory within app/Views for namespaced view overrides.
+ *
+ * Namespaced views will be searched in:
+ *
+ * app/Views/{$appOverridesFolder}/{Namespace}/{view_path}.{php|html...}
+ *
+ * This allows application-level overrides for package or module views
+ * without modifying vendor source files.
+ *
+ * Examples:
+ * 'overrides' -> app/Views/overrides/Example/Blog/post/card.php
+ * 'vendor' -> app/Views/vendor/Example/Blog/post/card.php
+ * '' -> app/Views/Example/Blog/post/card.php (direct mapping)
+ */
+ public string $appOverridesFolder = 'overrides';
+}
diff --git a/app/Config/WorkerMode.php b/app/Config/WorkerMode.php
new file mode 100644
index 0000000..fd8b494
--- /dev/null
+++ b/app/Config/WorkerMode.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Config;
+
+/**
+ * This configuration controls how CodeIgniter behaves when running
+ * in worker mode (with FrankenPHP).
+ */
+class WorkerMode
+{
+ /**
+ * Persistent Services
+ *
+ * List of service names that should persist across requests.
+ * These services will NOT be reset between requests.
+ *
+ * Services not in this list will be reset for each request to prevent
+ * state leakage.
+ *
+ * Recommended persistent services:
+ * - `autoloader`: PSR-4 autoloading configuration
+ * - `locator`: File locator
+ * - `exceptions`: Exception handler
+ * - `commands`: CLI commands registry
+ * - `codeigniter`: Main application instance
+ * - `superglobals`: Superglobals wrapper
+ * - `routes`: Router configuration
+ * - `cache`: Cache instance
+ *
+ * @var list<string>
+ */
+ public array $persistentServices = [
+ 'autoloader',
+ 'locator',
+ 'exceptions',
+ 'commands',
+ 'codeigniter',
+ 'superglobals',
+ 'routes',
+ 'cache',
+ ];
+
+ /**
+ * Reset Event Listeners
+ *
+ * List of event names whose listeners should be removed between requests.
+ * Use this if you register event listeners inside other event callbacks
+ * (rather than at the top level of Config/Events.php), which would cause
+ * them to accumulate across requests in worker mode.
+ *
+ * @var list<string>
+ */
+ public array $resetEventListeners = [];
+
+ /**
+ * Force Garbage Collection
+ *
+ * Whether to force garbage collection after each request.
+ * Helps prevent memory leaks at a small performance cost.
+ */
+ public bool $forceGarbageCollection = true;
+}
diff --git a/app/Controllers/BaseController.php b/app/Controllers/BaseController.php
new file mode 100644
index 0000000..ab45a77
--- /dev/null
+++ b/app/Controllers/BaseController.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace App\Controllers;
+
+use CodeIgniter\Controller;
+use CodeIgniter\HTTP\RequestInterface;
+use CodeIgniter\HTTP\ResponseInterface;
+use Psr\Log\LoggerInterface;
+
+/**
+ * BaseController provides a convenient place for loading components
+ * and performing functions that are needed by all your controllers.
+ *
+ * Extend this class in any new controllers:
+ * ```
+ * class Home extends BaseController
+ * ```
+ *
+ * For security, be sure to declare any new methods as protected or private.
+ */
+abstract class BaseController extends Controller
+{
+ /**
+ * Be sure to declare properties for any property fetch you initialized.
+ * The creation of dynamic property is deprecated in PHP 8.2.
+ */
+
+ // protected $session;
+
+ /**
+ * @return void
+ */
+ public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
+ {
+ // Load here all helpers you want to be available in your controllers that extend BaseController.
+ // Caution: Do not put the this below the parent::initController() call below.
+ // $this->helpers = ['form', 'url'];
+
+ // Caution: Do not edit this line.
+ parent::initController($request, $response, $logger);
+
+ // Preload any models, libraries, etc, here.
+ // $this->session = service('session');
+ }
+}
diff --git a/app/Controllers/Home.php b/app/Controllers/Home.php
new file mode 100644
index 0000000..5934333
--- /dev/null
+++ b/app/Controllers/Home.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace App\Controllers;
+
+class Home extends BaseController
+{
+ public function index(): string
+ {
+ return view('welcome_message');
+ }
+}
diff --git a/app/Database/Migrations/.gitkeep b/app/Database/Migrations/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Database/Seeds/.gitkeep b/app/Database/Seeds/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Filters/.gitkeep b/app/Filters/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Helpers/.gitkeep b/app/Helpers/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Language/.gitkeep b/app/Language/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Language/en/Validation.php b/app/Language/en/Validation.php
new file mode 100644
index 0000000..54d1e7a
--- /dev/null
+++ b/app/Language/en/Validation.php
@@ -0,0 +1,4 @@
+<?php
+
+// override core en language system validation or define your own en language validation message
+return [];
diff --git a/app/Libraries/.gitkeep b/app/Libraries/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Models/.gitkeep b/app/Models/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/ThirdParty/.gitkeep b/app/ThirdParty/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/Views/errors/cli/error_404.php b/app/Views/errors/cli/error_404.php
new file mode 100644
index 0000000..456ea3e
--- /dev/null
+++ b/app/Views/errors/cli/error_404.php
@@ -0,0 +1,7 @@
+<?php
+
+use CodeIgniter\CLI\CLI;
+
+CLI::error('ERROR: ' . $code);
+CLI::write($message);
+CLI::newLine();
diff --git a/app/Views/errors/cli/error_exception.php b/app/Views/errors/cli/error_exception.php
new file mode 100644
index 0000000..624f3b5
--- /dev/null
+++ b/app/Views/errors/cli/error_exception.php
@@ -0,0 +1,65 @@
+<?php
+
+use CodeIgniter\CLI\CLI;
+
+// The main Exception
+CLI::write('[' . $exception::class . ']', 'light_gray', 'red');
+CLI::write($message);
+CLI::write('at ' . CLI::color(clean_path($exception->getFile()) . ':' . $exception->getLine(), 'green'));
+CLI::newLine();
+
+$last = $exception;
+
+while ($prevException = $last->getPrevious()) {
+ $last = $prevException;
+
+ CLI::write(' Caused by:');
+ CLI::write(' [' . $prevException::class . ']', 'red');
+ CLI::write(' ' . $prevException->getMessage());
+ CLI::write(' at ' . CLI::color(clean_path($prevException->getFile()) . ':' . $prevException->getLine(), 'green'));
+ CLI::newLine();
+}
+
+// The backtrace
+if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) {
+ $backtraces = $last->getTrace();
+
+ if ($backtraces) {
+ CLI::write('Backtrace:', 'green');
+ }
+
+ foreach ($backtraces as $i => $error) {
+ $padFile = ' '; // 4 spaces
+ $padClass = ' '; // 7 spaces
+ $c = str_pad($i + 1, 3, ' ', STR_PAD_LEFT);
+
+ if (isset($error['file'])) {
+ $filepath = clean_path($error['file']) . ':' . $error['line'];
+
+ CLI::write($c . $padFile . CLI::color($filepath, 'yellow'));
+ } else {
+ CLI::write($c . $padFile . CLI::color('[internal function]', 'yellow'));
+ }
+
+ $function = '';
+
+ if (isset($error['class'])) {
+ $type = ($error['type'] === '->') ? '()' . $error['type'] : $error['type'];
+ $function .= $padClass . $error['class'] . $type . $error['function'];
+ } elseif (! isset($error['class']) && isset($error['function'])) {
+ $function .= $padClass . $error['function'];
+ }
+
+ $args = implode(', ', array_map(static fn ($value): string => match (true) {
+ is_object($value) => 'Object(' . $value::class . ')',
+ is_array($value) => $value !== [] ? '[...]' : '[]',
+ $value === null => 'null', // return the lowercased version
+ default => var_export($value, true),
+ }, array_values($error['args'] ?? [])));
+
+ $function .= '(' . $args . ')';
+
+ CLI::write($function);
+ CLI::newLine();
+ }
+}
diff --git a/app/Views/errors/cli/production.php b/app/Views/errors/cli/production.php
new file mode 100644
index 0000000..7db744e
--- /dev/null
+++ b/app/Views/errors/cli/production.php
@@ -0,0 +1,5 @@
+<?php
+
+// On the CLI, we still want errors in productions
+// so just use the exception template.
+include __DIR__ . '/error_exception.php';
diff --git a/app/Views/errors/html/debug.css b/app/Views/errors/html/debug.css
new file mode 100644
index 0000000..b8539a4
--- /dev/null
+++ b/app/Views/errors/html/debug.css
@@ -0,0 +1,194 @@
+:root {
+ --main-bg-color: #fff;
+ --main-text-color: #555;
+ --dark-text-color: #222;
+ --light-text-color: #c7c7c7;
+ --brand-primary-color: #DC4814;
+ --light-bg-color: #ededee;
+ --dark-bg-color: #404040;
+}
+
+body {
+ height: 100%;
+ background: var(--main-bg-color);
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
+ color: var(--main-text-color);
+ font-weight: 300;
+ margin: 0;
+ padding: 0;
+}
+h1 {
+ font-weight: lighter;
+ font-size: 3rem;
+ color: var(--dark-text-color);
+ margin: 0;
+}
+h1.headline {
+ margin-top: 20%;
+ font-size: 5rem;
+}
+.text-center {
+ text-align: center;
+}
+p.lead {
+ font-size: 1.6rem;
+}
+.container {
+ max-width: 75rem;
+ margin: 0 auto;
+ padding: 1rem;
+}
+.header {
+ background: var(--light-bg-color);
+ color: var(--dark-text-color);
+ margin-top: 2.17rem;
+}
+.header .container {
+ padding: 1rem;
+}
+.header h1 {
+ font-size: 2.5rem;
+ font-weight: 500;
+}
+.header p {
+ font-size: 1.2rem;
+ margin: 0;
+ line-height: 2.5;
+}
+.header a {
+ color: var(--brand-primary-color);
+ margin-left: 2rem;
+ display: none;
+ text-decoration: none;
+}
+.header:hover a {
+ display: inline;
+}
+
+.environment {
+ background: var(--brand-primary-color);
+ color: var(--main-bg-color);
+ text-align: center;
+ padding: calc(4px + 0.2083vw);
+ width: 100%;
+ top: 0;
+ position: fixed;
+}
+
+.source {
+ background: #343434;
+ color: var(--light-text-color);
+ padding: 0.5em 1em;
+ border-radius: 5px;
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+ font-size: 0.85rem;
+ margin: 0;
+ overflow-x: scroll;
+}
+.source span.line {
+ line-height: 1.4;
+}
+.source span.line .number {
+ color: #666;
+}
+.source .line .highlight {
+ display: block;
+ background: var(--dark-text-color);
+ color: var(--light-text-color);
+}
+.source span.highlight .number {
+ color: #fff;
+}
+
+.tabs {
+ list-style: none;
+ list-style-position: inside;
+ margin: 0;
+ padding: 0;
+ margin-bottom: -1px;
+}
+.tabs li {
+ display: inline;
+}
+.tabs a:link,
+.tabs a:visited {
+ padding: 0 1rem;
+ line-height: 2.7;
+ text-decoration: none;
+ color: var(--dark-text-color);
+ background: var(--light-bg-color);
+ border: 1px solid rgba(0,0,0,0.15);
+ border-bottom: 0;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+ display: inline-block;
+}
+.tabs a:hover {
+ background: var(--light-bg-color);
+ border-color: rgba(0,0,0,0.15);
+}
+.tabs a.active {
+ background: var(--main-bg-color);
+ color: var(--main-text-color);
+}
+.tab-content {
+ background: var(--main-bg-color);
+ border: 1px solid rgba(0,0,0,0.15);
+}
+.content {
+ padding: 1rem;
+}
+.hide {
+ display: none;
+}
+
+.alert {
+ margin-top: 2rem;
+ display: block;
+ text-align: center;
+ line-height: 3.0;
+ background: #d9edf7;
+ border: 1px solid #bcdff1;
+ border-radius: 5px;
+ color: #31708f;
+}
+
+table {
+ width: 100%;
+ overflow: hidden;
+}
+th {
+ text-align: left;
+ border-bottom: 1px solid #e7e7e7;
+ padding-bottom: 0.5rem;
+}
+td {
+ padding: 0.2rem 0.5rem 0.2rem 0;
+}
+tr:hover td {
+ background: #f1f1f1;
+}
+td pre {
+ white-space: pre-wrap;
+}
+
+.trace a {
+ color: inherit;
+}
+.trace table {
+ width: auto;
+}
+.trace tr td:first-child {
+ min-width: 5em;
+ font-weight: bold;
+}
+.trace td {
+ background: var(--light-bg-color);
+ padding: 0 1rem;
+}
+.trace td pre {
+ margin: 0;
+}
+.args {
+ display: none;
+}
diff --git a/app/Views/errors/html/debug.js b/app/Views/errors/html/debug.js
new file mode 100644
index 0000000..99199ca
--- /dev/null
+++ b/app/Views/errors/html/debug.js
@@ -0,0 +1,116 @@
+var tabLinks = new Array();
+var contentDivs = new Array();
+
+function init()
+{
+ // Grab the tab links and content divs from the page
+ var tabListItems = document.getElementById('tabs').childNodes;
+ console.log(tabListItems);
+ for (var i = 0; i < tabListItems.length; i ++)
+ {
+ if (tabListItems[i].nodeName == "LI")
+ {
+ var tabLink = getFirstChildWithTagName(tabListItems[i], 'A');
+ var id = getHash(tabLink.getAttribute('href'));
+ tabLinks[id] = tabLink;
+ contentDivs[id] = document.getElementById(id);
+ }
+ }
+
+ // Assign onclick events to the tab links, and
+ // highlight the first tab
+ var i = 0;
+
+ for (var id in tabLinks)
+ {
+ tabLinks[id].onclick = showTab;
+ tabLinks[id].onfocus = function () {
+ this.blur()
+ };
+ if (i == 0)
+ {
+ tabLinks[id].className = 'active';
+ }
+ i ++;
+ }
+
+ // Hide all content divs except the first
+ var i = 0;
+
+ for (var id in contentDivs)
+ {
+ if (i != 0)
+ {
+ console.log(contentDivs[id]);
+ contentDivs[id].className = 'content hide';
+ }
+ i ++;
+ }
+}
+
+function showTab()
+{
+ var selectedId = getHash(this.getAttribute('href'));
+
+ // Highlight the selected tab, and dim all others.
+ // Also show the selected content div, and hide all others.
+ for (var id in contentDivs)
+ {
+ if (id == selectedId)
+ {
+ tabLinks[id].className = 'active';
+ contentDivs[id].className = 'content';
+ }
+ else
+ {
+ tabLinks[id].className = '';
+ contentDivs[id].className = 'content hide';
+ }
+ }
+
+ // Stop the browser following the link
+ return false;
+}
+
+function getFirstChildWithTagName(element, tagName)
+{
+ for (var i = 0; i < element.childNodes.length; i ++)
+ {
+ if (element.childNodes[i].nodeName == tagName)
+ {
+ return element.childNodes[i];
+ }
+ }
+}
+
+function getHash(url)
+{
+ var hashPos = url.lastIndexOf('#');
+ return url.substring(hashPos + 1);
+}
+
+function toggle(elem)
+{
+ elem = document.getElementById(elem);
+
+ if (elem.style && elem.style['display'])
+ {
+ // Only works with the "style" attr
+ var disp = elem.style['display'];
+ }
+ else if (elem.currentStyle)
+ {
+ // For MSIE, naturally
+ var disp = elem.currentStyle['display'];
+ }
+ else if (window.getComputedStyle)
+ {
+ // For most other browsers
+ var disp = document.defaultView.getComputedStyle(elem, null).getPropertyValue('display');
+ }
+
+ // Toggle the state of the "display" style
+ elem.style.display = disp == 'block' ? 'none' : 'block';
+
+ return false;
+}
diff --git a/app/Views/errors/html/error_400.php b/app/Views/errors/html/error_400.php
new file mode 100644
index 0000000..555da04
--- /dev/null
+++ b/app/Views/errors/html/error_400.php
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title><?= lang('Errors.badRequest') ?></title>
+
+ <style>
+ div.logo {
+ height: 200px;
+ width: 155px;
+ display: inline-block;
+ opacity: 0.08;
+ position: absolute;
+ top: 2rem;
+ left: 50%;
+ margin-left: -73px;
+ }
+ body {
+ height: 100%;
+ background: #fafafa;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ color: #777;
+ font-weight: 300;
+ }
+ h1 {
+ font-weight: lighter;
+ letter-spacing: normal;
+ font-size: 3rem;
+ margin-top: 0;
+ margin-bottom: 0;
+ color: #222;
+ }
+ .wrap {
+ max-width: 1024px;
+ margin: 5rem auto;
+ padding: 2rem;
+ background: #fff;
+ text-align: center;
+ border: 1px solid #efefef;
+ border-radius: 0.5rem;
+ position: relative;
+ }
+ pre {
+ white-space: normal;
+ margin-top: 1.5rem;
+ }
+ code {
+ background: #fafafa;
+ border: 1px solid #efefef;
+ padding: 0.5rem 1rem;
+ border-radius: 5px;
+ display: block;
+ }
+ p {
+ margin-top: 1.5rem;
+ }
+ .footer {
+ margin-top: 2rem;
+ border-top: 1px solid #efefef;
+ padding: 1em 2em 0 2em;
+ font-size: 85%;
+ color: #999;
+ }
+ a:active,
+ a:link,
+ a:visited {
+ color: #dd4814;
+ }
+ </style>
+</head>
+<body>
+<div class="wrap">
+ <h1>400</h1>
+
+ <p>
+ <?php if (ENVIRONMENT !== 'production') : ?>
+ <?= nl2br(esc($message)) ?>
+ <?php else : ?>
+ <?= lang('Errors.sorryBadRequest') ?>
+ <?php endif; ?>
+ </p>
+</div>
+</body>
+</html>
diff --git a/app/Views/errors/html/error_404.php b/app/Views/errors/html/error_404.php
new file mode 100644
index 0000000..e506f08
--- /dev/null
+++ b/app/Views/errors/html/error_404.php
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title><?= lang('Errors.pageNotFound') ?></title>
+
+ <style>
+ div.logo {
+ height: 200px;
+ width: 155px;
+ display: inline-block;
+ opacity: 0.08;
+ position: absolute;
+ top: 2rem;
+ left: 50%;
+ margin-left: -73px;
+ }
+ body {
+ height: 100%;
+ background: #fafafa;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ color: #777;
+ font-weight: 300;
+ }
+ h1 {
+ font-weight: lighter;
+ letter-spacing: normal;
+ font-size: 3rem;
+ margin-top: 0;
+ margin-bottom: 0;
+ color: #222;
+ }
+ .wrap {
+ max-width: 1024px;
+ margin: 5rem auto;
+ padding: 2rem;
+ background: #fff;
+ text-align: center;
+ border: 1px solid #efefef;
+ border-radius: 0.5rem;
+ position: relative;
+ }
+ pre {
+ white-space: normal;
+ margin-top: 1.5rem;
+ }
+ code {
+ background: #fafafa;
+ border: 1px solid #efefef;
+ padding: 0.5rem 1rem;
+ border-radius: 5px;
+ display: block;
+ }
+ p {
+ margin-top: 1.5rem;
+ }
+ .footer {
+ margin-top: 2rem;
+ border-top: 1px solid #efefef;
+ padding: 1em 2em 0 2em;
+ font-size: 85%;
+ color: #999;
+ }
+ a:active,
+ a:link,
+ a:visited {
+ color: #dd4814;
+ }
+ </style>
+</head>
+<body>
+ <div class="wrap">
+ <h1>404</h1>
+
+ <p>
+ <?php if (ENVIRONMENT !== 'production') : ?>
+ <?= nl2br(esc($message)) ?>
+ <?php else : ?>
+ <?= lang('Errors.sorryCannotFind') ?>
+ <?php endif; ?>
+ </p>
+ </div>
+</body>
+</html>
diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php
new file mode 100644
index 0000000..6e54b13
--- /dev/null
+++ b/app/Views/errors/html/error_exception.php
@@ -0,0 +1,429 @@
+<?php
+use CodeIgniter\CodeIgniter;
+use CodeIgniter\HTTP\Header;
+
+$errorId = uniqid('error', true);
+?>
+<!doctype html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <meta name="robots" content="noindex">
+
+ <title><?= esc($title) ?></title>
+ <style>
+ <?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
+ </style>
+
+ <script>
+ <?= file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.js') ?>
+ </script>
+</head>
+<body onload="init()">
+
+ <!-- Header -->
+ <div class="header">
+ <div class="environment">
+ Displayed at <?= esc(date('H:i:s')) ?> —
+ PHP: <?= esc(PHP_VERSION) ?> —
+ CodeIgniter: <?= esc(CodeIgniter::CI_VERSION) ?> --
+ Environment: <?= ENVIRONMENT ?>
+ </div>
+ <div class="container">
+ <h1><?= esc($title), esc($exception->getCode() ? ' #' . $exception->getCode() : '') ?></h1>
+ <p>
+ <?= nl2br(esc($exception->getMessage())) ?>
+ <a href="https://www.duckduckgo.com/?q=<?= urlencode($title . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())) ?>"
+ rel="noreferrer" target="_blank">search →</a>
+ </p>
+ </div>
+ </div>
+
+ <!-- Source -->
+ <div class="container">
+ <p><b><?= esc(clean_path($file)) ?></b> at line <b><?= esc($line) ?></b></p>
+
+ <?php if (is_file($file)) : ?>
+ <div class="source">
+ <?= static::highlightFile($file, $line, 15); ?>
+ </div>
+ <?php endif; ?>
+ </div>
+
+ <div class="container">
+ <?php
+ $last = $exception;
+
+while ($prevException = $last->getPrevious()) {
+ $last = $prevException;
+ ?>
+
+ <pre>
+ Caused by:
+ <?= esc($prevException::class), esc($prevException->getCode() ? ' #' . $prevException->getCode() : '') ?>
+
+ <?= nl2br(esc($prevException->getMessage())) ?>
+ <a href="https://www.duckduckgo.com/?q=<?= urlencode($prevException::class . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $prevException->getMessage())) ?>"
+ rel="noreferrer" target="_blank">search →</a>
+ <?= esc(clean_path($prevException->getFile()) . ':' . $prevException->getLine()) ?>
+ </pre>
+
+ <?php
+}
+?>
+ </div>
+
+ <?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) : ?>
+ <div class="container">
+
+ <ul class="tabs" id="tabs">
+ <li><a href="#backtrace">Backtrace</a></li>
+ <li><a href="#server">Server</a></li>
+ <li><a href="#request">Request</a></li>
+ <li><a href="#response">Response</a></li>
+ <li><a href="#files">Files</a></li>
+ <li><a href="#memory">Memory</a></li>
+ </ul>
+
+ <div class="tab-content">
+
+ <!-- Backtrace -->
+ <div class="content" id="backtrace">
+
+ <ol class="trace">
+ <?php foreach ($trace as $index => $row) : ?>
+
+ <li>
+ <p>
+ <!-- Trace info -->
+ <?php if (isset($row['file']) && is_file($row['file'])) : ?>
+ <?php
+ if (isset($row['function']) && in_array($row['function'], ['include', 'include_once', 'require', 'require_once'], true)) {
+ echo esc($row['function'] . ' ' . clean_path($row['file']));
+ } else {
+ echo esc(clean_path($row['file']) . ' : ' . $row['line']);
+ }
+ ?>
+ <?php else: ?>
+ {PHP internal code}
+ <?php endif; ?>
+
+ <!-- Class/Method -->
+ <?php if (isset($row['class'])) : ?>
+ — <?= esc($row['class'] . $row['type'] . $row['function']) ?>
+ <?php if (! empty($row['args'])) : ?>
+ <?php $argsId = $errorId . 'args' . $index ?>
+ ( <a href="#" onclick="return toggle('<?= esc($argsId, 'attr') ?>');">arguments</a> )
+ <div class="args" id="<?= esc($argsId, 'attr') ?>">
+ <table cellspacing="0">
+
+ <?php
+ $params = null;
+ // Reflection by name is not available for closure function
+ if (! str_ends_with($row['function'], '}')) {
+ $mirror = isset($row['class']) ? new ReflectionMethod($row['class'], $row['function']) : new ReflectionFunction($row['function']);
+ $params = $mirror->getParameters();
+ }
+
+ foreach ($row['args'] as $key => $value) : ?>
+ <tr>
+ <td><code><?= esc(isset($params[$key]) ? '$' . $params[$key]->name : "#{$key}") ?></code></td>
+ <td><pre><?= esc(print_r($value, true)) ?></pre></td>
+ </tr>
+ <?php endforeach ?>
+
+ </table>
+ </div>
+ <?php else : ?>
+ ()
+ <?php endif; ?>
+ <?php endif; ?>
+
+ <?php if (! isset($row['class']) && isset($row['function'])) : ?>
+ — <?= esc($row['function']) ?>()
+ <?php endif; ?>
+ </p>
+
+ <!-- Source? -->
+ <?php if (isset($row['file']) && is_file($row['file']) && isset($row['class'])) : ?>
+ <div class="source">
+ <?= static::highlightFile($row['file'], $row['line']) ?>
+ </div>
+ <?php endif; ?>
+ </li>
+
+ <?php endforeach; ?>
+ </ol>
+
+ </div>
+
+ <!-- Server -->
+ <div class="content" id="server">
+ <?php foreach (['_SERVER', '_SESSION'] as $var) : ?>
+ <?php
+ if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
+ continue;
+ } ?>
+
+ <h3>$<?= esc($var) ?></h3>
+
+ <table>
+ <thead>
+ <tr>
+ <th>Key</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($GLOBALS[$var] as $key => $value) : ?>
+ <tr>
+ <td><?= esc($key) ?></td>
+ <td>
+ <?php if (is_string($value)) : ?>
+ <?= esc($value) ?>
+ <?php else: ?>
+ <pre><?= esc(print_r($value, true)) ?></pre>
+ <?php endif; ?>
+ </td>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+ </table>
+
+ <?php endforeach ?>
+
+ <!-- Constants -->
+ <?php $constants = get_defined_constants(true); ?>
+ <?php if (! empty($constants['user'])) : ?>
+ <h3>Constants</h3>
+
+ <table>
+ <thead>
+ <tr>
+ <th>Key</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($constants['user'] as $key => $value) : ?>
+ <tr>
+ <td><?= esc($key) ?></td>
+ <td>
+ <?php if (is_string($value)) : ?>
+ <?= esc($value) ?>
+ <?php else: ?>
+ <pre><?= esc(print_r($value, true)) ?></pre>
+ <?php endif; ?>
+ </td>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+ </table>
+ <?php endif; ?>
+ </div>
+
+ <!-- Request -->
+ <div class="content" id="request">
+ <?php $request = service('request'); ?>
+
+ <table>
+ <tbody>
+ <tr>
+ <td style="width: 10em">Path</td>
+ <td><?= esc($request->getUri()) ?></td>
+ </tr>
+ <tr>
+ <td>HTTP Method</td>
+ <td><?= esc($request->getMethod()) ?></td>
+ </tr>
+ <tr>
+ <td>IP Address</td>
+ <td><?= esc($request->getIPAddress()) ?></td>
+ </tr>
+ <tr>
+ <td style="width: 10em">Is AJAX Request?</td>
+ <td><?= $request->isAJAX() ? 'yes' : 'no' ?></td>
+ </tr>
+ <tr>
+ <td>Is CLI Request?</td>
+ <td><?= $request->isCLI() ? 'yes' : 'no' ?></td>
+ </tr>
+ <tr>
+ <td>Is Secure Request?</td>
+ <td><?= $request->isSecure() ? 'yes' : 'no' ?></td>
+ </tr>
+ <tr>
+ <td>User Agent</td>
+ <td><?= esc($request->getUserAgent()->getAgentString()) ?></td>
+ </tr>
+
+ </tbody>
+ </table>
+
+
+ <?php $empty = true; ?>
+ <?php foreach (['_GET', '_POST', '_COOKIE'] as $var) : ?>
+ <?php
+ if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
+ continue;
+ } ?>
+
+ <?php $empty = false; ?>
+
+ <h3>$<?= esc($var) ?></h3>
+
+ <table style="width: 100%">
+ <thead>
+ <tr>
+ <th>Key</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($GLOBALS[$var] as $key => $value) : ?>
+ <tr>
+ <td><?= esc($key) ?></td>
+ <td>
+ <?php if (is_string($value)) : ?>
+ <?= esc($value) ?>
+ <?php else: ?>
+ <pre><?= esc(print_r($value, true)) ?></pre>
+ <?php endif; ?>
+ </td>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+ </table>
+
+ <?php endforeach ?>
+
+ <?php if ($empty) : ?>
+
+ <div class="alert">
+ No $_GET, $_POST, or $_COOKIE Information to show.
+ </div>
+
+ <?php endif; ?>
+
+ <?php $headers = $request->headers(); ?>
+ <?php if (! empty($headers)) : ?>
+
+ <h3>Headers</h3>
+
+ <table>
+ <thead>
+ <tr>
+ <th>Header</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($headers as $name => $value) : ?>
+ <tr>
+ <td><?= esc($name, 'html') ?></td>
+ <td>
+ <?php
+ if ($value instanceof Header) {
+ echo esc($value->getValueLine(), 'html');
+ } else {
+ foreach ($value as $i => $header) {
+ echo ' (' . $i + 1 . ') ' . esc($header->getValueLine(), 'html');
+ }
+ }
+ ?>
+ </td>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+ </table>
+
+ <?php endif; ?>
+ </div>
+
+ <!-- Response -->
+ <?php
+ $response = service('response');
+$response->setStatusCode(http_response_code());
+?>
+ <div class="content" id="response">
+ <table>
+ <tr>
+ <td style="width: 15em">Response Status</td>
+ <td><?= esc($response->getStatusCode() . ' - ' . $response->getReasonPhrase()) ?></td>
+ </tr>
+ </table>
+
+ <?php $headers = $response->headers(); ?>
+ <?php if (! empty($headers)) : ?>
+ <h3>Headers</h3>
+
+ <table>
+ <thead>
+ <tr>
+ <th>Header</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($headers as $name => $value) : ?>
+ <tr>
+ <td><?= esc($name, 'html') ?></td>
+ <td>
+ <?php
+ if ($value instanceof Header) {
+ echo esc($response->getHeaderLine($name), 'html');
+ } else {
+ foreach ($value as $i => $header) {
+ echo ' (' . $i + 1 . ') ' . esc($header->getValueLine(), 'html');
+ }
+ }
+ ?>
+ </td>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+ </table>
+
+ <?php endif; ?>
+ </div>
+
+ <!-- Files -->
+ <div class="content" id="files">
+ <?php $files = get_included_files(); ?>
+
+ <ol>
+ <?php foreach ($files as $file) :?>
+ <li><?= esc(clean_path($file)) ?></li>
+ <?php endforeach ?>
+ </ol>
+ </div>
+
+ <!-- Memory -->
+ <div class="content" id="memory">
+
+ <table>
+ <tbody>
+ <tr>
+ <td>Memory Usage</td>
+ <td><?= esc(static::describeMemory(memory_get_usage(true))) ?></td>
+ </tr>
+ <tr>
+ <td style="width: 12em">Peak Memory Usage:</td>
+ <td><?= esc(static::describeMemory(memory_get_peak_usage(true))) ?></td>
+ </tr>
+ <tr>
+ <td>Memory Limit:</td>
+ <td><?= esc(ini_get('memory_limit')) ?></td>
+ </tr>
+ </tbody>
+ </table>
+
+ </div>
+
+ </div> <!-- /tab-content -->
+
+ </div> <!-- /container -->
+ <?php endif; ?>
+
+</body>
+</html>
diff --git a/app/Views/errors/html/production.php b/app/Views/errors/html/production.php
new file mode 100644
index 0000000..2f59a8d
--- /dev/null
+++ b/app/Views/errors/html/production.php
@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <meta name="robots" content="noindex">
+
+ <title><?= lang('Errors.whoops') ?></title>
+
+ <style>
+ <?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
+ </style>
+</head>
+<body>
+
+ <div class="container text-center">
+
+ <h1 class="headline"><?= lang('Errors.whoops') ?></h1>
+
+ <p class="lead"><?= lang('Errors.weHitASnag') ?></p>
+
+ </div>
+
+</body>
+
+</html>
diff --git a/app/Views/welcome_message.php b/app/Views/welcome_message.php
new file mode 100644
index 0000000..c18eca3
--- /dev/null
+++ b/app/Views/welcome_message.php
@@ -0,0 +1,331 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Welcome to CodeIgniter 4!</title>
+ <meta name="description" content="The small framework with powerful features">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <link rel="shortcut icon" type="image/png" href="/favicon.ico">
+
+ <!-- STYLES -->
+
+ <style {csp-style-nonce}>
+ * {
+ transition: background-color 300ms ease, color 300ms ease;
+ }
+ *:focus {
+ background-color: rgba(221, 72, 20, .2);
+ outline: none;
+ }
+ html, body {
+ color: rgba(33, 37, 41, 1);
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
+ font-size: 16px;
+ margin: 0;
+ padding: 0;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ text-rendering: optimizeLegibility;
+ }
+ header {
+ background-color: rgba(247, 248, 249, 1);
+ padding: .4rem 0 0;
+ }
+ .menu {
+ padding: .4rem 2rem;
+ }
+ header ul {
+ border-bottom: 1px solid rgba(242, 242, 242, 1);
+ list-style-type: none;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+ text-align: right;
+ }
+ header li {
+ display: inline-block;
+ }
+ header li a {
+ border-radius: 5px;
+ color: rgba(0, 0, 0, .5);
+ display: block;
+ height: 44px;
+ text-decoration: none;
+ }
+ header li.menu-item a {
+ border-radius: 5px;
+ margin: 5px 0;
+ height: 38px;
+ line-height: 36px;
+ padding: .4rem .65rem;
+ text-align: center;
+ }
+ header li.menu-item a:hover,
+ header li.menu-item a:focus {
+ background-color: rgba(221, 72, 20, .2);
+ color: rgba(221, 72, 20, 1);
+ }
+ header .logo {
+ float: left;
+ height: 44px;
+ padding: .4rem .5rem;
+ }
+ header .menu-toggle {
+ display: none;
+ float: right;
+ font-size: 2rem;
+ font-weight: bold;
+ }
+ header .menu-toggle button {
+ background-color: rgba(221, 72, 20, .6);
+ border: none;
+ border-radius: 3px;
+ color: rgba(255, 255, 255, 1);
+ cursor: pointer;
+ font: inherit;
+ font-size: 1.3rem;
+ height: 36px;
+ padding: 0;
+ margin: 11px 0;
+ overflow: visible;
+ width: 40px;
+ }
+ header .menu-toggle button:hover,
+ header .menu-toggle button:focus {
+ background-color: rgba(221, 72, 20, .8);
+ color: rgba(255, 255, 255, .8);
+ }
+ header .heroe {
+ margin: 0 auto;
+ max-width: 1100px;
+ padding: 1rem 1.75rem 1.75rem 1.75rem;
+ }
+ header .heroe h1 {
+ font-size: 2.5rem;
+ font-weight: 500;
+ }
+ header .heroe h2 {
+ font-size: 1.5rem;
+ font-weight: 300;
+ }
+ section {
+ margin: 0 auto;
+ max-width: 1100px;
+ padding: 2.5rem 1.75rem 3.5rem 1.75rem;
+ }
+ section h1 {
+ margin-bottom: 2.5rem;
+ }
+ section h2 {
+ font-size: 120%;
+ line-height: 2.5rem;
+ padding-top: 1.5rem;
+ }
+ section pre {
+ background-color: rgba(247, 248, 249, 1);
+ border: 1px solid rgba(242, 242, 242, 1);
+ display: block;
+ font-size: .9rem;
+ margin: 2rem 0;
+ padding: 1rem 1.5rem;
+ white-space: pre-wrap;
+ word-break: break-all;
+ }
+ section code {
+ display: block;
+ }
+ section a {
+ color: rgba(221, 72, 20, 1);
+ }
+ section svg {
+ margin-bottom: -5px;
+ margin-right: 5px;
+ width: 25px;
+ }
+ .further {
+ background-color: rgba(247, 248, 249, 1);
+ border-bottom: 1px solid rgba(242, 242, 242, 1);
+ border-top: 1px solid rgba(242, 242, 242, 1);
+ }
+ .further h2:first-of-type {
+ padding-top: 0;
+ }
+ .svg-stroke {
+ fill: none;
+ stroke: #000;
+ stroke-width: 32px;
+ }
+ footer {
+ background-color: rgba(221, 72, 20, .8);
+ text-align: center;
+ }
+ footer .environment {
+ color: rgba(255, 255, 255, 1);
+ padding: 2rem 1.75rem;
+ }
+ footer .copyrights {
+ background-color: rgba(62, 62, 62, 1);
+ color: rgba(200, 200, 200, 1);
+ padding: .25rem 1.75rem;
+ }
+ @media (max-width: 629px) {
+ header ul {
+ padding: 0;
+ }
+ header .menu-toggle {
+ padding: 0 1rem;
+ }
+ header .menu-item {
+ background-color: rgba(244, 245, 246, 1);
+ border-top: 1px solid rgba(242, 242, 242, 1);
+ margin: 0 15px;
+ width: calc(100% - 30px);
+ }
+ header .menu-toggle {
+ display: block;
+ }
+ header .hidden {
+ display: none;
+ }
+ header li.menu-item a {
+ background-color: rgba(221, 72, 20, .1);
+ }
+ header li.menu-item a:hover,
+ header li.menu-item a:focus {
+ background-color: rgba(221, 72, 20, .7);
+ color: rgba(255, 255, 255, .8);
+ }
+ }
+ </style>
+</head>
+<body>
+
+<!-- HEADER: MENU + HEROE SECTION -->
+<header>
+
+ <div class="menu">
+ <ul>
+ <li class="logo">
+ <a href="https://codeigniter.com" target="_blank">
+ <svg role="img" aria-label="Visit CodeIgniter.com official website!" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2100 500" height="44"><path fill="#dd4814" d="M148.2 411c-20.53-9.07-34.48-28.61-36.31-50.99 1.2-23.02 13.36-44.06 32.67-56.61-3.17 7.73-2.4 16.53 2 23.6 5.01 7 13.63 10.36 22.07 8.61 12.02-3.38 19.06-15.86 15.68-27.89-1.2-4.21-3.6-8.03-6.88-10.91-13.6-11.06-20.43-28.44-18-45.81 2.33-9.2 7.42-17.52 14.61-23.8-5.4 14.4 9.83 28.61 20.05 35.6 18.14 10.88 35.6 22.84 52.32 35.81 18.27 14.4 28.23 36.94 26.67 60-4.11 24.54-21.47 44.8-45.13 52.4 47.33-10.53 96.13-48.13 97.06-101.46-.93-42.67-26.4-80.96-65.33-98.4h-1.73c.86 2.09 1.28 4.34 1.2 6.61.13-1.47.13-2.93 0-4.4.21 1.73.21 3.47 0 5.2-2.96 12.13-15.2 19.6-27.36 16.64-4.86-1.2-9.2-3.93-12.32-7.87-15.6-20 0-42.76 2.61-64.76 1.6-28.13-11.25-55.02-34.05-71.46 11.41 19.02-3.79 44-14.84 58.21-11.07 14.21-27.07 24.8-40.11 37.2-14.05 13.07-26.93 27.44-38.49 42.8-24.99 30.53-34.8 70.8-26.67 109.4 11.15 37.2 42.07 65.15 80.2 72.4h.21l-.13-.12Zm324.56-159.8q0-17.92 6.16-35.56 6.44-17.92 18.48-31.92t29.68-22.68q17.64-8.96 40.04-8.96 26.6 0 45.36 12.04 19.04 12.04 28 31.36l-15.4 9.52q-4.76-9.8-11.76-16.52-6.72-6.72-14.56-10.92-7.84-4.2-16.24-5.88-8.4-1.96-16.52-1.96-17.92 0-31.64 7.28-13.72 7.28-23.24 19.04-9.24 11.76-14 26.6-4.76 14.56-4.76 29.68 0 16.52 5.6 31.64 5.88 15.12 15.68 26.88 10.08 11.48 23.52 18.48 13.72 6.72 29.68 6.72 8.4 0 17.08-1.96 8.96-2.24 17.08-6.72 8.4-4.76 15.4-11.48 7-7 11.76-16.8l16.24 8.4q-4.76 11.2-13.44 19.88-8.68 8.4-19.32 14.28-10.64 5.88-22.68 8.96-11.76 3.08-23.24 3.08-20.44 0-37.52-8.96-17.08-8.96-29.4-23.24-12.32-14.56-19.32-32.76-6.72-18.48-6.72-37.52Zm263.48 103.6q-15.96 0-29.12-5.88-13.16-6.16-22.96-16.52-9.52-10.36-14.84-24.08Q664 294.6 664 279.48q0-15.4 5.32-29.12 5.6-13.72 15.12-24.08 9.8-10.36 22.96-16.52t28.84-6.16q15.68 0 28.84 6.16 13.44 6.16 22.96 16.52 9.8 10.36 15.12 24.08 5.6 13.72 5.6 29.12 0 15.12-5.32 28.84t-15.12 24.08q-9.52 10.36-22.96 16.52-13.16 5.88-29.12 5.88Zm-52.92-75.04q0 12.32 4.2 22.96 4.2 10.36 11.2 18.48 7.28 7.84 16.8 12.32 9.8 4.48 20.72 4.48 10.92 0 20.44-4.48 9.8-4.76 17.08-12.6 7.28-8.12 11.48-18.76 4.2-10.64 4.2-22.96 0-12.04-4.2-22.68-4.2-10.92-11.48-18.76-7.28-8.12-17.08-12.6-9.52-4.76-20.44-4.76-10.92 0-20.44 4.76-9.52 4.48-16.8 12.6-7.28 8.12-11.48 19.04-4.2 10.64-4.2 22.96ZM900.6 354.8q-15.12 0-28-6.16-12.88-6.44-22.12-16.8t-14.56-23.8q-5.04-13.72-5.04-28.56 0-15.4 5.04-29.12 5.04-14 13.72-24.36 8.96-10.36 21-16.24 12.32-6.16 26.88-6.16 18.48 0 32.76 9.8 14.28 9.52 22.4 23.24V147.6h19.04v179.76q0 7.84 6.72 7.84V352q-4.2.84-6.72.84-6.72 0-11.76-4.2-5.04-4.48-5.04-10.64v-14.28Q946.24 338 931.4 346.4t-30.8 8.4Zm4.2-16.8q7 0 14.84-2.8 8.12-2.8 15.12-7.56 7-5.04 11.76-11.48 5.04-6.72 6.16-14.28V256.8q-2.8-7.56-8.12-14-5.32-6.72-12.32-11.76-6.72-5.04-14.56-7.84-7.84-2.8-15.4-2.8-11.76 0-21.28 5.04-9.52 5.04-16.52 13.44-6.72 8.12-10.36 18.76-3.64 10.64-3.64 21.84 0 11.76 4.2 22.4 4.2 10.64 11.48 18.76 7.28 7.84 17.08 12.6Q893.32 338 904.8 338Zm173.04 16.8q-15.96 0-29.4-5.88-13.16-6.16-22.96-16.52-9.8-10.64-15.4-24.36-5.32-13.72-5.32-29.4 0-15.4 5.32-28.84 5.6-13.72 15.12-23.8 9.8-10.36 23.24-16.24 13.44-6.16 29.12-6.16 15.96 0 29.12 6.16 13.44 5.88 22.96 16.24 9.52 10.36 14.84 23.8 5.32 13.44 5.32 28.56v4.48q0 2.24-.28 3.08h-124.88q.84 11.76 5.32 21.84 4.76 9.8 12.04 17.08 7.28 7.28 16.52 11.48 9.52 3.92 20.16 3.92 7 0 14-1.96t12.88-5.32q5.88-3.36 10.64-8.12 4.76-5.04 7.28-10.92l16.52 4.48q-3.36 8.12-9.52 14.84-6.16 6.44-14.28 11.48-8.12 4.76-17.92 7.56-9.8 2.52-20.44 2.52Zm-53.48-83.44h107.24q-.84-11.76-5.6-21.28-4.48-9.8-11.76-16.8-7-7-16.52-10.92-9.24-3.92-19.88-3.92-10.64 0-20.16 3.92t-16.8 10.92q-7 7-11.48 16.8-4.2 9.8-5.04 21.28Zm193.2 80.64h-38.64V153.2h38.64V352Zm93.52.84q-14.84 0-26.88-5.88t-21-15.96q-8.68-10.36-13.44-23.8-4.76-13.44-4.76-28.56 0-15.96 5.04-29.68 5.04-13.72 14-24.08 8.96-10.36 21.56-16.24 12.6-5.88 27.72-5.88 17.08 0 29.96 7.84 12.88 7.56 21.28 20.44v-25.76h32.76V345q0 16.24-6.16 29.12-6.16 12.88-17.08 21.84-10.64 8.96-25.76 13.72-14.84 4.76-32.48 4.76-24.08 0-40.6-7.84-16.24-8.12-28-22.68l20.44-19.88q8.4 10.36 21 16.24 12.88 5.88 27.16 5.88 8.68 0 16.52-2.24 8.12-2.52 14.28-7.56 6.16-5.04 9.52-12.88 3.64-7.84 3.64-18.48v-18.48q-7.28 12.6-20.44 19.6-13.16 6.72-28.28 6.72Zm12.6-29.96q6.16 0 11.76-1.96t10.36-5.32q4.76-3.36 8.4-7.84 3.64-4.48 5.6-9.52v-35q-5.04-12.88-15.96-20.72-10.64-7.84-22.4-7.84-8.68 0-15.68 3.92-7 3.64-12.04 10.08-5.04 6.16-7.84 14.28-2.52 8.12-2.52 16.8 0 8.96 3.08 16.8t8.4 13.72q5.6 5.88 12.88 9.24 7.28 3.36 15.96 3.36Zm243.88-62.44V352h-37.52v-82.32q0-17.64-6.16-25.76-6.16-8.12-17.08-8.12-5.6 0-11.48 2.24-5.88 2.24-11.2 6.44-5.04 3.92-9.24 9.52t-6.16 12.32V352h-37.52V205.28h33.88v27.16q8.12-14 23.52-21.84t34.72-7.84q13.72 0 22.4 5.04 8.68 5.04 13.44 13.16 4.76 8.12 6.44 18.48 1.96 10.36 1.96 21Zm70.28 91.56h-37.52V205.28h37.52V352Zm0-167.16h-37.52V147.6h37.52v37.24Zm114.24 129.92 7.56 29.68q-7.56 3.36-18.48 6.72-10.92 3.36-22.96 3.36-7.84 0-14.84-1.96-6.72-1.96-12.04-6.16-5.04-4.48-8.12-11.2-3.08-7-3.08-16.8v-84.28h-19.32v-28.84h19.32v-47.6h37.52v47.6h30.8v28.84h-30.8v71.68q0 7.84 3.92 11.2 4.2 3.08 10.08 3.08t11.48-1.96q5.6-1.96 8.96-3.36Zm91.56 40.04q-17.64 0-31.92-5.88-14.28-6.16-24.36-16.52t-15.68-24.08q-5.32-13.72-5.32-28.84 0-15.68 5.32-29.4 5.32-14 15.4-24.36 10.08-10.64 24.36-16.8 14.56-6.16 32.48-6.16 17.92 0 31.92 6.16 14.28 6.16 24.08 16.52 10.08 10.36 15.12 24.08 5.32 13.72 5.32 28.56 0 3.64-.28 7 0 3.36-.56 5.6h-113.4q.84 8.68 4.2 15.4 3.36 6.72 8.68 11.48 5.32 4.76 12.04 7.28 6.72 2.52 14 2.52 11.2 0 21-5.32 10.08-5.6 13.72-14.56l32.2 8.96q-8.12 16.8-26.04 27.72-17.64 10.64-42.28 10.64Zm-38.08-88.48h76.16q-1.4-16.52-12.32-26.32-10.64-10.08-26.04-10.08-7.56 0-14.28 2.8-6.44 2.52-11.48 7.28t-8.4 11.48q-3.08 6.72-3.64 14.84Zm225.12-62.72v34.16q-17.08.28-30.52 6.72-13.44 6.16-19.32 18.76V352h-37.52V205.28h34.44v31.36q3.92-7.56 9.24-13.44 5.32-6.16 11.48-10.64t12.32-6.72q6.44-2.52 12.32-2.52h4.48q1.68 0 3.08.28Z"/></svg>
+ </a>
+ </li>
+ <li class="menu-toggle">
+ <button id="menuToggle">☰</button>
+ </li>
+ <li class="menu-item hidden"><a href="#">Home</a></li>
+ <li class="menu-item hidden"><a href="https://codeigniter.com/user_guide/" target="_blank">Docs</a>
+ </li>
+ <li class="menu-item hidden"><a href="https://forum.codeigniter.com/" target="_blank">Community</a></li>
+ <li class="menu-item hidden"><a
+ href="https://codeigniter.com/contribute" target="_blank">Contribute</a>
+ </li>
+ </ul>
+ </div>
+
+ <div class="heroe">
+
+ <h1>Welcome to CodeIgniter <?= CodeIgniter\CodeIgniter::CI_VERSION ?></h1>
+
+ <h2>The small framework with powerful features</h2>
+
+ </div>
+
+</header>
+
+<!-- CONTENT -->
+
+<section>
+
+ <h1>About this page</h1>
+
+ <p>The page you are looking at is being generated dynamically by CodeIgniter.</p>
+
+ <p>If you would like to edit this page you will find it located at:</p>
+
+ <pre><code>app/Views/welcome_message.php</code></pre>
+
+ <p>The corresponding controller for this page can be found at:</p>
+
+ <pre><code>app/Controllers/Home.php</code></pre>
+
+</section>
+
+<div class="further">
+
+ <section>
+
+ <h1>Go further</h1>
+
+ <h2>
+ <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><rect x='32' y='96' width='64' height='368' rx='16' ry='16' class="svg-stroke" /><line x1='112' y1='224' x2='240' y2='224' class="svg-stroke" /><line x1='112' y1='400' x2='240' y2='400' class="svg-stroke" /><rect x='112' y='160' width='128' height='304' rx='16' ry='16' class="svg-stroke" /><rect x='256' y='48' width='96' height='416' rx='16' ry='16' class="svg-stroke" /><path d='M422.46,96.11l-40.4,4.25c-11.12,1.17-19.18,11.57-17.93,23.1l34.92,321.59c1.26,11.53,11.37,20,22.49,18.84l40.4-4.25c11.12-1.17,19.18-11.57,17.93-23.1L445,115C443.69,103.42,433.58,94.94,422.46,96.11Z' class="svg-stroke"/></svg>
+ Learn
+ </h2>
+
+ <p>The User Guide contains an introduction, tutorial, a number of "how to"
+ guides, and then reference documentation for the components that make up
+ the framework. Check the <a href="https://codeigniter.com/user_guide/"
+ target="_blank">User Guide</a> !</p>
+
+ <h2>
+ <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><path d='M431,320.6c-1-3.6,1.2-8.6,3.3-12.2a33.68,33.68,0,0,1,2.1-3.1A162,162,0,0,0,464,215c.3-92.2-77.5-167-173.7-167C206.4,48,136.4,105.1,120,180.9a160.7,160.7,0,0,0-3.7,34.2c0,92.3,74.8,169.1,171,169.1,15.3,0,35.9-4.6,47.2-7.7s22.5-7.2,25.4-8.3a26.44,26.44,0,0,1,9.3-1.7,26,26,0,0,1,10.1,2L436,388.6a13.52,13.52,0,0,0,3.9,1,8,8,0,0,0,8-8,12.85,12.85,0,0,0-.5-2.7Z' class="svg-stroke" /><path d='M66.46,232a146.23,146.23,0,0,0,6.39,152.67c2.31,3.49,3.61,6.19,3.21,8s-11.93,61.87-11.93,61.87a8,8,0,0,0,2.71,7.68A8.17,8.17,0,0,0,72,464a7.26,7.26,0,0,0,2.91-.6l56.21-22a15.7,15.7,0,0,1,12,.2c18.94,7.38,39.88,12,60.83,12A159.21,159.21,0,0,0,284,432.11' class="svg-stroke" /></svg>
+ Discuss
+ </h2>
+
+ <p>CodeIgniter is a community-developed open source project, with several
+ venues for the community members to gather and exchange ideas. View all
+ the threads on <a href="https://forum.codeigniter.com/"
+ target="_blank">CodeIgniter's forum</a>, or <a href="https://join.slack.com/t/codeigniterchat/shared_invite/zt-rl30zw00-obL1Hr1q1ATvkzVkFp8S0Q"
+ target="_blank">chat on Slack</a> !</p>
+
+ <h2>
+ <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><line x1='176' y1='48' x2='336' y2='48' class="svg-stroke" /><line x1='118' y1='304' x2='394' y2='304' class="svg-stroke" /><path d='M208,48v93.48a64.09,64.09,0,0,1-9.88,34.18L73.21,373.49C48.4,412.78,76.63,464,123.08,464H388.92c46.45,0,74.68-51.22,49.87-90.51L313.87,175.66A64.09,64.09,0,0,1,304,141.48V48' class="svg-stroke" /></svg>
+ Contribute
+ </h2>
+
+ <p>CodeIgniter is a community driven project and accepts contributions
+ of code and documentation from the community. Why not
+ <a href="https://codeigniter.com/contribute" target="_blank">
+ join us</a> ?</p>
+
+ </section>
+
+</div>
+
+<!-- FOOTER: DEBUG INFO + COPYRIGHTS -->
+
+<footer>
+ <div class="environment">
+
+ <p>Page rendered in {elapsed_time} seconds using {memory_usage} MB of memory.</p>
+
+ <p>Environment: <?= ENVIRONMENT ?></p>
+
+ </div>
+
+ <div class="copyrights">
+
+ <p>© <?= date('Y') ?> CodeIgniter Foundation. CodeIgniter is open source project released under the MIT
+ open source licence.</p>
+
+ </div>
+
+</footer>
+
+<!-- SCRIPTS -->
+
+<script {csp-script-nonce}>
+ document.getElementById("menuToggle").addEventListener('click', toggleMenu);
+ function toggleMenu() {
+ var menuItems = document.getElementsByClassName('menu-item');
+ for (var i = 0; i < menuItems.length; i++) {
+ var menuItem = menuItems[i];
+ menuItem.classList.toggle("hidden");
+ }
+ }
+</script>
+
+<!-- -->
+
+</body>
+</html>
diff --git a/app/index.html b/app/index.html
new file mode 100644
index 0000000..69df4e1
--- /dev/null
+++ b/app/index.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>
diff --git a/builds b/builds
new file mode 100755
index 0000000..c68c089
--- /dev/null
+++ b/builds
@@ -0,0 +1,128 @@
+#!/usr/bin/env php
+<?php
+
+define('LATEST_RELEASE', '^4.7');
+define('DEVELOP_BRANCH', 'dev-develop');
+define('NEXT_MINOR', '^4.8-dev');
+define('GITHUB_URL', 'https://github.com/codeigniter4/codeigniter4');
+
+/*
+ * --------------------------------------------------------------------
+ * Stability Toggle
+ * --------------------------------------------------------------------
+ * Use this script to toggle the CodeIgniter dependency between the
+ * latest stable release and the most recent development update.
+ *
+ * Usage: php builds [release|development|next]
+ */
+
+$branch = $argv[1] ?? '';
+
+// Determine the requested stability
+if ($branch === '' || ! in_array($branch, ['release', 'development', 'next'], true)) {
+ echo 'Usage: php builds [release|development|next]' . PHP_EOL;
+
+ exit;
+}
+
+$modified = [];
+
+// Locate each file and update it for the requested stability
+
+$file = __DIR__ . DIRECTORY_SEPARATOR . 'composer.json';
+
+if (is_file($file)) {
+ $contents = file_get_contents($file);
+
+ if ((string) $contents !== '') {
+ $array = json_decode($contents, true);
+
+ if (is_array($array)) {
+ if ($branch !== 'release') {
+ $array['minimum-stability'] = 'dev';
+ $array['prefer-stable'] = true;
+ $array['repositories'] ??= [];
+
+ $found = false;
+
+ foreach ($array['repositories'] as $repository) {
+ if ($repository['url'] === GITHUB_URL) {
+ $found = true;
+ break;
+ }
+ }
+
+ if (! $found) {
+ $array['repositories'][] = [
+ 'type' => 'vcs',
+ 'url' => GITHUB_URL,
+ ];
+ }
+
+ $array['require']['codeigniter4/codeigniter4'] = $branch === 'next' ? NEXT_MINOR : DEVELOP_BRANCH;
+ unset($array['require']['codeigniter4/framework']);
+ } else {
+ unset($array['minimum-stability']);
+
+ if (isset($array['repositories'])) {
+ foreach ($array['repositories'] as $i => $repository) {
+ if ($repository['url'] === GITHUB_URL) {
+ unset($array['repositories'][$i]);
+ break;
+ }
+ }
+
+ if ($array['repositories'] === []) {
+ unset($array['repositories']);
+ }
+ }
+
+ $array['require']['codeigniter4/framework'] = LATEST_RELEASE;
+ unset($array['require']['codeigniter4/codeigniter4']);
+ }
+
+ file_put_contents($file, json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL);
+
+ $modified[] = $file;
+ } else {
+ echo 'Warning: Unable to decode composer.json! Skipping...' . PHP_EOL;
+ }
+ } else {
+ echo 'Warning: Unable to read composer.json! Skipping...' . PHP_EOL;
+ }
+}
+
+$files = [
+ __DIR__ . DIRECTORY_SEPARATOR . 'app/Config/Paths.php',
+ __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.dist.xml',
+ __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml',
+];
+
+foreach ($files as $file) {
+ if (is_file($file)) {
+ $contents = file_get_contents($file);
+
+ if ($branch !== 'release') {
+ $contents = str_replace('vendor/codeigniter4/framework', 'vendor/codeigniter4/codeigniter4', $contents);
+ } else {
+ $contents = str_replace('vendor/codeigniter4/codeigniter4', 'vendor/codeigniter4/framework', $contents);
+ }
+
+ file_put_contents($file, $contents);
+
+ $modified[] = $file;
+ }
+}
+
+if ($modified === []) {
+ echo 'No files modified.' . PHP_EOL;
+} else {
+ echo 'The following files were modified:' . PHP_EOL;
+
+ foreach ($modified as $file) {
+ echo " * {$file}" . PHP_EOL;
+ }
+}
+
+echo 'Run `composer update` to sync changes with your vendor folder.' . PHP_EOL;
+echo 'Don\'t forget to update the project files in app folder from "vendor/codeigniter4/*/app/".' . PHP_EOL;
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..8a47633
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,47 @@
+{
+ "name": "codeigniter4/appstarter",
+ "description": "CodeIgniter4 starter app",
+ "license": "MIT",
+ "type": "project",
+ "homepage": "https://codeigniter.com",
+ "support": {
+ "forum": "https://forum.codeigniter.com/",
+ "source": "https://github.com/codeigniter4/CodeIgniter4",
+ "slack": "https://codeigniterchat.slack.com"
+ },
+ "require": {
+ "php": "^8.2",
+ "codeigniter4/framework": "^4.7",
+ "codeigniter4/settings": "^2.4",
+ "codeigniter4/shield": "^1.4",
+ "codeigniter4/translations": "^4.7"
+ },
+ "require-dev": {
+ "codeigniter/coding-standard": "^1.9",
+ "fakerphp/faker": "^1.9",
+ "mikey179/vfsstream": "^1.6",
+ "phpunit/phpunit": "^10.5.16"
+ },
+ "autoload": {
+ "psr-4": {
+ "App\\": "app/",
+ "Config\\": "app/Config/"
+ },
+ "exclude-from-classmap": [
+ "**/Database/Migrations/**"
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Tests\\Support\\": "tests/_support"
+ }
+ },
+ "config": {
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "sort-packages": true
+ },
+ "scripts": {
+ "test": "phpunit"
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..a365003
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,4967 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "586e91984691adfcd3a7fe5c04628077",
+ "packages": [
+ {
+ "name": "codeigniter4/framework",
+ "version": "v4.7.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/codeigniter4/framework.git",
+ "reference": "67ead895b7491703e5e5bc17436778806192008f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/codeigniter4/framework/zipball/67ead895b7491703e5e5bc17436778806192008f",
+ "reference": "67ead895b7491703e5e5bc17436778806192008f",
+ "shasum": ""
+ },
+ "require": {
+ "ext-intl": "*",
+ "ext-mbstring": "*",
+ "laminas/laminas-escaper": "^2.18",
+ "php": "^8.2",
+ "psr/log": "^3.0"
+ },
+ "require-dev": {
+ "codeigniter/coding-standard": "^1.7",
+ "fakerphp/faker": "^1.24",
+ "friendsofphp/php-cs-fixer": "^3.47.1",
+ "kint-php/kint": "^6.1",
+ "mikey179/vfsstream": "^1.6.12",
+ "nexusphp/cs-config": "^3.6",
+ "phpunit/phpunit": "^10.5.16 || ^11.2",
+ "predis/predis": "^3.0"
+ },
+ "suggest": {
+ "ext-apcu": "If you use Cache class ApcuHandler",
+ "ext-curl": "If you use CURLRequest class",
+ "ext-dom": "If you use TestResponse",
+ "ext-exif": "If you run Image class tests",
+ "ext-fileinfo": "Improves mime type detection for files",
+ "ext-gd": "If you use Image class GDHandler",
+ "ext-imagick": "If you use Image class ImageMagickHandler",
+ "ext-libxml": "If you use TestResponse",
+ "ext-memcache": "If you use Cache class MemcachedHandler with Memcache",
+ "ext-memcached": "If you use Cache class MemcachedHandler with Memcached",
+ "ext-mysqli": "If you use MySQL",
+ "ext-oci8": "If you use Oracle Database",
+ "ext-pcntl": "If you use Signals",
+ "ext-pgsql": "If you use PostgreSQL",
+ "ext-posix": "If you use Signals",
+ "ext-readline": "Improves CLI::input() usability",
+ "ext-redis": "If you use Cache class RedisHandler",
+ "ext-simplexml": "If you format XML",
+ "ext-sodium": "If you use Encryption SodiumHandler",
+ "ext-sqlite3": "If you use SQLite3",
+ "ext-sqlsrv": "If you use SQL Server",
+ "ext-xdebug": "If you use CIUnitTestCase::assertHeaderEmitted()"
+ },
+ "type": "project",
+ "autoload": {
+ "psr-4": {
+ "CodeIgniter\\": "system/"
+ },
+ "exclude-from-classmap": [
+ "**/Database/Migrations/**"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "The CodeIgniter framework v4",
+ "homepage": "https://codeigniter.com",
+ "support": {
+ "forum": "https://forum.codeigniter.com/",
+ "slack": "https://codeigniterchat.slack.com",
+ "source": "https://github.com/codeigniter4/CodeIgniter4"
+ },
+ "time": "2026-07-07T09:23:35+00:00"
+ },
+ {
+ "name": "codeigniter4/settings",
+ "version": "v2.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/codeigniter4/settings.git",
+ "reference": "7cbd2e2146e32211cc8194d9c35632631500adad"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/codeigniter4/settings/zipball/7cbd2e2146e32211cc8194d9c35632631500adad",
+ "reference": "7cbd2e2146e32211cc8194d9c35632631500adad",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.2"
+ },
+ "require-dev": {
+ "codeigniter4/devkit": "^1.3",
+ "codeigniter4/framework": "^4.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "CodeIgniter\\Settings\\": "src"
+ },
+ "exclude-from-classmap": [
+ "**/Database/Migrations/**"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Lonnie Ezell",
+ "email": "[email protected]",
+ "role": "Developer"
+ }
+ ],
+ "description": "Settings library for CodeIgniter 4",
+ "homepage": "https://github.com/codeigniter4/settings",
+ "keywords": [
+ "Settings",
+ "codeigniter",
+ "codeigniter4"
+ ],
+ "support": {
+ "issues": "https://github.com/codeigniter4/settings/issues",
+ "source": "https://github.com/codeigniter4/settings/tree/v2.4.0"
+ },
+ "time": "2026-07-30T16:03:46+00:00"
+ },
+ {
+ "name": "codeigniter4/shield",
+ "version": "v1.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/codeigniter4/shield.git",
+ "reference": "93c5f1f1481ced93ceb4071ffa3a08a9647a7c8b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/codeigniter4/shield/zipball/93c5f1f1481ced93ceb4071ffa3a08a9647a7c8b",
+ "reference": "93c5f1f1481ced93ceb4071ffa3a08a9647a7c8b",
+ "shasum": ""
+ },
+ "require": {
+ "codeigniter4/settings": "^2.1",
+ "php": "^8.2"
+ },
+ "provide": {
+ "codeigniter4/authentication-implementation": "1.0"
+ },
+ "require-dev": {
+ "boundwize/pyrameter": "^0.5",
+ "boundwize/structarmed": "^0.15",
+ "codeigniter/phpstan-codeigniter": "^2.0",
+ "codeigniter4/devkit": "^1.3",
+ "codeigniter4/framework": ">=4.3.5 <4.5.0 || ^4.5.1",
+ "firebase/php-jwt": "^7.0.3",
+ "mikey179/vfsstream": "^1.6.7",
+ "mockery/mockery": "^1.0",
+ "phpstan/phpstan-strict-rules": "^2.0"
+ },
+ "suggest": {
+ "ext-curl": "Required to use the password validation rule via PwnedValidator class.",
+ "ext-openssl": "Required to use the JWT Authenticator."
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "CodeIgniter\\Shield\\": "src"
+ },
+ "exclude-from-classmap": [
+ "**/Database/Migrations/**"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Lonnie Ezell",
+ "email": "[email protected]",
+ "role": "Developer"
+ }
+ ],
+ "description": "Authentication and Authorization for CodeIgniter 4",
+ "homepage": "https://github.com/codeigniter4/shield",
+ "keywords": [
+ "Authentication",
+ "authorization",
+ "codeigniter",
+ "codeigniter4"
+ ],
+ "support": {
+ "docs": "https://codeigniter4.github.io/shield/",
+ "forum": "https://github.com/codeigniter4/shield/discussions",
+ "issues": "https://github.com/codeigniter4/shield/issues",
+ "slack": "https://codeigniterchat.slack.com",
+ "source": "https://github.com/codeigniter4/shield"
+ },
+ "time": "2026-08-18T12:02:04+00:00"
+ },
+ {
+ "name": "codeigniter4/translations",
+ "version": "v4.7.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/codeigniter4/translations.git",
+ "reference": "a5df30934aa25a65bc1f78e6462b47fae0a0179a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/codeigniter4/translations/zipball/a5df30934aa25a65bc1f78e6462b47fae0a0179a",
+ "reference": "a5df30934aa25a65bc1f78e6462b47fae0a0179a",
+ "shasum": ""
+ },
+ "require": {
+ "ext-intl": "*",
+ "php": "^8.2"
+ },
+ "require-dev": {
+ "codeigniter/coding-standard": "^1.7",
+ "codeigniter4/codeigniter4": "dev-develop",
+ "ext-tokenizer": "*",
+ "friendsofphp/php-cs-fixer": "^3.53",
+ "nexusphp/cs-config": "^3.22",
+ "phpunit/phpunit": "^11.5 || ^12.5"
+ },
+ "type": "project",
+ "extra": {
+ "branch-alias": {
+ "dev-develop": "4.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Translations\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Translations for CodeIgniter v4 web framework",
+ "homepage": "https://codeigniter.com",
+ "support": {
+ "forum": "http://forum.codeigniter.com/",
+ "issues": "https://github.com/codeigniter4/translations/issues",
+ "slack": "https://codeigniterchat.slack.com",
+ "source": "https://github.com/codeigniter4/translations"
+ },
+ "time": "2026-08-05T12:38:16+00:00"
+ },
+ {
+ "name": "laminas/laminas-escaper",
+ "version": "2.18.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laminas/laminas-escaper.git",
+ "reference": "06f211dfffff18d91844c1f55250d5d13c007e18"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/06f211dfffff18d91844c1f55250d5d13c007e18",
+ "reference": "06f211dfffff18d91844c1f55250d5d13c007e18",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ctype": "*",
+ "ext-mbstring": "*",
+ "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
+ },
+ "conflict": {
+ "zendframework/zend-escaper": "*"
+ },
+ "require-dev": {
+ "infection/infection": "^0.31.0",
+ "laminas/laminas-coding-standard": "~3.1.0",
+ "phpunit/phpunit": "^11.5.42",
+ "psalm/plugin-phpunit": "^0.19.5",
+ "vimeo/psalm": "^6.13.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Laminas\\Escaper\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs",
+ "homepage": "https://laminas.dev",
+ "keywords": [
+ "escaper",
+ "laminas"
+ ],
+ "support": {
+ "chat": "https://laminas.dev/chat",
+ "docs": "https://docs.laminas.dev/laminas-escaper/",
+ "forum": "https://discourse.laminas.dev",
+ "issues": "https://github.com/laminas/laminas-escaper/issues",
+ "rss": "https://github.com/laminas/laminas-escaper/releases.atom",
+ "source": "https://github.com/laminas/laminas-escaper"
+ },
+ "funding": [
+ {
+ "url": "https://funding.communitybridge.org/projects/laminas-project",
+ "type": "community_bridge"
+ }
+ ],
+ "time": "2025-10-14T18:31:13+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
+ },
+ "time": "2024-09-11T13:17:53+00:00"
+ }
+ ],
+ "packages-dev": [
+ {
+ "name": "clue/ndjson-react",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-ndjson.git",
+ "reference": "392dc165fce93b5bb5c637b67e59619223c931b0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0",
+ "reference": "392dc165fce93b5bb5c637b67e59619223c931b0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\NDJson\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "[email protected]"
+ }
+ ],
+ "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-ndjson",
+ "keywords": [
+ "NDJSON",
+ "json",
+ "jsonlines",
+ "newline",
+ "reactphp",
+ "streaming"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-ndjson/issues",
+ "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-12-23T10:58:28+00:00"
+ },
+ {
+ "name": "codeigniter/coding-standard",
+ "version": "v1.9.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/CodeIgniter/coding-standard.git",
+ "reference": "e9c690ebb86140a2ddf874940b0758c4b88110ce"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/CodeIgniter/coding-standard/zipball/e9c690ebb86140a2ddf874940b0758c4b88110ce",
+ "reference": "e9c690ebb86140a2ddf874940b0758c4b88110ce",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "friendsofphp/php-cs-fixer": "^3.95",
+ "nexusphp/cs-config": "^3.28",
+ "php": "^8.2"
+ },
+ "require-dev": {
+ "nexusphp/tachycardia": "^2.4",
+ "phpstan/phpstan": "^2.1",
+ "phpunit/phpunit": "^11.5 || ^12.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "CodeIgniter\\CodingStandard\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "John Paul E. Balandan, CPA",
+ "email": "[email protected]"
+ }
+ ],
+ "description": "Official Coding Standards for CodeIgniter based on PHP CS Fixer",
+ "keywords": [
+ "phpcs",
+ "static analysis"
+ ],
+ "support": {
+ "forum": "http://forum.codeigniter.com/",
+ "issues": "https://github.com/CodeIgniter/coding-standard/issues",
+ "slack": "https://codeigniterchat.slack.com",
+ "source": "https://github.com/CodeIgniter/coding-standard"
+ },
+ "time": "2026-04-11T20:06:02+00:00"
+ },
+ {
+ "name": "composer/pcre",
+ "version": "3.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/pcre.git",
+ "reference": "d5a341b3fb61f3001970940afb1d332968a183ed"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/d5a341b3fb61f3001970940afb1d332968a183ed",
+ "reference": "d5a341b3fb61f3001970940afb1d332968a183ed",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4 || ^8.0"
+ },
+ "conflict": {
+ "phpstan/phpstan": "<2.2.2"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^2",
+ "phpstan/phpstan-deprecation-rules": "^2",
+ "phpstan/phpstan-strict-rules": "^2",
+ "phpunit/phpunit": "^9"
+ },
+ "type": "library",
+ "extra": {
+ "phpstan": {
+ "includes": [
+ "extension.neon"
+ ]
+ },
+ "branch-alias": {
+ "dev-main": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Pcre\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "[email protected]",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
+ "keywords": [
+ "PCRE",
+ "preg",
+ "regex",
+ "regular expression"
+ ],
+ "support": {
+ "issues": "https://github.com/composer/pcre/issues",
+ "source": "https://github.com/composer/pcre/tree/3.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ }
+ ],
+ "time": "2026-06-07T11:47:49+00:00"
+ },
+ {
+ "name": "composer/semver",
+ "version": "3.4.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/semver.git",
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.2 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.11",
+ "symfony/phpunit-bridge": "^3 || ^7"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Semver\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "[email protected]",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "[email protected]",
+ "homepage": "http://seld.be"
+ },
+ {
+ "name": "Rob Bast",
+ "email": "[email protected]",
+ "homepage": "http://robbast.nl"
+ }
+ ],
+ "description": "Semver library that offers utilities, version constraint parsing and validation.",
+ "keywords": [
+ "semantic",
+ "semver",
+ "validation",
+ "versioning"
+ ],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/semver/issues",
+ "source": "https://github.com/composer/semver/tree/3.4.4"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ }
+ ],
+ "time": "2025-08-20T19:15:30+00:00"
+ },
+ {
+ "name": "composer/xdebug-handler",
+ "version": "3.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/xdebug-handler.git",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "shasum": ""
+ },
+ "require": {
+ "composer/pcre": "^1 || ^2 || ^3",
+ "php": "^7.2.5 || ^8.0",
+ "psr/log": "^1 || ^2 || ^3"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.0",
+ "phpstan/phpstan-strict-rules": "^1.1",
+ "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Composer\\XdebugHandler\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "John Stevenson",
+ "email": "[email protected]"
+ }
+ ],
+ "description": "Restarts a process without Xdebug.",
+ "keywords": [
+ "Xdebug",
+ "performance"
+ ],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/xdebug-handler/issues",
+ "source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-05-06T16:37:16+00:00"
+ },
+ {
+ "name": "ergebnis/agent-detector",
+ "version": "1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ergebnis/agent-detector.git",
+ "reference": "e211f17928c8b95a51e06040792d57f5462fb271"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ergebnis/agent-detector/zipball/e211f17928c8b95a51e06040792d57f5462fb271",
+ "reference": "e211f17928c8b95a51e06040792d57f5462fb271",
+ "shasum": ""
+ },
+ "require": {
+ "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0 || ~8.6.0"
+ },
+ "require-dev": {
+ "ergebnis/composer-normalize": "^2.51.0",
+ "ergebnis/license": "^2.7.0",
+ "ergebnis/php-cs-fixer-config": "^6.60.2",
+ "ergebnis/phpstan-rules": "^2.13.1",
+ "ergebnis/phpunit-slow-test-detector": "^2.24.0",
+ "ergebnis/rector-rules": "^1.18.1",
+ "fakerphp/faker": "^1.24.1",
+ "infection/infection": "^0.26.6",
+ "phpstan/extension-installer": "^1.4.3",
+ "phpstan/phpstan": "^2.1.54",
+ "phpstan/phpstan-deprecation-rules": "^2.0.4",
+ "phpstan/phpstan-phpunit": "^2.0.16",
+ "phpstan/phpstan-strict-rules": "^2.0.10",
+ "phpunit/phpunit": "^9.6.34",
+ "rector/rector": "^2.4.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.2-dev"
+ },
+ "composer-normalize": {
+ "indent-size": 2,
+ "indent-style": "space"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Ergebnis\\AgentDetector\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Andreas Möller",
+ "email": "[email protected]",
+ "homepage": "https://localheinz.com"
+ }
+ ],
+ "description": "Provides a detector for detecting the presence of an agent.",
+ "homepage": "https://github.com/ergebnis/agent-detector",
+ "support": {
+ "issues": "https://github.com/ergebnis/agent-detector/issues",
+ "security": "https://github.com/ergebnis/agent-detector/blob/main/.github/SECURITY.md",
+ "source": "https://github.com/ergebnis/agent-detector"
+ },
+ "time": "2026-05-07T08:19:07+00:00"
+ },
+ {
+ "name": "evenement/evenement",
+ "version": "v3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/igorw/evenement.git",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9 || ^6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Evenement\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Igor Wiedler",
+ "email": "[email protected]"
+ }
+ ],
+ "description": "Événement is a very simple event dispatching library for PHP",
+ "keywords": [
+ "event-dispatcher",
+ "event-emitter"
+ ],
+ "support": {
+ "issues": "https://github.com/igorw/evenement/issues",
+ "source": "https://github.com/igorw/evenement/tree/v3.0.2"
+ },
+ "time": "2023-08-08T05:53:35+00:00"
+ },
+ {
+ "name": "fakerphp/faker",
+ "version": "v1.24.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/FakerPHP/Faker.git",
+ "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5",
+ "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4 || ^8.0",
+ "psr/container": "^1.0 || ^2.0",
+ "symfony/deprecation-contracts": "^2.2 || ^3.0"
+ },
+ "conflict": {
+ "fzaninotto/faker": "*"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.4.1",
+ "doctrine/persistence": "^1.3 || ^2.0",
+ "ext-intl": "*",
+ "phpunit/phpunit": "^9.5.26",
+ "symfony/phpunit-bridge": "^5.4.16"
+ },
+ "suggest": {
+ "doctrine/orm": "Required to use Faker\\ORM\\Doctrine",
+ "ext-curl": "Required by Faker\\Provider\\Image to download images.",
+ "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.",
+ "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.",
+ "ext-mbstring": "Required for multibyte Unicode string functionality."
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Faker\\": "src/Faker/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "François Zaninotto"
+ }
+ ],
+ "description": "Faker is a PHP library that generates fake data for you.",
+ "keywords": [
+ "data",
+ "faker",
+ "fixtures"
+ ],
+ "support": {
+ "issues": "https://github.com/FakerPHP/Faker/issues",
+ "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1"
+ },
+ "time": "2024-11-21T13:46:39+00:00"
+ },
+ {
+ "name": "fidry/cpu-core-counter",
+ "version": "1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theofidry/cpu-core-counter.git",
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678",
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "fidry/makefile": "^0.2.0",
+ "fidry/php-cs-fixer-config": "^1.1.2",
+ "phpstan/extension-installer": "^1.2.0",
+ "phpstan/phpstan": "^2.0",
+ "phpstan/phpstan-deprecation-rules": "^2.0.0",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpstan/phpstan-strict-rules": "^2.0",
+ "phpunit/phpunit": "^8.5.31 || ^9.5.26",
+ "webmozarts/strict-phpunit": "^7.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Fidry\\CpuCoreCounter\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Théo FIDRY",
+ "email": "[email protected]"
+ }
+ ],
+ "description": "Tiny utility to get the number of CPU cores.",
+ "keywords": [
+ "CPU",
+ "core"
+ ],
+ "support": {
+ "issues": "https://github.com/theofidry/cpu-core-counter/issues",
+ "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theofidry",
+ "type": "github"
+ }
+ ],
+ "time": "2025-08-14T07:29:31+00:00"
+ },
+ {
+ "name": "friendsofphp/php-cs-fixer",
+ "version": "v3.95.24",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
+ "reference": "9a4b8050f8768646bf3693ee7416978ceeca6206"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/9a4b8050f8768646bf3693ee7416978ceeca6206",
+ "reference": "9a4b8050f8768646bf3693ee7416978ceeca6206",
+ "shasum": ""
+ },
+ "require": {
+ "clue/ndjson-react": "^1.3",
+ "composer/semver": "^3.4",
+ "composer/xdebug-handler": "^3.0.5",
+ "ergebnis/agent-detector": "^1.2",
+ "ext-filter": "*",
+ "ext-hash": "*",
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "fidry/cpu-core-counter": "^1.3",
+ "php": "^7.4 || ^8.0",
+ "react/child-process": "^0.6.6",
+ "react/event-loop": "^1.5",
+ "react/socket": "^1.16",
+ "react/stream": "^1.4",
+ "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0 || ^9.0",
+ "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
+ "symfony/polyfill-mbstring": "^1.37",
+ "symfony/polyfill-php80": "^1.37",
+ "symfony/polyfill-php81": "^1.37",
+ "symfony/polyfill-php84": "^1.37",
+ "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2 || ^8.0",
+ "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "facile-it/paraunit": "^1.3.1 || ^2.11.0",
+ "infection/infection": "^0.32.7",
+ "justinrainbow/json-schema": "^6.10.0",
+ "keradus/cli-executor": "^2.3",
+ "php-coveralls/php-coveralls": "^2.9.1",
+ "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.8",
+ "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.8",
+ "phpunit/phpunit": "^9.6.35 || ^10.5.64 || ^11.5.56 || ^12.5.31 || ^13.0.6",
+ "symfony/polyfill-php85": "^1.38",
+ "symfony/var-dumper": "^5.4.48 || ^6.4.36 || ^7.4.8 || ^8.1.1",
+ "symfony/yaml": "^5.4.53 || ^6.4.41 || ^7.4.13 || ^8.1.1"
+ },
+ "suggest": {
+ "ext-dom": "For handling output formats in XML",
+ "ext-mbstring": "For handling non-UTF8 characters."
+ },
+ "bin": [
+ "php-cs-fixer"
+ ],
+ "type": "application",
+ "autoload": {
+
[Diff truncated. Use the raw view or local clone for the full content.]