diff --git a/app/Config/Cache.php b/app/Config/Cache.php index a3b3bbc..e5711a3 100644 --- a/app/Config/Cache.php +++ b/app/Config/Cache.php @@ -84,6 +84,21 @@ /** * -------------------------------------------------------------------------- + * 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. + * + * @var integer + */ + public $ttl = 60; + + /** + * -------------------------------------------------------------------------- * File settings * -------------------------------------------------------------------------- * Your file storage preferences can be specified below, if you are using diff --git a/public/index.php b/public/index.php index cd60bae..7737302 100644 --- a/public/index.php +++ b/public/index.php @@ -17,8 +17,9 @@ // Load our paths config file // This is the line that might need to be changed, depending on your folder structure. -require realpath(FCPATH . '../app/Config/Paths.php') ?: FCPATH . '../app/Config/Paths.php'; +$pathsConfig = FCPATH . '../app/Config/Paths.php'; // ^^^ Change this if you move your application folder +require realpath($pathsConfig) ?: $pathsConfig; $paths = new Config\Paths(); diff --git a/spark b/spark index c4ad645..f62aedd 100755 --- a/spark +++ b/spark @@ -33,8 +33,9 @@ define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR); // Load our paths config file -require realpath('app/Config/Paths.php') ?: 'app/Config/Paths.php'; +$pathsConfig = 'app/Config/Paths.php'; // ^^^ Change this line if you move your application folder +require realpath($pathsConfig) ?: $pathsConfig; $paths = new Config\Paths(); diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 273be08..162d898 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -22,17 +22,17 @@ * An autoloader that uses both PSR4 autoloading, and traditional classmaps. * * Given a foo-bar package of classes in the file system at the following paths: - *``` + * ``` * /path/to/packages/foo-bar/ * /src * Baz.php # Foo\Bar\Baz * Qux/ * Quux.php # Foo\Bar\Qux\Quux - *``` + * ``` * you can add the path to the configuration array that is passed in the constructor. * The Config array consists of 2 primary keys, both of which are associative arrays: * 'psr4', and 'classmap'. - *``` + * ``` * $Config = [ * 'psr4' => [ * 'Foo\Bar' => '/path/to/packages/foo-bar' @@ -41,9 +41,9 @@ * 'MyClass' => '/path/to/class/file.php' * ] * ]; - *``` + * ``` * Example: - *``` + * ``` * register(); - *``` + * ``` */ class Autoloader { @@ -258,15 +258,6 @@ { if (strpos($class, '\\') === false) { - $class = 'Config\\' . $class; - $filePath = APPPATH . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'; - $filename = $this->includeFile($filePath); - - if ($filename) - { - return $filename; - } - return false; } @@ -353,7 +344,9 @@ return; } - /** @var ClassLoader $composer */ + /** + * @var ClassLoader $composer + */ $composer = include COMPOSER_PATH; $paths = $composer->getPrefixesPsr4(); $classes = $composer->getClassMap(); diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 1f311ad..a477f71 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -983,7 +983,7 @@ // If the option didn't have a value, simply return TRUE // so they know it was set, otherwise return the actual value. - $val = static::$options[$name] === null ? true : static::$options[$name]; + $val = static::$options[$name] ?? true; return $val; } diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php index 91afb21..c67b218 100644 --- a/system/Cache/Handlers/FileHandler.php +++ b/system/Cache/Handlers/FileHandler.php @@ -285,35 +285,13 @@ { $key = static::validateKey($key, $this->prefix); - if (! is_file($this->path . $key)) + if (false === $data = $this->getItem($key)) { return false; // This will return null in a future release } - $data = @unserialize(file_get_contents($this->path . $key)); - - if (! is_array($data) || ! isset($data['ttl'])) - { - return false; // This will return null in a future release - } - - // Consider expired items as missing - $expire = $data['time'] + $data['ttl']; - - // @phpstan-ignore-next-line - if ($data['ttl'] > 0 && time() > $expire) - { - // If the file is still there then remove it - if (is_file($this->path . $key)) - { - unlink($this->path . $key); - } - - return false; // This will return null in a future release - } - return [ - 'expire' => $expire, + 'expire' => $data['time'] + $data['ttl'], 'mtime' => filemtime($this->path . $key), 'data' => $data['data'], ]; @@ -348,15 +326,19 @@ return false; } - $data = unserialize(file_get_contents($this->path . $filename)); + $data = @unserialize(file_get_contents($this->path . $filename)); + if (! is_array($data) || ! isset($data['ttl'])) + { + return false; + } // @phpstan-ignore-next-line if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl']) { - // If the file is still there then remove it + // If the file is still there then try to remove it if (is_file($this->path . $filename)) { - unlink($this->path . $filename); + @unlink($this->path . $filename); } return false; diff --git a/system/Cache/Handlers/MemcachedHandler.php b/system/Cache/Handlers/MemcachedHandler.php index 7452330..e6a0ce2 100644 --- a/system/Cache/Handlers/MemcachedHandler.php +++ b/system/Cache/Handlers/MemcachedHandler.php @@ -351,7 +351,7 @@ return false; // This will return null in a future release } - list($data, $time, $limit) = $stored; + [$data, $time, $limit] = $stored; // Calculate the remaining time to live from the original limit $ttl = time() - $time - $limit; diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 56a01dc..92bb010 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -44,11 +44,8 @@ /** * The current version of CodeIgniter Framework */ - const CI_VERSION = '4.1.2'; + const CI_VERSION = '4.1.3'; - /** - * @var string - */ private const MIN_PHP_VERSION = '7.3'; /** @@ -474,7 +471,7 @@ // Save our current URI as the previous URI in the session // for safer, more accurate use with `previous_url()` helper function. - $this->storePreviousURL((string) current_url(true)); + $this->storePreviousURL(current_url(true)); unset($uri); @@ -1080,7 +1077,7 @@ if (isset($_SESSION)) { - $_SESSION['_ci_previous_url'] = (string) $uri; + $_SESSION['_ci_previous_url'] = URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()); } } diff --git a/system/Commands/Generators/ValidationGenerator.php b/system/Commands/Generators/ValidationGenerator.php index 13fe3e2..9a79d47 100644 --- a/system/Commands/Generators/ValidationGenerator.php +++ b/system/Commands/Generators/ValidationGenerator.php @@ -12,7 +12,6 @@ namespace CodeIgniter\Commands\Generators; use CodeIgniter\CLI\BaseCommand; -use CodeIgniter\CLI\CLI; use CodeIgniter\CLI\GeneratorTrait; /** diff --git a/system/Commands/Utilities/Environment.php b/system/Commands/Utilities/Environment.php new file mode 100644 index 0000000..1fa4331 --- /dev/null +++ b/system/Commands/Utilities/Environment.php @@ -0,0 +1,160 @@ +]'; + + /** + * The Command's arguments + * + * @var array + */ + protected $arguments = [ + 'environment' => '[Optional] The new environment to set. If none is provided, this will print the current environment.', + ]; + + /** + * The Command's options + * + * @var array + */ + protected $options = []; + + /** + * Allowed values for environment. `testing` is excluded + * since spark won't work on it. + * + * @var array + */ + private static $knownTypes = [ + 'production', + 'development', + ]; + + /** + * @inheritDoc + * + * @param array $params + * + * @return void + */ + public function run(array $params) + { + if ($params === []) + { + CLI::write(sprintf('Your environment is currently set as %s.', CLI::color($_SERVER['CI_ENVIRONMENT'] ?? ENVIRONMENT, 'green'))); + CLI::newLine(); + + return; + } + + $env = strtolower(array_shift($params)); + + if ($env === 'testing') + { + CLI::error('The "testing" environment is reserved for PHPUnit testing.', 'light_gray', 'red'); + CLI::error('You will not be able to run spark under a "testing" environment.', 'light_gray', 'red'); + CLI::newLine(); + + return; + } + + if (! in_array($env, self::$knownTypes, true)) + { + CLI::error(sprintf('Invalid environment type "%s". Expected one of "%s".', $env, implode('" and "', self::$knownTypes)), 'light_gray', 'red'); + CLI::newLine(); + + return; + } + + if (! $this->writeNewEnvironmentToEnvFile($env)) + { + CLI::error('Error in writing new environment to .env file.', 'light_gray', 'red'); + CLI::newLine(); + + return; + } + + // force DotEnv to reload the new environment + // however we cannot redefine the ENVIRONMENT constant + putenv('CI_ENVIRONMENT'); + unset($_ENV['CI_ENVIRONMENT'], $_SERVER['CI_ENVIRONMENT']); + (new DotEnv(ROOTPATH))->load(); + + CLI::write(sprintf('Environment is successfully changed to "%s".', $env), 'green'); + CLI::write('The ENVIRONMENT constant will be changed in the next script execution.'); + CLI::newLine(); + } + + /** + * @see https://regex101.com/r/4sSORp/1 for the regex in action + * + * @param string $newEnv + * + * @return boolean + */ + private function writeNewEnvironmentToEnvFile(string $newEnv): bool + { + $baseEnv = ROOTPATH . 'env'; + $envFile = ROOTPATH . '.env'; + + if (! is_file($envFile)) + { + if (! is_file($baseEnv)) + { + CLI::write('Both default shipped `env` file and custom `.env` are missing.', 'yellow'); + CLI::write('It is impossible to write the new environment type.', 'yellow'); + CLI::newLine(); + + return false; + } + + copy($baseEnv, $envFile); + } + + $pattern = preg_quote($_SERVER['CI_ENVIRONMENT'] ?? ENVIRONMENT, '/'); + $pattern = sprintf('/^[#\s]*CI_ENVIRONMENT[=\s]+%s$/m', $pattern); + + return file_put_contents( + $envFile, + preg_replace($pattern, "\nCI_ENVIRONMENT = {$newEnv}", file_get_contents($envFile), -1, $count) + ) !== false && $count > 0; + } +} diff --git a/system/Common.php b/system/Common.php index acdc668..f975ab3 100644 --- a/system/Common.php +++ b/system/Common.php @@ -740,15 +740,36 @@ if (! function_exists('is_cli')) { /** - * Is CLI? - * - * Test to see if a request was made from the command line. + * Check if PHP was invoked from the command line. * * @return boolean + * + * @codeCoverageIgnore Cannot be tested fully as PHPUnit always run in CLI */ function is_cli(): bool { - return (PHP_SAPI === 'cli' || defined('STDIN')); + if (PHP_SAPI === 'cli') + { + return true; + } + + if (defined('STDIN')) + { + return true; + } + + if (stristr(PHP_SAPI, 'cgi') && getenv('TERM')) + { + return true; + } + + if (! isset($_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT']) && isset($_SERVER['argv']) && count($_SERVER['argv']) > 0) + { + return true; + } + + // if source of request is from CLI, the `$_SERVER` array will not populate this key + return ! isset($_SERVER['REQUEST_METHOD']); } } @@ -1278,14 +1299,16 @@ * * @see https://github.com/laravel/framework/blob/8.x/src/Illuminate/Support/helpers.php */ -// @codeCoverageIgnoreStart if (! function_exists('class_basename')) { /** * Get the class "basename" of the given object / class. * - * @param string|object $class + * @param string|object $class + * * @return string + * + * @codeCoverageIgnore */ function class_basename($class) { @@ -1300,8 +1323,11 @@ /** * Returns all traits used by a class, its parent classes and trait of their traits. * - * @param object|string $class + * @param object|string $class + * * @return array + * + * @codeCoverageIgnore */ function class_uses_recursive($class) { @@ -1327,8 +1353,11 @@ /** * Returns all traits used by a trait and its traits. * - * @param string $trait + * @param string $trait + * * @return array + * + * @codeCoverageIgnore */ function trait_uses_recursive($trait) { @@ -1342,4 +1371,3 @@ return $traits; } } -// @codeCoverageIgnoreEnd diff --git a/system/Config/DotEnv.php b/system/Config/DotEnv.php index 75140f0..54374ad 100644 --- a/system/Config/DotEnv.php +++ b/system/Config/DotEnv.php @@ -90,7 +90,7 @@ // If there is an equal sign, then we know we are assigning a variable. if (strpos($line, '=') !== false) { - list($name, $value) = $this->normaliseVariable($line); + [$name, $value] = $this->normaliseVariable($line); $vars[$name] = $value; $this->setVariable($name, $value); } @@ -143,7 +143,7 @@ // Split our compound string into its parts. if (strpos($name, '=') !== false) { - list($name, $value) = explode('=', $name, 2); + [$name, $value] = explode('=', $name, 2); } $name = trim($name); diff --git a/system/Config/Factories.php b/system/Config/Factories.php index 9222e5e..22a9a27 100644 --- a/system/Config/Factories.php +++ b/system/Config/Factories.php @@ -23,7 +23,7 @@ * instantiation checks. * * @method static Model models(...$arguments) - * @method static \Config\BaseConfig config(...$arguments) + * @method static BaseConfig config(...$arguments) */ class Factories { diff --git a/system/Cookie/Cookie.php b/system/Cookie/Cookie.php index f6ebf37..614f327 100644 --- a/system/Cookie/Cookie.php +++ b/system/Cookie/Cookie.php @@ -184,7 +184,7 @@ { if (strpos($part, '=') !== false) { - list($attr, $val) = explode('=', $part); + [$attr, $val] = explode('=', $part); } else { @@ -220,15 +220,19 @@ unset($options['max-age']); } - // to retain backward compatibility with previous versions' fallback - $prefix = $options['prefix'] ?: self::$defaults['prefix']; - $path = $options['path'] ?: self::$defaults['path']; - $domain = $options['domain'] ?: self::$defaults['domain']; - $secure = $options['secure'] ?: self::$defaults['secure']; - $httponly = $options['httponly'] ?: self::$defaults['httponly']; + // to preserve backward compatibility with array-based cookies in previous CI versions + $prefix = $options['prefix'] ?: self::$defaults['prefix']; + $path = $options['path'] ?: self::$defaults['path']; + $domain = $options['domain'] ?: self::$defaults['domain']; + + // empty string SameSite should use the default for browsers $samesite = $options['samesite'] ?: self::$defaults['samesite']; - $this->validateName($name, $options['raw']); + $raw = $options['raw']; + $secure = $options['secure']; + $httponly = $options['httponly']; + + $this->validateName($name, $raw); $this->validatePrefix($prefix, $secure, $path, $domain); $this->validateSameSite($samesite, $secure); @@ -241,7 +245,7 @@ $this->secure = $secure; $this->httponly = $httponly; $this->samesite = ucfirst(strtolower($samesite)); - $this->raw = $options['raw']; + $this->raw = $raw; } //========================================================================= diff --git a/system/Cookie/CookieInterface.php b/system/Cookie/CookieInterface.php index 1dddb13..550323f 100644 --- a/system/Cookie/CookieInterface.php +++ b/system/Cookie/CookieInterface.php @@ -29,24 +29,18 @@ * Cookies are not sent on normal cross-site subrequests (for example to * load images or frames into a third party site), but are sent when a * user is navigating to the origin site (i.e. when following a link). - * - * @var string */ public const SAMESITE_LAX = 'lax'; /** * Cookies will only be sent in a first-party context and not be sent * along with requests initiated by third party websites. - * - * @var string */ public const SAMESITE_STRICT = 'strict'; /** * RFC 6265 allowed values for the "SameSite" attribute. * - * @var string[] - * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite */ public const ALLOWED_SAMESITE_VALUES = [ @@ -58,8 +52,6 @@ /** * Expires date format. * - * @var string - * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Date * @see https://tools.ietf.org/html/rfc7231#section-7.1.1.2 */ diff --git a/system/Database/Forge.php b/system/Database/Forge.php index a8975f1..f2e2ee5 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -964,8 +964,8 @@ $field = [ 'name' => $key, - 'new_name' => isset($attributes['NAME']) ? $attributes['NAME'] : null, - 'type' => isset($attributes['TYPE']) ? $attributes['TYPE'] : null, + 'new_name' => $attributes['NAME'] ?? null, + 'type' => $attributes['TYPE'] ?? null, 'length' => '', 'unsigned' => '', 'null' => '', diff --git a/system/Database/MySQLi/Result.php b/system/Database/MySQLi/Result.php index 5488212..4be7fc9 100644 --- a/system/Database/MySQLi/Result.php +++ b/system/Database/MySQLi/Result.php @@ -98,7 +98,7 @@ $retVal[$i] = new stdClass(); $retVal[$i]->name = $data->name; $retVal[$i]->type = $data->type; - $retVal[$i]->type_name = in_array($data->type, [1, 247], true) ? 'char' : (isset($dataTypes[$data->type]) ? $dataTypes[$data->type] : null); + $retVal[$i]->type_name = in_array($data->type, [1, 247], true) ? 'char' : ($dataTypes[$data->type] ?? null); $retVal[$i]->max_length = $data->max_length; $retVal[$i]->primary_key = (int) ($data->flags & 2); $retVal[$i]->length = $data->length; diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php index d77bcb2..f23d6dc 100644 --- a/system/Database/Postgre/Builder.php +++ b/system/Database/Postgre/Builder.php @@ -310,7 +310,8 @@ */ protected function _updateBatch(string $table, array $values, string $index): string { - $ids = []; + $ids = []; + $final = []; foreach ($values as $val) { $ids[] = $val[$index]; @@ -319,13 +320,15 @@ { if ($field !== $index) { + $final[$field] = $final[$field] ?? []; + $final[$field][] = "WHEN {$val[$index]} THEN {$val[$field]}"; } } } $cases = ''; - foreach ($final as $k => $v) // @phpstan-ignore-line + foreach ($final as $k => $v) { $cases .= "{$k} = (CASE {$index}\n" . implode("\n", $v) @@ -383,11 +386,11 @@ * * @see https://www.postgresql.org/docs/9.2/static/functions-matching.html * - * @param string|null $prefix - * @param string $column - * @param string|null $not - * @param string $bind - * @param boolean $insensitiveSearch + * @param string|null $prefix + * @param string $column + * @param string|null $not + * @param string $bind + * @param boolean $insensitiveSearch * * @return string $like_statement */ diff --git a/system/Database/Query.php b/system/Database/Query.php index e548dfc..ba84ac4 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -315,13 +315,13 @@ * * @return void * - * @see https://regex101.com/r/EUEhay/1 Test + * @see https://regex101.com/r/EUEhay/4 */ protected function compileBinds() { $sql = $this->finalQueryString; - $hasNamedBinds = preg_match('/:[a-z\d.)_(]+:/i', $sql) === 1; + $hasNamedBinds = preg_match('/:((?!=).+):/', $sql) === 1; if (empty($this->binds) || empty($this->bindMarker) diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php index c7b6b1d..0e039a0 100755 --- a/system/Database/SQLSRV/Connection.php +++ b/system/Database/SQLSRV/Connection.php @@ -11,7 +11,6 @@ namespace CodeIgniter\Database\SQLSRV; -use CodeIgniter\Database\Query; use CodeIgniter\Database\BaseConnection; use CodeIgniter\Database\Exceptions\DatabaseException; use Exception; @@ -130,12 +129,11 @@ unset($connection['UID'], $connection['PWD']); } + sqlsrv_configure('WarningsReturnAsErrors', 0); $this->connID = sqlsrv_connect($this->hostname, $connection); if ($this->connID !== false) { - sqlsrv_configure('WarningsReturnAsErrors', 0); - // Determine how identifiers are escaped $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi'); $query = $query->getResultObject(); diff --git a/system/Database/SQLSRV/Result.php b/system/Database/SQLSRV/Result.php index b3ae7f9..f5e771e 100755 --- a/system/Database/SQLSRV/Result.php +++ b/system/Database/SQLSRV/Result.php @@ -20,13 +20,6 @@ */ class Result extends BaseResult { - /** - * Row offset - * - * @var integer - */ - private $rowOffset = 0; - //-------------------------------------------------------------------- /** @@ -106,7 +99,7 @@ $retVal[$i] = new stdClass(); $retVal[$i]->name = $field['Name']; $retVal[$i]->type = $field['Type']; - $retVal[$i]->type_name = isset($dataTypes[$field['Type']]) ? $dataTypes[$field['Type']] : null; + $retVal[$i]->type_name = $dataTypes[$field['Type']] ?? null; $retVal[$i]->max_length = $field['Size']; } diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index 3bdf1fa..4547ad7 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -11,7 +11,6 @@ namespace CodeIgniter\Database\SQLite3; -use CodeIgniter\Database\Query; use CodeIgniter\Database\BaseConnection; use CodeIgniter\Database\Exceptions\DatabaseException; use ErrorException; diff --git a/system/Database/SQLite3/Result.php b/system/Database/SQLite3/Result.php index 7d1948b..bd07eac 100644 --- a/system/Database/SQLite3/Result.php +++ b/system/Database/SQLite3/Result.php @@ -76,7 +76,7 @@ $retVal[$i]->name = $this->resultID->columnName($i); // @phpstan-ignore-line $type = $this->resultID->columnType($i); // @phpstan-ignore-line $retVal[$i]->type = $type; - $retVal[$i]->type_name = isset($dataTypes[$type]) ? $dataTypes[$type] : null; + $retVal[$i]->type_name = $dataTypes[$type] ?? null; $retVal[$i]->max_length = null; $retVal[$i]->length = null; } diff --git a/system/Database/SQLite3/Table.php b/system/Database/SQLite3/Table.php index 296810a..1183f4a 100644 --- a/system/Database/SQLite3/Table.php +++ b/system/Database/SQLite3/Table.php @@ -301,12 +301,8 @@ foreach ($this->fields as $name => $details) { - $newFields[] = isset($details['new_name']) - // Are we modifying the column? - ? $details['new_name'] - : $name; - - $exFields[] = $name; + $newFields[] = $details['new_name'] ?? $name; + $exFields[] = $name; } $exFields = implode(', ', $exFields); @@ -336,9 +332,9 @@ foreach ($fields as $field) { $return[$field->name] = [ - 'type' => $field->type, - 'default' => $field->default, - 'nullable' => $field->nullable, + 'type' => $field->type, + 'default' => $field->default, + 'null' => $field->nullable, ]; if ($field->primary_key) diff --git a/system/Database/Seeder.php b/system/Database/Seeder.php index 4e9b2a7..6d32702 100644 --- a/system/Database/Seeder.php +++ b/system/Database/Seeder.php @@ -127,25 +127,16 @@ */ public function call(string $class) { - if (empty($class)) + $class = trim($class); + + if ($class === '') { throw new InvalidArgumentException('No seeder was specified.'); } - $path = str_replace('.php', '', $class) . '.php'; - - // If we have namespaced class, simply try to load it. - if (strpos($class, '\\') !== false) + if (strpos($class, '\\') === false) { - /** - * @var Seeder - */ - $seeder = new $class($this->config); - } - // Otherwise, try to load the class manually. - else - { - $path = $this->seedPath . $path; + $path = $this->seedPath . str_replace('.php', '', $class) . '.php'; if (! is_file($path)) { @@ -160,14 +151,13 @@ { require_once $path; } - - /** - * @var Seeder - */ - $seeder = new $class($this->config); // @codeCoverageIgnoreEnd } + /** + * @var Seeder + */ + $seeder = new $class($this->config); $seeder->setSilent($this->silent)->run(); unset($seeder); diff --git a/system/Email/Email.php b/system/Email/Email.php index a3c3b27..36720ba 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -1272,6 +1272,8 @@ return; case 'html': + $boundary = uniqid('B_ALT_', true); + if ($this->sendMultipart === false) { $hdr .= 'Content-Type: text/html; charset=' @@ -1280,8 +1282,6 @@ } else { - $boundary = uniqid('B_ALT_', true); - $hdr .= 'Content-Type: multipart/alternative; boundary="' . $boundary . '"'; $body .= $this->getMimeMessage() . $this->newline . $this->newline . '--' . $boundary . $this->newline @@ -1306,7 +1306,7 @@ if ($this->sendMultipart !== false) { - $this->finalBody .= '--' . $boundary . '--'; // @phpstan-ignore-line + $this->finalBody .= '--' . $boundary . '--'; } return; @@ -1432,7 +1432,7 @@ { continue; } - $name = isset($attachment['name'][1]) ? $attachment['name'][1] : basename($attachment['name'][0]); + $name = $attachment['name'][1] ?? basename($attachment['name'][0]); $body .= '--' . $boundary . $this->newline . 'Content-Type: ' . $attachment['type'] . '; name="' . $name . '"' . $this->newline . 'Content-Disposition: ' . $attachment['disposition'] . ';' . $this->newline @@ -2184,13 +2184,16 @@ $this->sendData('QUIT'); $resp = 221; break; + + default: + $resp = null; } $reply = $this->getSMTPData(); $this->debugMessage[] = '
' . $cmd . ': ' . $reply . '
'; - if ((int) static::substr($reply, 0, 3) !== $resp) // @phpstan-ignore-line + if ($resp === null || ((int) static::substr($reply, 0, 3) !== $resp)) { $this->setErrorMessage(lang('Email.SMTPError', [$reply])); @@ -2278,6 +2281,8 @@ { $data .= $this->newline; + $result = null; + for ($written = $timestamp = 0, $length = static::strlen($data); $written < $length; $written += $result) { if (($result = fwrite($this->SMTPConnect, static::substr($data, $written))) === false) @@ -2307,7 +2312,7 @@ $timestamp = 0; } - if ($result === false) // @phpstan-ignore-line + if (! is_int($result)) { $this->setErrorMessage(lang('Email.SMTPDataFailure', [$data])); diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index 0e96943..1ba881f 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -358,7 +358,7 @@ // Get parameters and clean name if (strpos($name, ':') !== false) { - list($name, $params) = explode(':', $name); + [$name, $params] = explode(':', $name); $params = explode(',', $params); array_walk($params, function (&$item) { diff --git a/system/Format/XMLFormatter.php b/system/Format/XMLFormatter.php index 1e46f6a..249f916 100644 --- a/system/Format/XMLFormatter.php +++ b/system/Format/XMLFormatter.php @@ -63,15 +63,15 @@ { foreach ($data as $key => $value) { + $key = $this->normalizeXMLTag($key); + if (is_array($value)) { - $key = $this->normalizeXMLTag($key); $subnode = $output->addChild("$key"); $this->arrayToXML($value, $subnode); } else { - $key = $this->normalizeXMLTag($key); $output->addChild("$key", htmlspecialchars("$value")); } } diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 35fb535..55797e0 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -347,7 +347,8 @@ $uri = $this->baseURI->resolveRelativeURI($url); - return (string) $uri; + // Create the string instead of casting to prevent baseURL muddling + return URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()); } //-------------------------------------------------------------------- diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 560b652..9d3e722 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -14,7 +14,6 @@ use CodeIgniter\HTTP\Exceptions\HTTPException; use CodeIgniter\HTTP\Files\FileCollection; use CodeIgniter\HTTP\Files\UploadedFile; -use CodeIgniter\HTTP\URI; use Config\App; use Config\Services; use InvalidArgumentException; @@ -270,7 +269,7 @@ foreach (explode('/', $_SERVER['SCRIPT_NAME']) as $i => $segment) { // If these segments are not the same then we're done - if ($segment !== $segments[$i]) + if (! isset($segments[$i]) || $segment !== $segments[$i]) { break; } diff --git a/system/HTTP/Negotiate.php b/system/HTTP/Negotiate.php index 4dea868..fb2608f 100644 --- a/system/HTTP/Negotiate.php +++ b/system/HTTP/Negotiate.php @@ -391,8 +391,8 @@ { // PHPDocumentor v2 cannot parse yet the shorter list syntax, // causing no API generation for the file. - list($aType, $aSubType) = explode('/', $acceptable['value']); - list($sType, $sSubType) = explode('/', $supported['value']); + [$aType, $aSubType] = explode('/', $acceptable['value']); + [$sType, $sSubType] = explode('/', $supported['value']); // If the types don't match, we're done. if ($aType !== $sType) diff --git a/system/HTTP/RedirectResponse.php b/system/HTTP/RedirectResponse.php index 50061c8..4f31e90 100644 --- a/system/HTTP/RedirectResponse.php +++ b/system/HTTP/RedirectResponse.php @@ -36,7 +36,7 @@ // for better security. if (strpos($uri, 'http') !== 0) { - $uri = (string) current_url(true)->resolveRelativeURI($uri); + $uri = site_url($uri); } return $this->redirect($uri, $method, $code); diff --git a/system/HTTP/RequestTrait.php b/system/HTTP/RequestTrait.php index 0f4de37..2c9a0f9 100644 --- a/system/HTTP/RequestTrait.php +++ b/system/HTTP/RequestTrait.php @@ -60,7 +60,7 @@ /** * @deprecated $this->proxyIPs property will be removed in the future */ - $proxyIPs = isset($this->proxyIPs) ? $this->proxyIPs : config('App')->proxyIPs; + $proxyIPs = $this->proxyIPs ?? config('App')->proxyIPs; if (! empty($proxyIPs) && ! is_array($proxyIPs)) { $proxyIPs = explode(',', str_replace(' ', '', $proxyIPs)); diff --git a/system/HTTP/ResponseInterface.php b/system/HTTP/ResponseInterface.php index bfa493b..c1f2ed0 100644 --- a/system/HTTP/ResponseInterface.php +++ b/system/HTTP/ResponseInterface.php @@ -38,32 +38,29 @@ * From https://en.wikipedia.org/wiki/List_of_HTTP_status_codes */ // Informational - const HTTP_CONTINUE = 100; - const HTTP_SWITCHING_PROTOCOLS = 101; - const HTTP_PROCESSING = 102; - const HTTP_EARLY_HINTS = 103; - // Success - const HTTP_OK = 200; - const HTTP_CREATED = 201; - const HTTP_ACCEPTED = 202; - const HTTP_NONAUTHORITATIVE_INFORMATION = 203; - const HTTP_NO_CONTENT = 204; - const HTTP_RESET_CONTENT = 205; - const HTTP_PARTIAL_CONTENT = 206; - const HTTP_MULTI_STATUS = 207; - const HTTP_ALREADY_REPORTED = 208; - const HTTP_IM_USED = 226; - // Redirection - const HTTP_MULTIPLE_CHOICES = 300; - const HTTP_MOVED_PERMANENTLY = 301; - const HTTP_FOUND = 302; - const HTTP_SEE_OTHER = 303; - const HTTP_NOT_MODIFIED = 304; - const HTTP_USE_PROXY = 305; - const HTTP_SWITCH_PROXY = 306; - const HTTP_TEMPORARY_REDIRECT = 307; - const HTTP_PERMANENT_REDIRECT = 308; - // Client Error + const HTTP_CONTINUE = 100; + const HTTP_SWITCHING_PROTOCOLS = 101; + const HTTP_PROCESSING = 102; + const HTTP_EARLY_HINTS = 103; + const HTTP_OK = 200; + const HTTP_CREATED = 201; + const HTTP_ACCEPTED = 202; + const HTTP_NONAUTHORITATIVE_INFORMATION = 203; + const HTTP_NO_CONTENT = 204; + const HTTP_RESET_CONTENT = 205; + const HTTP_PARTIAL_CONTENT = 206; + const HTTP_MULTI_STATUS = 207; + const HTTP_ALREADY_REPORTED = 208; + const HTTP_IM_USED = 226; + const HTTP_MULTIPLE_CHOICES = 300; + const HTTP_MOVED_PERMANENTLY = 301; + const HTTP_FOUND = 302; + const HTTP_SEE_OTHER = 303; + const HTTP_NOT_MODIFIED = 304; + const HTTP_USE_PROXY = 305; + const HTTP_SWITCH_PROXY = 306; + const HTTP_TEMPORARY_REDIRECT = 307; + const HTTP_PERMANENT_REDIRECT = 308; const HTTP_BAD_REQUEST = 400; const HTTP_UNAUTHORIZED = 401; const HTTP_PAYMENT_REQUIRED = 402; @@ -94,7 +91,6 @@ const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; const HTTP_CLIENT_CLOSED_REQUEST = 499; - // Server Error const HTTP_INTERNAL_SERVER_ERROR = 500; const HTTP_NOT_IMPLEMENTED = 501; const HTTP_BAD_GATEWAY = 502; diff --git a/system/HTTP/URI.php b/system/HTTP/URI.php index 4eb1f39..3fc4434 100644 --- a/system/HTTP/URI.php +++ b/system/HTTP/URI.php @@ -21,15 +21,11 @@ { /** * Sub-delimiters used in query strings and fragments. - * - * @const string */ const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;='; /** * Unreserved characters used in paths, query strings, and fragments. - * - * @const string */ const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~'; diff --git a/system/Helpers/filesystem_helper.php b/system/Helpers/filesystem_helper.php index ddbbcf5..5735537 100644 --- a/system/Helpers/filesystem_helper.php +++ b/system/Helpers/filesystem_helper.php @@ -75,6 +75,59 @@ // ------------------------------------------------------------------------ +if (! function_exists('directory_mirror')) +{ + /** + * Recursively copies the files and directories of the origin directory + * into the target directory, i.e. "mirror" its contents. + * + * @param string $originDir + * @param string $targetDir + * @param boolean $overwrite Whether individual files overwrite on collision + * + * @return void + * + * @throws InvalidArgumentException + */ + function directory_mirror(string $originDir, string $targetDir, bool $overwrite = true): void + { + if (! is_dir($originDir = rtrim($originDir, '\\/'))) + { + throw new InvalidArgumentException(sprintf('The origin directory "%s" was not found.', $originDir)); + } + + if (! is_dir($targetDir = rtrim($targetDir, '\\/'))) + { + @mkdir($targetDir, 0755, true); + } + + $dirLen = strlen($originDir); + + /** + * @var SplFileInfo $file + */ + foreach (new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($originDir, FilesystemIterator::SKIP_DOTS), + RecursiveIteratorIterator::SELF_FIRST + ) as $file) + { + $origin = $file->getPathname(); + $target = $targetDir . substr($origin, $dirLen); + + if ($file->isDir()) + { + mkdir($target, 0755); + } + elseif (! is_file($target) || ($overwrite && is_file($target))) + { + copy($origin, $target); + } + } + } +} + +// ------------------------------------------------------------------------ + if (! function_exists('write_file')) { /** @@ -159,12 +212,12 @@ $isDir = $object->isDir(); if ($isDir && $delDir) { - @rmdir($object->getPathname()); + rmdir($object->getPathname()); continue; } if (! $isDir) { - @unlink($object->getPathname()); + unlink($object->getPathname()); } } } @@ -264,7 +317,7 @@ try { - $fp = @opendir($sourceDir); { + $fp = opendir($sourceDir); { // reset the array and make sure $source_dir has a trailing slash on the initial call if ($recursion === false) { @@ -321,6 +374,8 @@ return null; } + $fileInfo = []; + if (is_string($returnedValues)) { $returnedValues = explode(',', $returnedValues); @@ -356,7 +411,7 @@ } } - return $fileInfo; // @phpstan-ignore-line + return $fileInfo; } } @@ -448,6 +503,24 @@ // ------------------------------------------------------------------------ +if (! function_exists('same_file')) +{ + /** + * Checks if two files both exist and have identical hashes + * + * @param string $file1 + * @param string $file2 + * + * @return boolean Same or not + */ + function same_file(string $file1, string $file2): bool + { + return is_file($file1) && is_file($file2) && md5_file($file1) === md5_file($file2); + } +} + +// ------------------------------------------------------------------------ + if (! function_exists('set_realpath')) { /** diff --git a/system/Helpers/test_helper.php b/system/Helpers/test_helper.php index c6f9beb..e051d9d 100644 --- a/system/Helpers/test_helper.php +++ b/system/Helpers/test_helper.php @@ -9,6 +9,7 @@ * file that was distributed with this source code. */ +use CodeIgniter\Model; use CodeIgniter\Test\Fabricator; /** diff --git a/system/Helpers/text_helper.php b/system/Helpers/text_helper.php index eebe3ca..0e3baed 100755 --- a/system/Helpers/text_helper.php +++ b/system/Helpers/text_helper.php @@ -122,7 +122,7 @@ */ if (count($temp) === 1) { - $out .= '&#' . array_shift($temp) . ';'; + $out .= '&#' . array_shift($temp) . ';'; $count = 1; } @@ -140,9 +140,9 @@ if (count($temp) === $count) { $number = ($count === 3) ? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64) : (($temp[0] % 32) * 64) + ($temp[1] % 64); - $out .= '&#' . $number . ';'; - $count = 1; - $temp = []; + $out .= '&#' . $number . ';'; + $count = 1; + $temp = []; } // If this is the last iteration, just output whatever we have elseif ($i === $s) @@ -486,7 +486,7 @@ } // Trim the word down $temp .= mb_substr($line, 0, $charlim - 1); - $line = mb_substr($line, $charlim - 1); + $line = mb_substr($line, $charlim - 1); } // If $temp contains data it means we had to split up an over-length @@ -811,14 +811,14 @@ $phrasePos = stripos($text, $phrase); $phraseLen = strlen($phrase); } - elseif (! isset($phrase)) + else { $phrasePos = $radius / 2; $phraseLen = 1; } - $pre = explode(' ', substr($text, 0, $phrasePos)); // @phpstan-ignore-line - $pos = explode(' ', substr($text, $phrasePos + $phraseLen)); // @phpstan-ignore-line + $pre = explode(' ', substr($text, 0, $phrasePos)); + $pos = explode(' ', substr($text, $phrasePos + $phraseLen)); $prev = ' '; $post = ' '; diff --git a/system/Helpers/url_helper.php b/system/Helpers/url_helper.php index f58045a..2424a98 100644 --- a/system/Helpers/url_helper.php +++ b/system/Helpers/url_helper.php @@ -205,20 +205,9 @@ */ function uri_string(bool $relative = false): string { - $request = Services::request(); - $uri = $request->uri; - - // An absolute path is equivalent to getPath() - if (! $relative) - { - return $uri->getPath(); - } - - // Remove the baseURL from the entire URL - $url = (string) $uri->__toString(); - $baseURL = rtrim($request->config->baseURL, '/ ') . '/'; - - return substr($url, strlen($baseURL)); + return $relative + ? ltrim(Services::request()->getPath(), '/') + : Services::request()->getUri()->getPath(); } } diff --git a/system/I18n/Time.php b/system/I18n/Time.php index 87697c6..c50f8f4 100644 --- a/system/I18n/Time.php +++ b/system/I18n/Time.php @@ -758,7 +758,7 @@ */ protected function setValue(string $name, $value) { - list($year, $month, $day, $hour, $minute, $second) = explode('-', $this->format('Y-n-j-G-i-s')); + [$year, $month, $day, $hour, $minute, $second] = explode('-', $this->format('Y-n-j-G-i-s')); $$name = $value; return Time::create( diff --git a/system/Images/Handlers/BaseHandler.php b/system/Images/Handlers/BaseHandler.php index 9eb007a..b721bce 100644 --- a/system/Images/Handlers/BaseHandler.php +++ b/system/Images/Handlers/BaseHandler.php @@ -638,14 +638,14 @@ $origWidth = $this->image()->origWidth; $origHeight = $this->image()->origHeight; - list($cropWidth, $cropHeight) = $this->calcAspectRatio($width, $height, $origWidth, $origHeight); + [$cropWidth, $cropHeight] = $this->calcAspectRatio($width, $height, $origWidth, $origHeight); if (is_null($height)) { $height = ceil(($width / $cropWidth) * $cropHeight); } - list($x, $y) = $this->calcCropCoords($cropWidth, $cropHeight, $origWidth, $origHeight, $position); + [$x, $y] = $this->calcCropCoords($cropWidth, $cropHeight, $origWidth, $origHeight, $position); return $this->crop($cropWidth, $cropHeight, $x, $y) ->resize($width, $height); diff --git a/system/Images/Handlers/ImageMagickHandler.php b/system/Images/Handlers/ImageMagickHandler.php index b43863a..53dc66e 100644 --- a/system/Images/Handlers/ImageMagickHandler.php +++ b/system/Images/Handlers/ImageMagickHandler.php @@ -234,10 +234,11 @@ $this->config->libraryPath = rtrim($this->config->libraryPath, '/') . '/convert'; } - $cmd = $this->config->libraryPath; + $cmd = $this->config->libraryPath; $cmd .= $action === '-version' ? ' ' . $action : ' -quality ' . $quality . ' ' . $action; $retval = 1; + $output = []; // exec() might be disabled if (function_usable('exec')) { @@ -250,7 +251,7 @@ throw ImageException::forImageProcessFailed(); } - return $output; // @phpstan-ignore-line + return $output; } //-------------------------------------------------------------------- @@ -449,7 +450,7 @@ // Color if (isset($options['color'])) { - list($r, $g, $b) = sscanf("#{$options['color']}", '#%02x%02x%02x'); + [$r, $g, $b] = sscanf("#{$options['color']}", '#%02x%02x%02x'); $cmd .= " -fill 'rgba({$r},{$g},{$b},{$options['opacity']})'"; } diff --git a/system/Language/Language.php b/system/Language/Language.php index cb66922..be66b8a 100644 --- a/system/Language/Language.php +++ b/system/Language/Language.php @@ -115,15 +115,15 @@ // Parse out the file name and the actual alias. // Will load the language file and strings. - list($file, $parsedLine) = $this->parseLine($line, $this->locale); + [$file, $parsedLine] = $this->parseLine($line, $this->locale); $output = $this->getTranslationOutput($this->locale, $file, $parsedLine); if ($output === null && strpos($this->locale, '-')) { - list($locale) = explode('-', $this->locale, 2); + [$locale] = explode('-', $this->locale, 2); - list($file, $parsedLine) = $this->parseLine($line, $locale); + [$file, $parsedLine] = $this->parseLine($line, $locale); $output = $this->getTranslationOutput($locale, $file, $parsedLine); } @@ -131,7 +131,7 @@ // if still not found, try English if ($output === null) { - list($file, $parsedLine) = $this->parseLine($line, 'en'); + [$file, $parsedLine] = $this->parseLine($line, 'en'); $output = $this->getTranslationOutput('en', $file, $parsedLine); } diff --git a/system/Log/Handlers/ChromeLoggerHandler.php b/system/Log/Handlers/ChromeLoggerHandler.php index b248072..21a1bd7 100644 --- a/system/Log/Handlers/ChromeLoggerHandler.php +++ b/system/Log/Handlers/ChromeLoggerHandler.php @@ -26,8 +26,6 @@ { /** * Version of this library - for ChromeLogger use. - * - * @var float */ const VERSION = 1.0; @@ -87,9 +85,7 @@ { parent::__construct($config); - $request = Services::request(null, true); - - $this->json['request_uri'] = (string) $request->uri; + $this->json['request_uri'] = current_url(); } //-------------------------------------------------------------------- diff --git a/system/Log/Handlers/FileHandler.php b/system/Log/Handlers/FileHandler.php index 8b608b3..362758f 100644 --- a/system/Log/Handlers/FileHandler.php +++ b/system/Log/Handlers/FileHandler.php @@ -112,6 +112,8 @@ flock($fp, LOCK_EX); + $result = null; + for ($written = 0, $length = strlen($msg); $written < $length; $written += $result) { if (($result = fwrite($fp, substr($msg, $written))) === false) @@ -131,7 +133,7 @@ chmod($filepath, $this->filePermissions); } - return is_int($result); // @phpstan-ignore-line + return is_int($result); } //-------------------------------------------------------------------- diff --git a/system/Log/Logger.php b/system/Log/Logger.php index d3054ef..c457545 100644 --- a/system/Log/Logger.php +++ b/system/Log/Logger.php @@ -409,7 +409,7 @@ // Allow us to log the file/line that we are logging from if (strpos($message, '{file}') !== false) { - list($file, $line) = $this->determineFile(); + [$file, $line] = $this->determineFile(); $replace['{file}'] = $file; $replace['{line}'] = $line; diff --git a/system/Pager/Pager.php b/system/Pager/Pager.php index 3220d12..7b15b31 100644 --- a/system/Pager/Pager.php +++ b/system/Pager/Pager.php @@ -147,12 +147,11 @@ */ protected function displayLinks(string $group, string $template): string { - $pager = new PagerRenderer($this->getDetails($group)); - if (! array_key_exists($template, $this->config->templates)) { throw PagerException::forInvalidTemplate($template); } + $pager = new PagerRenderer($this->getDetails($group)); return $this->view->setVar('pager', $pager) ->render($this->config->templates[$template]); @@ -377,7 +376,7 @@ $uri->setQueryArray($query); } - return $returnObject === true ? $uri : (string) $uri; + return $returnObject === true ? $uri : URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()); } //-------------------------------------------------------------------- diff --git a/system/Pager/PagerRenderer.php b/system/Pager/PagerRenderer.php index 37f289e..f1a4599 100644 --- a/system/Pager/PagerRenderer.php +++ b/system/Pager/PagerRenderer.php @@ -156,7 +156,7 @@ $uri->setSegment($this->segment, $this->first - 1); } - return (string) $uri; + return URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()); } //-------------------------------------------------------------------- @@ -200,7 +200,7 @@ $uri->setSegment($this->segment, $this->last + 1); } - return (string) $uri; + return URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()); } //-------------------------------------------------------------------- @@ -223,7 +223,7 @@ $uri->setSegment($this->segment, 1); } - return (string) $uri; + return URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()); } //-------------------------------------------------------------------- @@ -246,7 +246,7 @@ $uri->setSegment($this->segment, $this->pageCount); } - return (string) $uri; + return URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()); } //-------------------------------------------------------------------- @@ -269,7 +269,7 @@ $uri->setSegment($this->segment, $this->current); } - return (string) $uri; + return URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()); } //-------------------------------------------------------------------- @@ -290,8 +290,9 @@ for ($i = $this->first; $i <= $this->last; $i ++) { + $uri = $this->segment === 0 ? $uri->addQuery($this->pageSelector, $i) : $uri->setSegment($this->segment, $i); $links[] = [ - 'uri' => (string) ($this->segment === 0 ? $uri->addQuery($this->pageSelector, $i) : $uri->setSegment($this->segment, $i)), + 'uri' => URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()), 'title' => (int) $i, 'active' => ($i === $this->current), ]; @@ -359,7 +360,7 @@ $uri->setSegment($this->segment, $this->current - 1); } - return (string) $uri; + return URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()); } //-------------------------------------------------------------------- @@ -401,7 +402,7 @@ $uri->setSegment($this->segment, $this->current + 1); } - return (string) $uri; + return URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()); } /** diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 4cd4f20..b7d586e 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -13,7 +13,6 @@ use Closure; use CodeIgniter\Autoloader\FileLocator; -use CodeIgniter\HTTP\Request; use CodeIgniter\Router\Exceptions\RouterException; use Config\Modules; use Config\Services; diff --git a/system/Router/Router.php b/system/Router/Router.php index 1980bda..dcadd8b 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -716,7 +716,7 @@ return; } - list($controller, $method) = array_pad(explode('::', $segments[0]), 2, null); + [$controller, $method] = array_pad(explode('::', $segments[0]), 2, null); $this->controller = $controller; diff --git a/system/Session/Handlers/FileHandler.php b/system/Session/Handlers/FileHandler.php index 17ee5bf..dc28cd4 100644 --- a/system/Session/Handlers/FileHandler.php +++ b/system/Session/Handlers/FileHandler.php @@ -240,6 +240,8 @@ if (($length = strlen($sessionData)) > 0) { + $result = null; + for ($written = 0; $written < $length; $written += $result) { if (($result = fwrite($this->fileHandle, substr($sessionData, $written))) === false) @@ -248,7 +250,7 @@ } } - if (! is_int($result)) // @phpstan-ignore-line + if (! is_int($result)) { $this->fingerprint = md5(substr($sessionData, 0, $written)); $this->logger->error('Session: Unable to write data.'); diff --git a/system/Session/Session.php b/system/Session/Session.php index e6cab17..5532dc7 100644 --- a/system/Session/Session.php +++ b/system/Session/Session.php @@ -187,7 +187,9 @@ $this->cookieSecure = $config->cookieSecure ?? $this->cookieSecure; $this->cookieSameSite = $config->cookieSameSite ?? $this->cookieSameSite; - /** @var CookieConfig */ + /** + * @var CookieConfig + */ $cookie = config('Cookie'); $this->cookie = new Cookie($this->sessionCookieName, '', [ @@ -512,7 +514,7 @@ */ public function get(string $key = null) { - if (! empty($key) && (! is_null($value = isset($_SESSION[$key]) ? $_SESSION[$key] : null) || ! is_null($value = dot_array_search($key, $_SESSION ?? [])))) + if (! empty($key) && (! is_null($value = $_SESSION[$key] ?? null) || ! is_null($value = dot_array_search($key, $_SESSION ?? [])))) { return $value; } diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index 95fea08..c651aaa 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -14,6 +14,7 @@ use CodeIgniter\CodeIgniter; use CodeIgniter\Config\Factories; use CodeIgniter\Database\BaseConnection; +use CodeIgniter\Database\MigrationRunner; use CodeIgniter\Database\Seeder; use CodeIgniter\Events\Events; use CodeIgniter\Router\RouteCollection; diff --git a/system/Test/ControllerResponse.php b/system/Test/ControllerResponse.php index 8e7cea6..2365c35 100644 --- a/system/Test/ControllerResponse.php +++ b/system/Test/ControllerResponse.php @@ -46,7 +46,7 @@ */ public function __construct() { - parent::__construct($response ?? Services::response()); + parent::__construct(Services::response()); $this->dom = &$this->domParser; } diff --git a/system/Test/ControllerTestTrait.php b/system/Test/ControllerTestTrait.php index 83a520e..47810e5 100644 --- a/system/Test/ControllerTestTrait.php +++ b/system/Test/ControllerTestTrait.php @@ -19,6 +19,7 @@ use Config\App; use Config\Services; use InvalidArgumentException; +use Psr\Log\LoggerInterface; use Throwable; /** diff --git a/system/Test/ControllerTester.php b/system/Test/ControllerTester.php index 078d260..391873a 100644 --- a/system/Test/ControllerTester.php +++ b/system/Test/ControllerTester.php @@ -18,6 +18,7 @@ use Config\App; use Config\Services; use InvalidArgumentException; +use Psr\Log\LoggerInterface; use Throwable; /** diff --git a/system/Test/DOMParser.php b/system/Test/DOMParser.php index ab86167..4938fdf 100644 --- a/system/Test/DOMParser.php +++ b/system/Test/DOMParser.php @@ -296,7 +296,7 @@ // ID? if ($pos = strpos($selector, '#') !== false) { - list($tag, $id) = explode('#', $selector); + [$tag, $id] = explode('#', $selector); } // Attribute elseif (strpos($selector, '[') !== false && strpos($selector, ']') !== false) @@ -311,7 +311,7 @@ $text = explode(',', $text); $text = trim(array_shift($text)); - list($name, $value) = explode('=', $text); + [$name, $value] = explode('=', $text); $name = trim($name); $value = trim($value); $attr = [$name => trim($value, '] ')]; @@ -319,7 +319,7 @@ // Class? elseif ($pos = strpos($selector, '.') !== false) { - list($tag, $class) = explode('.', $selector); + [$tag, $class] = explode('.', $selector); } // Otherwise, assume the entire string is our tag else diff --git a/system/Test/DatabaseTestTrait.php b/system/Test/DatabaseTestTrait.php index 0d2949a..2c8ba23 100644 --- a/system/Test/DatabaseTestTrait.php +++ b/system/Test/DatabaseTestTrait.php @@ -12,10 +12,7 @@ namespace CodeIgniter\Test; use CodeIgniter\Database\BaseBuilder; -use CodeIgniter\Database\BaseConnection; use CodeIgniter\Database\Exceptions\DatabaseException; -use CodeIgniter\Database\MigrationRunner; -use CodeIgniter\Database\Seeder; use CodeIgniter\Test\Constraints\SeeInDatabase; use Config\Database; use Config\Migrations; diff --git a/system/Test/Fabricator.php b/system/Test/Fabricator.php index ef2294e..885f2ef 100644 --- a/system/Test/Fabricator.php +++ b/system/Test/Fabricator.php @@ -43,7 +43,7 @@ /** * Model instance (can be non-framework if it follows framework design) * - * @var CodeIgniter\Model|object + * @var Model|object */ protected $model; diff --git a/system/Test/Mock/MockServices.php b/system/Test/Mock/MockServices.php index 3fa1a14..58fac0c 100644 --- a/system/Test/Mock/MockServices.php +++ b/system/Test/Mock/MockServices.php @@ -11,7 +11,7 @@ namespace CodeIgniter\Test\Mock; -use \CodeIgniter\Config\BaseService; +use CodeIgniter\Config\BaseService; use CodeIgniter\Autoloader\FileLocator; class MockServices extends BaseService diff --git a/system/Test/TestResponse.php b/system/Test/TestResponse.php index 4c7a655..a1bacda 100644 --- a/system/Test/TestResponse.php +++ b/system/Test/TestResponse.php @@ -16,7 +16,6 @@ use CodeIgniter\HTTP\ResponseInterface; use Config\Services; use Exception; -use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\TestCase; /** diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index 44e77a5..9f9e23d 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -130,7 +130,7 @@ public function is_not_unique(string $str = null, string $field, array $data): bool { // Grab any data for exclusion of a single row. - list($field, $whereField, $whereValue) = array_pad(explode(',', $field), 3, null); + [$field, $whereField, $whereValue] = array_pad(explode(',', $field), 3, null); // Break the table and field apart sscanf($field, '%[^.].%[^.]', $table, $field); @@ -186,7 +186,7 @@ public function is_unique(string $str = null, string $field, array $data): bool { // Grab any data for exclusion of a single row. - list($field, $ignoreField, $ignoreValue) = array_pad(explode(',', $field), 3, null); + [$field, $ignoreField, $ignoreValue] = array_pad(explode(',', $field), 3, null); // Break the table and field apart sscanf($field, '%[^.].%[^.]', $table, $field); diff --git a/system/View/Cell.php b/system/View/Cell.php index acb58de..8f753e6 100644 --- a/system/View/Cell.php +++ b/system/View/Cell.php @@ -78,7 +78,7 @@ */ public function render(string $library, $params = null, int $ttl = 0, string $cacheName = null): string { - list($class, $method) = $this->determineClass($library); + [$class, $method] = $this->determineClass($library); // Is it cached? $cacheName = ! empty($cacheName) @@ -194,7 +194,7 @@ { if (! empty($p)) { - list($key, $val) = explode('=', $p); + [$key, $val] = explode('=', $p); $newParams[trim($key)] = trim($val, ', '); } } @@ -228,7 +228,7 @@ // by default, so convert any double colons. $library = str_replace('::', ':', $library); - list($class, $method) = explode(':', $library); + [$class, $method] = explode(':', $library); if (empty($class)) { diff --git a/system/View/Parser.php b/system/View/Parser.php index 9bfb937..b3cef4b 100644 --- a/system/View/Parser.php +++ b/system/View/Parser.php @@ -101,16 +101,13 @@ $fileExt = pathinfo($view, PATHINFO_EXTENSION); $view = empty($fileExt) ? $view . '.php' : $view; // allow Views as .html, .tpl, etc (from CI3) - // Was it cached? - if (isset($options['cache'])) - { - $cacheName = $options['cache_name'] ?? str_replace('.php', '', $view); + $cacheName = $options['cache_name'] ?? str_replace('.php', '', $view); - if ($output = cache($cacheName)) - { - $this->logPerformance($start, microtime(true), $view); - return $output; - } + // Was it cached? + if (isset($options['cache']) && ($output = cache($cacheName))) + { + $this->logPerformance($start, microtime(true), $view); + return $output; } $file = $this->viewPath . $view; @@ -143,7 +140,7 @@ // Should we cache? if (isset($options['cache'])) { - cache()->save($cacheName, $output, (int) $options['cache']); // @phpstan-ignore-line + cache()->save($cacheName, $output, (int) $options['cache']); } $this->tempData = null; return $output; diff --git a/system/View/Table.php b/system/View/Table.php index aa1ae36..ec10e75 100644 --- a/system/View/Table.php +++ b/system/View/Table.php @@ -320,7 +320,7 @@ } } - $out .= $temp . (isset($heading['data']) ? $heading['data'] : '') . $this->template['heading_cell_end']; + $out .= $temp . ($heading['data'] ?? '') . $this->template['heading_cell_end']; } $out .= $this->template['heading_row_end'] . $this->newline . $this->template['thead_close'] . $this->newline; @@ -352,7 +352,7 @@ } } - $cell = isset($cell['data']) ? $cell['data'] : ''; + $cell = $cell['data'] ?? ''; $out .= $temp; if ($cell === '' || $cell === null) @@ -394,7 +394,7 @@ } } - $out .= $temp . (isset($footing['data']) ? $footing['data'] : '') . $this->template['footing_cell_end']; + $out .= $temp . ($footing['data'] ?? '') . $this->template['footing_cell_end']; } $out .= $this->template['footing_row_end'] . $this->newline . $this->template['tfoot_close'] . $this->newline;