diff --git a/.env b/.env new file mode 100644 index 0000000..f8d95f8 --- /dev/null +++ b/.env @@ -0,0 +1,143 @@ +#-------------------------------------------------------------------- +# Example Environment Configuration file +# +# This file can be used as a starting point for your own +# custom .env files, and contains most of the possible settings +# available in a default install. +# +# By default, all of the settings are commented out. If you want +# to override the setting, you must un-comment it by removing the '#' +# at the beginning of the line. +#-------------------------------------------------------------------- + +#-------------------------------------------------------------------- +# ENVIRONMENT +#-------------------------------------------------------------------- + +CI_ENVIRONMENT = development + +#-------------------------------------------------------------------- +# APP +#-------------------------------------------------------------------- + +# app.baseURL = '' +# If you have trouble with `.`, you could also use `_`. +# app_baseURL = '' +# app.forceGlobalSecureRequests = false +# app.CSPEnabled = false + +#-------------------------------------------------------------------- +# DATABASE +#-------------------------------------------------------------------- + +# database.default.hostname = localhost +# database.default.database = ci4 +# database.default.username = root +# database.default.password = root +# database.default.DBDriver = MySQLi +# database.default.DBPrefix = +# database.default.port = 3306 + +# database.tests.hostname = localhost +# database.tests.database = ci4_test +# database.tests.username = root +# database.tests.password = root +# database.tests.DBDriver = MySQLi +# database.tests.DBPrefix = +# database.tests.port = 3306 + +#-------------------------------------------------------------------- +# CONTENT SECURITY POLICY +#-------------------------------------------------------------------- + +# contentsecuritypolicy.reportOnly = false +# contentsecuritypolicy.defaultSrc = 'none' +# contentsecuritypolicy.scriptSrc = 'self' +# contentsecuritypolicy.styleSrc = 'self' +# contentsecuritypolicy.imageSrc = 'self' +# contentsecuritypolicy.baseURI = null +# contentsecuritypolicy.childSrc = null +# contentsecuritypolicy.connectSrc = 'self' +# contentsecuritypolicy.fontSrc = null +# contentsecuritypolicy.formAction = null +# contentsecuritypolicy.frameAncestors = null +# contentsecuritypolicy.frameSrc = null +# contentsecuritypolicy.mediaSrc = null +# contentsecuritypolicy.objectSrc = null +# contentsecuritypolicy.pluginTypes = null +# contentsecuritypolicy.reportURI = null +# contentsecuritypolicy.sandbox = false +# contentsecuritypolicy.upgradeInsecureRequests = false +# contentsecuritypolicy.styleNonceTag = '{csp-style-nonce}' +# contentsecuritypolicy.scriptNonceTag = '{csp-script-nonce}' +# contentsecuritypolicy.autoNonce = true + +#-------------------------------------------------------------------- +# COOKIE +#-------------------------------------------------------------------- + +# cookie.prefix = '' +# cookie.expires = 0 +# cookie.path = '/' +# cookie.domain = '' +# cookie.secure = false +# cookie.httponly = false +# cookie.samesite = 'Lax' +# cookie.raw = false + +#-------------------------------------------------------------------- +# ENCRYPTION +#-------------------------------------------------------------------- + +# encryption.key = +# encryption.driver = OpenSSL +# encryption.blockSize = 16 +# encryption.digest = SHA512 + +#-------------------------------------------------------------------- +# HONEYPOT +#-------------------------------------------------------------------- + +# honeypot.hidden = 'true' +# honeypot.label = 'Fill This Field' +# honeypot.name = 'honeypot' +# honeypot.template = '' +# honeypot.container = '
{template}
' + +#-------------------------------------------------------------------- +# SECURITY +#-------------------------------------------------------------------- + +# security.csrfProtection = 'cookie' +# security.tokenRandomize = false +# security.tokenName = 'csrf_token_name' +# security.headerName = 'X-CSRF-TOKEN' +# security.cookieName = 'csrf_cookie_name' +# security.expires = 7200 +# security.regenerate = true +# security.redirect = false +# security.samesite = 'Lax' + +#-------------------------------------------------------------------- +# SESSION +#-------------------------------------------------------------------- + +# session.driver = 'CodeIgniter\Session\Handlers\FileHandler' +# session.cookieName = 'ci_session' +# session.expiration = 7200 +# session.savePath = null +# session.matchIP = false +# session.timeToUpdate = 300 +# session.regenerateDestroy = false + +#-------------------------------------------------------------------- +# LOGGER +#-------------------------------------------------------------------- + +# logger.threshold = 4 + +#-------------------------------------------------------------------- +# CURLRequest +#-------------------------------------------------------------------- + +# curlrequest.shareOptions = true diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0119e5f --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014-2019 British Columbia Institute of Technology +Copyright (c) 2019-2023 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_composer.md b/README_composer.md new file mode 100644 index 0000000..461e949 --- /dev/null +++ b/README_composer.md @@ -0,0 +1,62 @@ +# 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. + +The user guide corresponding to the latest version of the framework can be found +[here](https://codeigniter4.github.io/userguide/). + +## 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 7.4 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) + +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..f24db0a --- /dev/null +++ b/app/.htaccess @@ -0,0 +1,6 @@ + + Require all denied + + + Deny from all + 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 @@ + + */ + public array $allowedHostnames = []; + + /** + * -------------------------------------------------------------------------- + * Index File + * -------------------------------------------------------------------------- + * + * Typically this will be your index.php file, unless you've renamed it to + * something else. If you are using mod_rewrite to remove the page set this + * variable so that it is blank. + */ + 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'; + + /** + * -------------------------------------------------------------------------- + * 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 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'; + + /** + * -------------------------------------------------------------------------- + * URI PROTOCOL + * -------------------------------------------------------------------------- + * + * 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 header will be set. + */ + public bool $forceGlobalSecureRequests = false; + + /** + * -------------------------------------------------------------------------- + * Session Driver + * -------------------------------------------------------------------------- + * + * The session storage driver to use: + * - `CodeIgniter\Session\Handlers\FileHandler` + * - `CodeIgniter\Session\Handlers\DatabaseHandler` + * - `CodeIgniter\Session\Handlers\MemcachedHandler` + * - `CodeIgniter\Session\Handlers\RedisHandler` + * + * @deprecated use Config\Session::$driver instead. + */ + public string $sessionDriver = FileHandler::class; + + /** + * -------------------------------------------------------------------------- + * Session Cookie Name + * -------------------------------------------------------------------------- + * + * The session cookie name, must contain only [0-9a-z_-] characters + * + * @deprecated use Config\Session::$cookieName instead. + */ + public string $sessionCookieName = '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. + * + * @deprecated use Config\Session::$expiration instead. + */ + public int $sessionExpiration = 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! + * + * @deprecated use Config\Session::$savePath instead. + */ + public string $sessionSavePath = 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. + * + * @deprecated use Config\Session::$matchIP instead. + */ + public bool $sessionMatchIP = false; + + /** + * -------------------------------------------------------------------------- + * Session Time to Update + * -------------------------------------------------------------------------- + * + * How many seconds between CI regenerating the session ID. + * + * @deprecated use Config\Session::$timeToUpdate instead. + */ + public int $sessionTimeToUpdate = 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. + * + * @deprecated use Config\Session::$regenerateDestroy instead. + */ + public bool $sessionRegenerateDestroy = false; + + /** + * -------------------------------------------------------------------------- + * Session Database Group + * -------------------------------------------------------------------------- + * + * DB Group for the database session. + * + * @deprecated use Config\Session::$DBGroup instead. + */ + public ?string $sessionDBGroup = null; + + /** + * -------------------------------------------------------------------------- + * Cookie Prefix + * -------------------------------------------------------------------------- + * + * Set a cookie name prefix if you need to avoid collisions. + * + * @deprecated use Config\Cookie::$prefix property instead. + */ + public string $cookiePrefix = ''; + + /** + * -------------------------------------------------------------------------- + * Cookie Domain + * -------------------------------------------------------------------------- + * + * Set to `.your-domain.com` for site-wide cookies. + * + * @deprecated use Config\Cookie::$domain property instead. + */ + public string $cookieDomain = ''; + + /** + * -------------------------------------------------------------------------- + * Cookie Path + * -------------------------------------------------------------------------- + * + * Typically will be a forward slash. + * + * @deprecated use Config\Cookie::$path property instead. + */ + public string $cookiePath = '/'; + + /** + * -------------------------------------------------------------------------- + * Cookie Secure + * -------------------------------------------------------------------------- + * + * Cookie will only be set if a secure HTTPS connection exists. + * + * @deprecated use Config\Cookie::$secure property instead. + */ + public bool $cookieSecure = false; + + /** + * -------------------------------------------------------------------------- + * Cookie HttpOnly + * -------------------------------------------------------------------------- + * + * Cookie will only be accessible via HTTP(S) (no JavaScript). + * + * @deprecated use Config\Cookie::$httponly property instead. + */ + public bool $cookieHTTPOnly = 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`, `$cookieSecure` must also be set. + * + * @deprecated use Config\Cookie::$samesite property instead. + */ + public ?string $cookieSameSite = 'Lax'; + + /** + * -------------------------------------------------------------------------- + * 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 + */ + public array $proxyIPs = []; + + /** + * -------------------------------------------------------------------------- + * CSRF Token Name + * -------------------------------------------------------------------------- + * + * The token name. + * + * @deprecated Use `Config\Security` $tokenName property instead of using this property. + */ + public string $CSRFTokenName = 'csrf_test_name'; + + /** + * -------------------------------------------------------------------------- + * CSRF Header Name + * -------------------------------------------------------------------------- + * + * The header name. + * + * @deprecated Use `Config\Security` $headerName property instead of using this property. + */ + public string $CSRFHeaderName = 'X-CSRF-TOKEN'; + + /** + * -------------------------------------------------------------------------- + * CSRF Cookie Name + * -------------------------------------------------------------------------- + * + * The cookie name. + * + * @deprecated Use `Config\Security` $cookieName property instead of using this property. + */ + public string $CSRFCookieName = 'csrf_cookie_name'; + + /** + * -------------------------------------------------------------------------- + * CSRF Expire + * -------------------------------------------------------------------------- + * + * The number in seconds the token should expire. + * + * @deprecated Use `Config\Security` $expire property instead of using this property. + */ + public int $CSRFExpire = 7200; + + /** + * -------------------------------------------------------------------------- + * CSRF Regenerate + * -------------------------------------------------------------------------- + * + * Regenerate token on every submission? + * + * @deprecated Use `Config\Security` $regenerate property instead of using this property. + */ + public bool $CSRFRegenerate = true; + + /** + * -------------------------------------------------------------------------- + * CSRF Redirect + * -------------------------------------------------------------------------- + * + * Redirect to previous page with error on failure? + * + * @deprecated Use `Config\Security` $redirect property instead of using this property. + */ + public bool $CSRFRedirect = false; + + /** + * -------------------------------------------------------------------------- + * CSRF SameSite + * -------------------------------------------------------------------------- + * + * Setting for CSRF SameSite cookie token. Allowed values are: + * - None + * - Lax + * - Strict + * - '' + * + * Defaults to `Lax` as recommended in this link: + * + * @see https://portswigger.net/web-security/csrf/samesite-cookies + * + * @deprecated `Config\Cookie` $samesite property is used. + */ + public string $CSRFSameSite = 'Lax'; + + /** + * -------------------------------------------------------------------------- + * 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..abd9df9 --- /dev/null +++ b/app/Config/Autoload.php @@ -0,0 +1,97 @@ + SYSTEMPATH, + * 'App' => APPPATH + * ]; + * + * @var array|string> + * @phpstan-var array> + */ + public $psr4 = [ + APP_NAMESPACE => APPPATH, // For custom app namespace + 'Config' => APPPATH . 'Config', + ]; + + /** + * ------------------------------------------------------------------- + * 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 + */ + 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 string[] + * @phpstan-var list + */ + public $files = []; + + /** + * ------------------------------------------------------------------- + * Helpers + * ------------------------------------------------------------------- + * Prototype: + * $helpers = [ + * 'form', + * ]; + * + * @var string[] + * @phpstan-var list + */ + public $helpers = []; +} diff --git a/app/Config/Boot/development.php b/app/Config/Boot/development.php new file mode 100644 index 0000000..05a8612 --- /dev/null +++ b/app/Config/Boot/development.php @@ -0,0 +1,32 @@ + + */ + 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 + */ + 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 + */ + public array $redis = [ + 'host' => '127.0.0.1', + 'password' => null, + 'port' => 6379, + 'timeout' => 0, + '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 + */ + public array $validHandlers = [ + 'dummy' => DummyHandler::class, + 'file' => FileHandler::class, + 'memcached' => MemcachedHandler::class, + 'predis' => PredisHandler::class, + 'redis' => RedisHandler::class, + 'wincache' => WincacheHandler::class, + ]; +} diff --git a/app/Config/Constants.php b/app/Config/Constants.php new file mode 100644 index 0000000..47b92f8 --- /dev/null +++ b/app/Config/Constants.php @@ -0,0 +1,94 @@ +` element. + * + * Will default to self if not overridden + * + * @var string|string[]|null + */ + public $baseURI; + + /** + * Lists the URLs for workers and embedded frame contents + * + * @var string|string[] + */ + public $childSrc = 'self'; + + /** + * Limits the origins that you can connect to (via XHR, + * WebSockets, and EventSource). + * + * @var string|string[] + */ + public $connectSrc = 'self'; + + /** + * Specifies the origins that can serve web fonts. + * + * @var string|string[] + */ + public $fontSrc; + + /** + * Lists valid endpoints for submission from `
` tags. + * + * @var string|string[] + */ + public $formAction = 'self'; + + /** + * Specifies the sources that can embed the current page. + * This directive applies to ``, `