diff --git a/app/Config/Mimes.php b/app/Config/Mimes.php index 973fb3984901..786bc6a1e5c7 100644 --- a/app/Config/Mimes.php +++ b/app/Config/Mimes.php @@ -509,7 +509,7 @@ public static function guessExtensionFromType(string $type, ?string $proposedExt { $type = trim(strtolower($type), '. '); - $proposedExtension = trim(strtolower($proposedExtension)); + $proposedExtension = trim(strtolower($proposedExtension ?? '')); if ($proposedExtension !== '') { if (array_key_exists($proposedExtension, static::$mimes) && in_array($type, is_string(static::$mimes[$proposedExtension]) ? [static::$mimes[$proposedExtension]] : static::$mimes[$proposedExtension], true)) { diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index ea1e1ad85611..347a894f7578 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -865,10 +865,12 @@ public static function getOptionString(bool $useLongOpts = false, bool $trim = f $out .= "-{$name} "; } - // If there's a space, we need to group - // so it will pass correctly. + if ($value === null) { + continue; + } + if (mb_strpos($value, ' ') !== false) { - $out .= '"' . $value . '" '; + $out .= "\"{$value}\" "; } elseif ($value !== null) { $out .= "{$value} "; } diff --git a/system/Database/BaseUtils.php b/system/Database/BaseUtils.php index 5af2b54dbad7..7848ae75ecf0 100644 --- a/system/Database/BaseUtils.php +++ b/system/Database/BaseUtils.php @@ -200,7 +200,7 @@ public function repairTable(string $tableName) public function getCSVFromResult(ResultInterface $query, string $delim = ',', string $newline = "\n", string $enclosure = '"') { $out = ''; - // First generate the headings from the table column names + foreach ($query->getFieldNames() as $name) { $out .= $enclosure . str_replace($enclosure, $enclosure . $enclosure, $name) . $enclosure . $delim; } @@ -212,7 +212,7 @@ public function getCSVFromResult(ResultInterface $query, string $delim = ',', st $line = []; foreach ($row as $item) { - $line[] = $enclosure . str_replace($enclosure, $enclosure . $enclosure, $item) . $enclosure; + $line[] = $enclosure . str_replace($enclosure, $enclosure . $enclosure, $item ?? '') . $enclosure; } $out .= implode($delim, $line) . $newline; diff --git a/system/Database/Forge.php b/system/Database/Forge.php index 8e0b7e43c7f3..d07675401df8 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -462,7 +462,7 @@ public function dropKey(string $table, string $keyName) public function dropForeignKey(string $table, string $foreignName) { $sql = sprintf( - $this->dropConstraintStr, + (string) $this->dropConstraintStr, $this->db->escapeIdentifiers($this->db->DBPrefix . $table), $this->db->escapeIdentifiers($this->db->DBPrefix . $foreignName) ); diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index a768e0ecf432..d39587821036 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -433,8 +433,11 @@ protected function buildDSN() $this->DSN = "host={$this->hostname} "; } - if (! empty($this->port) && ctype_digit($this->port)) { - $this->DSN .= "port={$this->port} "; + // ctype_digit only accepts strings + $port = (string) $this->port; + + if ($port !== '' && ctype_digit($port)) { + $this->DSN .= "port={$port} "; } if ($this->username !== '') { diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index faa1df358cb4..edeb8b0571c5 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -397,13 +397,10 @@ protected function processGlobals(?string $uri = null) return; } - $uri = strtolower(trim($uri, '/ ')); + $uri = strtolower(trim($uri ?? '', '/ ')); // Add any global filters, unless they are excluded for this URI - $sets = [ - 'before', - 'after', - ]; + $sets = ['before', 'after']; foreach ($sets as $set) { if (isset($this->config->globals[$set])) { diff --git a/system/HTTP/CLIRequest.php b/system/HTTP/CLIRequest.php index b10d41884733..11bf598fd36c 100644 --- a/system/HTTP/CLIRequest.php +++ b/system/HTTP/CLIRequest.php @@ -139,11 +139,13 @@ public function getOptionString(bool $useLongOpts = false): string $out .= "-{$name} "; } - // If there's a space, we need to group - // so it will pass correctly. + if ($value === null) { + continue; + } + if (mb_strpos($value, ' ') !== false) { $out .= '"' . $value . '" '; - } elseif ($value !== null) { + } else { $out .= "{$value} "; } } diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index fffe57258a54..9a66e632783b 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -424,7 +424,7 @@ protected function applyMethod(string $method, array $curlOptions): array $this->method = $method; $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; - $size = strlen($this->body); + $size = strlen($this->body ?? ''); // Have content? if ($size > 0) { diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 2b1205a5d47a..7ec5f1e69e6b 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -435,7 +435,7 @@ public function send() if ($this->CSPEnabled === true) { $this->CSP->finalize($this); } else { - $this->body = str_replace(['{csp-style-nonce}', '{csp-script-nonce}'], '', $this->body); + $this->body = str_replace(['{csp-style-nonce}', '{csp-script-nonce}'], '', $this->body ?? ''); } $this->sendHeaders(); diff --git a/system/I18n/Time.php b/system/I18n/Time.php index 919a5a391534..ca8ffc3dc72e 100644 --- a/system/I18n/Time.php +++ b/system/I18n/Time.php @@ -75,25 +75,23 @@ class Time extends DateTime */ public function __construct(?string $time = null, $timezone = null, ?string $locale = null) { - // If no locale was provided, grab it from Locale (set by IncomingRequest for web requests) - $this->locale = ! empty($locale) ? $locale : Locale::getDefault(); + $this->locale = $locale ?: Locale::getDefault(); - // If a test instance has been provided, use it instead. - if ($time === null && static::$testNow instanceof self) { - if (empty($timezone)) { - $timezone = static::$testNow->getTimezone(); - } + $time = $time ?? ''; - $time = static::$testNow->toDateTimeString(); + // If a test instance has been provided, use it instead. + if ($time === '' && static::$testNow instanceof self) { + $timezone = $timezone ?: static::$testNow->getTimezone(); + $time = (string) static::$testNow->toDateTimeString(); } - $timezone = ! empty($timezone) ? $timezone : date_default_timezone_get(); + $timezone = $timezone ?: date_default_timezone_get(); $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone); // If the time string was a relative string (i.e. 'next Tuesday') // then we need to adjust the time going in so that we have a current // timezone to work with. - if (! empty($time) && (is_string($time) && static::hasRelativeKeywords($time))) { + if ($time !== '' && static::hasRelativeKeywords($time)) { $instance = new DateTime('now', $this->timezone); $instance->modify($time); $time = $instance->format('Y-m-d H:i:s'); diff --git a/system/Security/Security.php b/system/Security/Security.php index fc8c1ac334c8..35e889a85d69 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -288,7 +288,7 @@ public function verify(RequestInterface $request) throw SecurityException::forDisallowedAction(); } - $json = json_decode($request->getBody()); + $json = json_decode($request->getBody() ?? ''); if (isset($_POST[$this->tokenName])) { // We kill this since we're done and we don't want to pollute the POST array. @@ -323,9 +323,10 @@ private function getPostedToken(RequestInterface $request): ?string if ($request->hasHeader($this->headerName) && ! empty($request->header($this->headerName)->getValue())) { $tokenName = $request->header($this->headerName)->getValue(); } else { - $json = json_decode($request->getBody()); + $body = (string) $request->getBody(); + $json = json_decode($body); - if (! empty($request->getBody()) && ! empty($json) && json_last_error() === JSON_ERROR_NONE) { + if ($body !== '' && ! empty($json) && json_last_error() === JSON_ERROR_NONE) { $tokenName = $json->{$this->tokenName} ?? null; } else { $tokenName = null; diff --git a/system/Validation/FormatRules.php b/system/Validation/FormatRules.php index 2167e28cba79..e28f6d6af13d 100644 --- a/system/Validation/FormatRules.php +++ b/system/Validation/FormatRules.php @@ -23,7 +23,7 @@ class FormatRules */ public function alpha(?string $str = null): bool { - return ctype_alpha($str); + return ctype_alpha($str ?? ''); } /** @@ -74,7 +74,7 @@ public function alpha_numeric_punct($str) */ public function alpha_numeric(?string $str = null): bool { - return ctype_alnum($str); + return ctype_alnum($str ?? ''); } /** @@ -83,7 +83,7 @@ public function alpha_numeric(?string $str = null): bool public function alpha_numeric_space(?string $str = null): bool { // @see https://regex101.com/r/0AZDME/1 - return (bool) preg_match('/\A[A-Z0-9 ]+\z/i', $str); + return (bool) preg_match('/\A[A-Z0-9 ]+\z/i', $str ?? ''); } /** @@ -105,7 +105,7 @@ public function string($str = null): bool public function decimal(?string $str = null): bool { // @see https://regex101.com/r/HULifl/2/ - return (bool) preg_match('/\A[-+]?\d{0,}\.?\d+\z/', $str); + return (bool) preg_match('/\A[-+]?\d{0,}\.?\d+\z/', $str ?? ''); } /** @@ -113,7 +113,7 @@ public function decimal(?string $str = null): bool */ public function hex(?string $str = null): bool { - return ctype_xdigit($str); + return ctype_xdigit($str ?? ''); } /** @@ -121,7 +121,7 @@ public function hex(?string $str = null): bool */ public function integer(?string $str = null): bool { - return (bool) preg_match('/\A[\-+]?\d+\z/', $str); + return (bool) preg_match('/\A[\-+]?\d+\z/', $str ?? ''); } /** @@ -129,7 +129,7 @@ public function integer(?string $str = null): bool */ public function is_natural(?string $str = null): bool { - return ctype_digit($str); + return ctype_digit($str ?? ''); } /** @@ -137,7 +137,7 @@ public function is_natural(?string $str = null): bool */ public function is_natural_no_zero(?string $str = null): bool { - return $str !== '0' && ctype_digit($str); + return $str !== '0' && ctype_digit($str ?? ''); } /** @@ -146,7 +146,7 @@ public function is_natural_no_zero(?string $str = null): bool public function numeric(?string $str = null): bool { // @see https://regex101.com/r/bb9wtr/2 - return (bool) preg_match('/\A[\-+]?\d*\.?\d+\z/', $str); + return (bool) preg_match('/\A[\-+]?\d*\.?\d+\z/', $str ?? ''); } /** @@ -158,7 +158,7 @@ public function regex_match(?string $str, string $pattern): bool $pattern = "/{$pattern}/"; } - return (bool) preg_match($pattern, $str); + return (bool) preg_match($pattern, $str ?? ''); } /** @@ -171,7 +171,7 @@ public function regex_match(?string $str, string $pattern): bool */ public function timezone(?string $str = null): bool { - return in_array($str, timezone_identifiers_list(), true); + return in_array($str ?? '', timezone_identifiers_list(), true); } /** @@ -184,6 +184,10 @@ public function timezone(?string $str = null): bool */ public function valid_base64(?string $str = null): bool { + if ($str === null) { + return false; + } + return base64_encode(base64_decode($str, true)) === $str; } @@ -194,7 +198,7 @@ public function valid_base64(?string $str = null): bool */ public function valid_json(?string $str = null): bool { - json_decode($str); + json_decode($str ?? ''); return json_last_error() === JSON_ERROR_NONE; } @@ -207,7 +211,7 @@ public function valid_json(?string $str = null): bool public function valid_email(?string $str = null): bool { // @see https://regex101.com/r/wlJG1t/1/ - if (function_exists('idn_to_ascii') && defined('INTL_IDNA_VARIANT_UTS46') && preg_match('#\A([^@]+)@(.+)\z#', $str, $matches)) { + if (function_exists('idn_to_ascii') && defined('INTL_IDNA_VARIANT_UTS46') && preg_match('#\A([^@]+)@(.+)\z#', $str ?? '', $matches)) { $str = $matches[1] . '@' . idn_to_ascii($matches[2], 0, INTL_IDNA_VARIANT_UTS46); } @@ -224,8 +228,9 @@ public function valid_email(?string $str = null): bool */ public function valid_emails(?string $str = null): bool { - foreach (explode(',', $str) as $email) { + foreach (explode(',', $str ?? '') as $email) { $email = trim($email); + if ($email === '') { return false; } @@ -241,8 +246,7 @@ public function valid_emails(?string $str = null): bool /** * Validate an IP address (human readable format or binary string - inet_pton) * - * @param string $ip IP Address - * @param string $which IP protocol: 'ipv4' or 'ipv6' + * @param string|null $which IP protocol: 'ipv4' or 'ipv6' */ public function valid_ip(?string $ip = null, ?string $which = null): bool { @@ -250,7 +254,7 @@ public function valid_ip(?string $ip = null, ?string $which = null): bool return false; } - switch (strtolower($which)) { + switch (strtolower($which ?? '')) { case 'ipv4': $which = FILTER_FLAG_IPV4; break; @@ -260,11 +264,11 @@ public function valid_ip(?string $ip = null, ?string $which = null): bool break; default: - $which = null; - break; + $which = 0; } - return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which) || (! ctype_print($ip) && (bool) filter_var(inet_ntop($ip), FILTER_VALIDATE_IP, $which)); + return filter_var($ip, FILTER_VALIDATE_IP, $which) !== false + || (! ctype_print($ip) && filter_var(inet_ntop($ip), FILTER_VALIDATE_IP, $which) !== false); } /** @@ -272,8 +276,6 @@ public function valid_ip(?string $ip = null, ?string $which = null): bool * * Warning: this rule will pass basic strings like * "banana"; use valid_url_strict for a stricter rule. - * - * @param string $str */ public function valid_url(?string $str = null): bool { @@ -317,18 +319,16 @@ public function valid_url_strict(?string $str = null, ?string $validSchemes = nu /** * Checks for a valid date and matches a given date format - * - * @param string $str - * @param string $format */ public function valid_date(?string $str = null, ?string $format = null): bool { if (empty($format)) { - return (bool) strtotime($str); + return strtotime($str) !== false; } - $date = DateTime::createFromFormat($format, $str); + $date = DateTime::createFromFormat($format, $str); + $errors = DateTime::getLastErrors(); - return (bool) $date && DateTime::getLastErrors()['warning_count'] === 0 && DateTime::getLastErrors()['error_count'] === 0; + return $date !== false && $errors !== false && $errors['warning_count'] === 0 && $errors['error_count'] === 0; } } diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index 20f558e52be2..367915ebae35 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -22,8 +22,7 @@ class Rules /** * The value does not match another field in $data. * - * @param string $str - * @param array $data Other field/value pairs + * @param array $data Other field/value pairs */ public function differs(?string $str, string $field, array $data): bool { @@ -36,8 +35,6 @@ public function differs(?string $str, string $field, array $data): bool /** * Equals the static value provided. - * - * @param string $str */ public function equals(?string $str, string $val): bool { @@ -47,15 +44,13 @@ public function equals(?string $str, string $val): bool /** * Returns true if $str is $val characters long. * $val = "5" (one) | "5,8,12" (multiple values) - * - * @param string $str */ public function exact_length(?string $str, string $val): bool { $val = explode(',', $val); foreach ($val as $tmp) { - if (is_numeric($tmp) && (int) $tmp === mb_strlen($str)) { + if (is_numeric($tmp) && (int) $tmp === mb_strlen($str ?? '')) { return true; } } @@ -65,8 +60,6 @@ public function exact_length(?string $str, string $val): bool /** * Greater than - * - * @param string $str */ public function greater_than(?string $str, string $min): bool { @@ -75,8 +68,6 @@ public function greater_than(?string $str, string $min): bool /** * Equal to or Greater than - * - * @param string $str */ public function greater_than_equal_to(?string $str, string $min): bool { @@ -91,8 +82,6 @@ public function greater_than_equal_to(?string $str, string $min): bool * Example: * is_not_unique[table.field,where_field,where_value] * is_not_unique[menu.id,active,1] - * - * @param string $str */ public function is_not_unique(?string $str, string $field, array $data): bool { @@ -102,9 +91,8 @@ public function is_not_unique(?string $str, string $field, array $data): bool // Break the table and field apart sscanf($field, '%[^.].%[^.]', $table, $field); - $db = Database::connect($data['DBGroup'] ?? null); - - $row = $db->table($table) + $row = Database::connect($data['DBGroup'] ?? null) + ->table($table) ->select('1') ->where($field, $str) ->limit(1); @@ -118,8 +106,6 @@ public function is_not_unique(?string $str, string $field, array $data): bool /** * Value should be within an array of values - * - * @param string $value */ public function in_list(?string $value, string $list): bool { @@ -136,20 +122,15 @@ public function in_list(?string $value, string $list): bool * Example: * is_unique[table.field,ignore_field,ignore_value] * is_unique[users.email,id,5] - * - * @param string $str */ public function is_unique(?string $str, string $field, array $data): bool { - // Grab any data for exclusion of a single row. [$field, $ignoreField, $ignoreValue] = array_pad(explode(',', $field), 3, null); - // Break the table and field apart sscanf($field, '%[^.].%[^.]', $table, $field); - $db = Database::connect($data['DBGroup'] ?? null); - - $row = $db->table($table) + $row = Database::connect($data['DBGroup'] ?? null) + ->table($table) ->select('1') ->where($field, $str) ->limit(1); @@ -163,8 +144,6 @@ public function is_unique(?string $str, string $field, array $data): bool /** * Less than - * - * @param string $str */ public function less_than(?string $str, string $max): bool { @@ -173,8 +152,6 @@ public function less_than(?string $str, string $max): bool /** * Equal to or Less than - * - * @param string $str */ public function less_than_equal_to(?string $str, string $max): bool { @@ -184,8 +161,7 @@ public function less_than_equal_to(?string $str, string $max): bool /** * Matches the value of another field in $data. * - * @param string $str - * @param array $data Other field/value pairs + * @param array $data Other field/value pairs */ public function matches(?string $str, string $field, array $data): bool { @@ -198,22 +174,18 @@ public function matches(?string $str, string $field, array $data): bool /** * Returns true if $str is $val or fewer characters in length. - * - * @param string $str */ public function max_length(?string $str, string $val): bool { - return is_numeric($val) && $val >= mb_strlen($str); + return is_numeric($val) && $val >= mb_strlen($str ?? ''); } /** * Returns true if $str is at least $val length. - * - * @param string $str */ public function min_length(?string $str, string $val): bool { - return is_numeric($val) && $val <= mb_strlen($str); + return is_numeric($val) && $val <= mb_strlen($str ?? ''); } /** @@ -237,11 +209,7 @@ public function not_in_list(?string $value, string $list): bool } /** - * Required - * - * @param mixed $str Value - * - * @return bool True if valid, false if not + * @param mixed $str */ public function required($str = null): bool { @@ -270,11 +238,10 @@ public function required_with($str = null, ?string $fields = null, array $data = throw new InvalidArgumentException('You must supply the parameters: fields, data.'); } - $fields = explode(',', $fields); - // If the field is present we can safely assume that // the field is here, no matter whether the corresponding // search field is present or not. + $fields = explode(',', $fields); $present = $this->required($str ?? ''); if ($present) { @@ -311,11 +278,10 @@ public function required_without($str = null, ?string $fields = null, array $dat throw new InvalidArgumentException('You must supply the parameters: fields, data.'); } - $fields = explode(',', $fields); - // If the field is present we can safely assume that // the field is here, no matter whether the corresponding // search field is present or not. + $fields = explode(',', $fields); $present = $this->required($str ?? ''); if ($present) { diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 8bd14817e79d..876ab3caffa0 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -215,7 +215,7 @@ protected function processRules(string $field, ?string $label, $value, $rules = } if (in_array('permit_empty', $rules, true)) { - if (! in_array('required', $rules, true) && (is_array($value) ? empty($value) : (trim($value) === ''))) { + if (! in_array('required', $rules, true) && (is_array($value) ? $value === [] : trim($value ?? '') === '')) { $passed = true; foreach ($rules as $rule) { @@ -570,13 +570,13 @@ protected function fillPlaceholders(array $rules, array $data): array continue; } - $row = strtr($row, $replacements); + $row = strtr($row ?? '', $replacements); } continue; } - $rule = strtr($rule, $replacements); + $rule = strtr($rule ?? '', $replacements); } } @@ -594,10 +594,6 @@ public function hasError(string $field): bool /** * Returns the error(s) for a specified $field (or empty string if not * set). - * - * @param string $field Field. - * - * @return string Error(s). */ public function getError(?string $field = null): string { @@ -617,9 +613,7 @@ public function getError(?string $field = null): string * 'field2' => 'error message', * ] * - * @return array - * - * Excluded from code coverage because that it always run as cli + * @return array * * @codeCoverageIgnore */ @@ -648,12 +642,10 @@ public function setError(string $field, string $error): ValidationInterface /** * Attempts to find the appropriate error message * - * @param string $param - * @param string $value The value that caused the validation to fail. + * @param string|null $value The value that caused the validation to fail. */ protected function getErrorMessage(string $rule, string $field, ?string $label = null, ?string $param = null, ?string $value = null): string { - // Check if custom message has been defined by user if (isset($this->customErrors[$field][$rule])) { $message = lang($this->customErrors[$field][$rule]); } else { @@ -666,7 +658,7 @@ protected function getErrorMessage(string $rule, string $field, ?string $label = $message = str_replace('{field}', empty($label) ? $field : lang($label), $message); $message = str_replace('{param}', empty($this->rules[$param]['label']) ? $param : lang($this->rules[$param]['label']), $message); - return str_replace('{value}', $value, $message); + return str_replace('{value}', $value ?? '', $message); } /** diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php index 205a98098724..75f4416676fc 100644 --- a/tests/system/I18n/TimeTest.php +++ b/tests/system/I18n/TimeTest.php @@ -42,8 +42,7 @@ public function testNewTimeNow() 'yyyy-MM-dd HH:mm:ss' ); - $time = new Time(null, 'America/Chicago'); - + $time = new Time('', 'America/Chicago'); $this->assertSame($formatter->format($time), (string) $time); }