diff --git a/Config/SettingsAbstract.php b/Config/SettingsAbstract.php index 042805f76..f23ecd39a 100644 --- a/Config/SettingsAbstract.php +++ b/Config/SettingsAbstract.php @@ -105,6 +105,11 @@ abstract class SettingsAbstract implements OptionsInterface $sth->execute(); $options = $sth->fetchAll(\PDO::FETCH_KEY_PAIR); + + if ($options === false) { + return []; + } + $this->setOptions($options); break; } diff --git a/DataStorage/Cache/Connection/FileCache.php b/DataStorage/Cache/Connection/FileCache.php index 59dca08bd..3c4a9edfc 100644 --- a/DataStorage/Cache/Connection/FileCache.php +++ b/DataStorage/Cache/Connection/FileCache.php @@ -257,7 +257,6 @@ class FileCache extends ConnectionAbstract } $path = $this->getPath($key); - if (!File::exists($path)) { return null; } @@ -269,12 +268,21 @@ class FileCache extends ConnectionAbstract return null; } - $raw = File::get($path); - $type = (int) $raw[0]; + $raw = \file_get_contents($path); + if ($raw === false) { + return null; + } + + $type = (int) $raw[0]; + $expireStart = (int) \strpos($raw, self::DELIM); + $expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1); + + if ($expireStart < 0 || $expireEnd < 0) { + return null; + } - $expireStart = \strpos($raw, self::DELIM); - $expireEnd = \strpos($raw, self::DELIM, $expireStart + 1); $cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1)); + $cacheExpire = ($cacheExpire === false) ? $created : (int) $cacheExpire; if ($cacheExpire >= 0 && $created + $cacheExpire < $now) { $this->delete($key); @@ -314,18 +322,23 @@ class FileCache extends ConnectionAbstract $value = \substr($raw, $expireEnd + 1); break; case CacheValueType::_ARRAY: - $value = \json_decode(substr($raw, $expireEnd + 1)); + $array = \substr($raw, $expireEnd + 1); + $value = \json_decode($array === false ? '[]' : $array, true); break; case CacheValueType::_NULL: $value = null; break; case CacheValueType::_SERIALIZABLE: case CacheValueType::_JSONSERIALIZABLE: - $namespaceStart = \strpos($raw, self::DELIM, $expireEnd); - $namespaceEnd = \strpos($raw, self::DELIM, $namespaceStart + 1); + $namespaceStart = (int) \strpos($raw, self::DELIM, $expireEnd); + $namespaceEnd = (int) \strpos($raw, self::DELIM, $namespaceStart + 1); $namespace = \substr($raw, $namespaceStart, $namespaceEnd); - $value = $namespace::unserialize(substr($raw, $namespaceEnd + 1)); + if ($namespace === false) { + return null; + } + + $value = $namespace::unserialize(\substr($raw, $namespaceEnd + 1)); break; } @@ -342,7 +355,6 @@ class FileCache extends ConnectionAbstract } $path = $this->getPath($key); - if ($expire < 0 && File::exists($path)) { File::delete($path); @@ -350,12 +362,29 @@ class FileCache extends ConnectionAbstract } if ($expire >= 0) { - $created = Directory::created(Directory::sanitize($key, self::SANITIZE))->getTimestamp(); - $now = \time(); - $raw = \file_get_contents($path); - $expireStart = \strpos($raw, self::DELIM); - $expireEnd = \strpos($raw, self::DELIM, $expireStart + 1); + $created = Directory::created(Directory::sanitize($key, self::SANITIZE))->getTimestamp(); + $now = \time(); + $raw = \file_get_contents($path); + + if ($raw === false) { + return false; + } + + $expireStart = (int) \strpos($raw, self::DELIM); + $expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1); + + if ($expireStart < 0 || $expireEnd < 0) { + return false; + } + $cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1)); + $cacheExpire = ($cacheExpire === false) ? $created : (int) $cacheExpire; + + if ($cacheExpire >= 0 && $created + $cacheExpire < $now) { + $this->delete($key); + + return false; + } if ($cacheExpire >= 0 && $created + $cacheExpire > $now) { File::delete($path); diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php index aa6fe6436..edeaebac3 100644 --- a/DataStorage/Database/DataMapperAbstract.php +++ b/DataStorage/Database/DataMapperAbstract.php @@ -2160,7 +2160,13 @@ class DataMapperAbstract implements DataMapperInterface $sth = self::$db->con->prepare($query->toSql()); $sth->execute(); - return self::populateIterable($sth->fetchAll(\PDO::FETCH_ASSOC)); + $result = $sth->fetchAll(\PDO::FETCH_ASSOC); + + if ($result === false) { + return []; + } + + return self::populateIterable($result); } /** @@ -2415,9 +2421,12 @@ class DataMapperAbstract implements DataMapperInterface $sth = self::$db->con->prepare($query->toSql()); $sth->execute(); - $results = array_column($sth->fetchAll(\PDO::FETCH_NUM) ?? [], 0); + $result = $sth->fetchAll(\PDO::FETCH_NUM); + if ($result === false) { + return []; + } - return $results; + return \array_column($result, 0); } /** @@ -2441,9 +2450,12 @@ class DataMapperAbstract implements DataMapperInterface $sth = self::$db->con->prepare($query->toSql()); $sth->execute(); - $results = array_column($sth->fetchAll(\PDO::FETCH_NUM) ?? [], 0); - - return $results; + $result = $sth->fetchAll(\PDO::FETCH_NUM); + if ($result === false) { + return []; + } + + return \array_column($result, 0); } /** @@ -2686,7 +2698,7 @@ class DataMapperAbstract implements DataMapperInterface $results = $sth->fetchAll(\PDO::FETCH_ASSOC); - return count($results) === 0; + return $results && count($results) === 0; } /** diff --git a/DataStorage/Database/Schema/Exception/TableException.php b/DataStorage/Database/Schema/Exception/TableException.php index ecd54500e..7fa34c155 100644 --- a/DataStorage/Database/Schema/Exception/TableException.php +++ b/DataStorage/Database/Schema/Exception/TableException.php @@ -49,18 +49,20 @@ class TableException extends \PDOException */ public static function findTable(string $message) : string { - $pos1 = strpos($message, '\''); + $pos1 = \strpos($message, '\''); if ($pos1 === false) { return $message; } - $pos2 = strpos($message, '\'', $pos1 + 1); + $pos2 = \strpos($message, '\'', $pos1 + 1); if ($pos2 === false) { return $message; } - return substr($message, $pos1 + 1, $pos2 - $pos1 - 1); + $table = \substr($message, $pos1 + 1, $pos2 - $pos1 - 1); + + return $table === false ? '' : $table; } } diff --git a/Localization/Money.php b/Localization/Money.php index c5085db47..df1410dbd 100644 --- a/Localization/Money.php +++ b/Localization/Money.php @@ -121,6 +121,9 @@ final class Money implements \Serializable } $right = \substr($right, 0, self::MAX_DECIMALS); + if ($right === false) { + return 0; + } return ((int) $left) * 10 ** self::MAX_DECIMALS + (int) \str_pad($right, self::MAX_DECIMALS, '0'); } @@ -192,6 +195,9 @@ final class Money implements \Serializable $left = \substr($value, 0, -self::MAX_DECIMALS); $right = \substr($value, -self::MAX_DECIMALS); + if ($left === false || $right === false) { + return '0'; + } return ($decimals > 0) ? number_format((float) $left, 0, $this->decimal, $this->thousands) . $this->decimal . \substr($right, 0, $decimals) : $left; } diff --git a/Message/Http/Header.php b/Message/Http/Header.php index 4922931b6..62d4fe803 100644 --- a/Message/Http/Header.php +++ b/Message/Http/Header.php @@ -147,8 +147,9 @@ final class Header extends HeaderAbstract $headers = []; foreach ($_SERVER as $name => $value) { - if (substr($name, 0, 5) == 'HTTP_') { - $headers[\str_replace(' ', '-', ucwords(strtolower(\str_replace('_', ' ', substr($name, 5)))))] = $value; + $part = \substr($name, 5); + if ($part === 'HTTP_') { + $headers[\str_replace(' ', '-', \ucwords(\strtolower(\str_replace('_', ' ', $part))))] = $value; } } diff --git a/Stdlib/Base/Iban.php b/Stdlib/Base/Iban.php index 44d68beb5..6fea5acdf 100644 --- a/Stdlib/Base/Iban.php +++ b/Stdlib/Base/Iban.php @@ -115,15 +115,16 @@ class Iban implements \Serializable { $country = $this->getCountry(); $layout = \str_replace(' ', '', IbanEnum::getByName('C_' . $country)); + $start = \stripos($layout, $sequence); + $end = \strrpos($layout, $sequence); - $start = \stripos($layout, $sequence); - $end = strrpos($layout, $sequence); - - if ($start === false) { + if ($start === false || $end === false) { return ''; } - return substr($this->iban, $start, $end - $start + 1); + $sequence = \substr($this->iban, $start, $end - $start + 1); + + return $sequence === false ? '' : $sequence; } /** @@ -135,7 +136,9 @@ class Iban implements \Serializable */ public function getCountry() : string { - return substr($this->iban, 0, 2); + $country = \substr($this->iban, 0, 2); + + return $country === false ? '?' : $country; } /** diff --git a/Uri/Http.php b/Uri/Http.php index 647cbeb15..25f4afd9a 100644 --- a/Uri/Http.php +++ b/Uri/Http.php @@ -145,7 +145,7 @@ final class Http implements UriInterface public function set(string $uri) : void { $this->uri = $uri; - $url = parse_url($this->uri); + $url = \parse_url($this->uri); $this->scheme = $url['scheme'] ?? ''; $this->host = $url['host'] ?? ''; @@ -155,17 +155,23 @@ final class Http implements UriInterface $this->path = $url['path'] ?? ''; if (StringUtils::endsWith($this->path, '.php')) { - $this->path = substr($this->path, 0, -4); + $path = \substr($this->path, 0, -4); + + if ($path === false) { + return; + } + + $this->path = $path; } - $this->path = strpos($this->path, $this->rootPath) === 0 ? substr($this->path, strlen($this->rootPath), strlen($this->path)) : $this->path; + $this->path = \strpos($this->path, $this->rootPath) === 0 ? \substr($this->path, \strlen($this->rootPath), \strlen($this->path)) : $this->path; $this->queryString = $url['query'] ?? ''; if (!empty($this->queryString)) { - parse_str($this->queryString, $this->query); + \parse_str($this->queryString, $this->query); } - $this->query = array_change_key_case($this->query, CASE_LOWER); + $this->query = \array_change_key_case($this->query, CASE_LOWER); $this->fragment = $url['fragment'] ?? ''; $this->base = $this->scheme . '://' . $this->host . $this->rootPath; diff --git a/Utils/Converter/Numeric.php b/Utils/Converter/Numeric.php index 27149160e..f0d929b5a 100644 --- a/Utils/Converter/Numeric.php +++ b/Utils/Converter/Numeric.php @@ -148,9 +148,13 @@ class Numeric $result = 0; foreach (self::ROMANS as $key => $value) { - while (strpos($roman, $key) === 0) { + while (\strpos($roman, $key) === 0) { $result += $value; - $roman = substr($roman, \strlen($key)); + $temp = \substr($roman, \strlen($key)); + + if ($temp !== false) { + $roman = $temp; + } } } diff --git a/Utils/Encoding/Huffman/Huffman.php b/Utils/Encoding/Huffman/Huffman.php index 25542ecd9..165a1c73e 100644 --- a/Utils/Encoding/Huffman/Huffman.php +++ b/Utils/Encoding/Huffman/Huffman.php @@ -134,6 +134,9 @@ final class Huffman } $decbin = \substr($decbin, $pos + 1); + if ($decbin === false) { + throw new \Exception(); + } } if ($i + 1 === $rawLenght) { @@ -144,6 +147,9 @@ final class Huffman } $decbin = \substr($decbin, 0, $pos); + if ($decbin === false) { + throw new \Exception(); + } } $binary .= $decbin; diff --git a/Utils/Git/Repository.php b/Utils/Git/Repository.php index e76e76ee4..fd84f731c 100644 --- a/Utils/Git/Repository.php +++ b/Utils/Git/Repository.php @@ -168,7 +168,7 @@ class Repository */ private function run(string $cmd) : array { - if (\strtolower(\substr(PHP_OS, 0, 3)) == 'win') { + if (\strtolower((string) \substr(PHP_OS, 0, 3)) == 'win') { $cmd = 'cd ' . \escapeshellarg(\dirname(Git::getBin())) . ' && ' . \basename(Git::getBin()) . ' -C ' . \escapeshellarg($this->path) . ' ' @@ -707,7 +707,8 @@ class Repository foreach ($lines as $line) { \preg_match('/^[0-9]*/', $line, $matches); - $contributor = new Author(\substr($line, \strlen($matches[0]) + 1)); + $author = \substr($line, \strlen($matches[0]) + 1); + $contributor = new Author($author === false ? '' : $author); $contributor->setCommitCount($this->getCommitsCount($start, $end)[$contributor->getName()]); $addremove = $this->getAdditionsRemovalsByContributor($contributor, $start, $end); @@ -881,8 +882,16 @@ class Repository } $author = \explode(':', $lines[1] ?? ''); - $author = \explode('<', trim($author[1] ?? '')); - $date = \substr($lines[2] ?? '', 6); + if (count($author) < 2) { + $author = ['none', 'none']; + } else { + $author = \explode('<', trim($author[1] ?? '')); + } + + $date = \substr($lines[2] ?? '', 6); + if ($date === false) { + $date = 'now'; + } $commit = new Commit($matches[0]); $commit->setAuthor(new Author(trim($author[0] ?? ''), rtrim($author[1] ?? '', '>'))); diff --git a/Utils/Parser/Markdown/Markdown.php b/Utils/Parser/Markdown/Markdown.php index fb1b691ce..f81edd4de 100644 --- a/Utils/Parser/Markdown/Markdown.php +++ b/Utils/Parser/Markdown/Markdown.php @@ -980,17 +980,17 @@ class Markdown $inline['position'] = $markerPosition; } - $unmarkedText = \substr($text, 0, $inline['position']); + $unmarkedText = (string) \substr($text, 0, $inline['position']); $markup .= self::unmarkedText($unmarkedText); $markup .= isset($inline['markup']) ? $inline['markup'] : self::element($inline['element']); - $text = \substr($text, $inline['position'] + $inline['extent']); + $text = (string) \substr($text, $inline['position'] + $inline['extent']); continue 2; } - $unmarkedText = \substr($text, 0, $markerPosition + 1); + $unmarkedText = (string) \substr($text, 0, $markerPosition + 1); $markup .= self::unmarkedText($unmarkedText); - $text = \substr($text, $markerPosition + 1); + $text = (string) \substr($text, $markerPosition + 1); } $markup .= self::unmarkedText($text); @@ -1185,13 +1185,13 @@ class Markdown $element['text'] = $matches[1]; $extent += \strlen($matches[0]); - $remainder = \substr($remainder, $extent); + $remainder = (string) \substr($remainder, $extent); if (\preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*"|\'[^\']*\'))?\s*[)]/', $remainder, $matches)) { $element['attributes']['href'] = UriFactory::build($matches[1]); if (isset($matches[2])) { - $element['attributes']['title'] = \substr($matches[2], 1, - 1); + $element['attributes']['title'] = (string) \substr($matches[2], 1, - 1); } $extent += \strlen($matches[0]); @@ -1427,7 +1427,7 @@ class Markdown if (!\in_array('', $lines) && \substr($trimmedMarkup, 0, 3) === '

') { $markup = $trimmedMarkup; - $markup = \substr($markup, 3); + $markup = (string) \substr($markup, 3); $position = \strpos($markup, '

'); $markup = \substr_replace($markup, '', $position, 4); } @@ -1524,6 +1524,6 @@ class Markdown return false; } - return \strtolower(\substr($string, 0, $length)) === \strtolower($needle); + return \strtolower((string) \substr($string, 0, $length)) === \strtolower($needle); } } diff --git a/Validation/Finance/Iban.php b/Validation/Finance/Iban.php index af5976040..f18fc508d 100644 --- a/Validation/Finance/Iban.php +++ b/Validation/Finance/Iban.php @@ -31,8 +31,14 @@ final class Iban extends ValidatorAbstract */ public static function isValid($value, array $constraints = null) : bool { - $value = \str_replace(' ', '', \strtolower($value)); - $enumName = 'C_' . \strtoupper(\substr($value, 0, 2)); + $value = \str_replace(' ', '', \strtolower($value)); + + $temp = \substr($value, 0, 2); + if ($temp === false) { + return false; + } + + $enumName = 'C_' . \strtoupper($temp); if (!IbanEnum::isValidName($enumName)) { self::$error = IbanErrorType::INVALID_COUNTRY; diff --git a/Views/View.php b/Views/View.php index 57b663d57..466fcfa06 100644 --- a/Views/View.php +++ b/Views/View.php @@ -177,25 +177,33 @@ class View extends ViewAbstract if ($module === null) { $match = '/Modules/'; - if (($start = strripos($this->template, $match)) === false) { + if (($start = \strripos($this->template, $match)) === false) { throw new InvalidModuleException($module ?? ''); } - $start = $start + strlen($match); - $end = strpos($this->template, '/', $start); - $module = substr($this->template, $start, $end - $start); + $start = $start + \strlen($match); + $end = \strpos($this->template, '/', $start); + $module = \substr($this->template, $start, $end - $start); + } + + if ($module === false) { + $module = '0'; } if ($theme === null) { $match = '/Theme/'; - if (($start = strripos($this->template, $match)) === false) { + if (($start = \strripos($this->template, $match)) === false) { throw new InvalidThemeException($theme ?? ''); } - $start = $start + strlen($match); - $end = strpos($this->template, '/', $start); - $theme = substr($this->template, $start, $end - $start); + $start = $start + \strlen($match); + $end = \strpos($this->template, '/', $start); + $theme = \substr($this->template, $start, $end - $start); + } + + if ($theme === false) { + $theme = '0'; } return $this->app->l11nManager->getText($this->l11n->getLanguage(), $module, $theme, $translation);