From cd2c9762d8c16f9c79a13e78d7e74d409aa63cfa Mon Sep 17 00:00:00 2001 From: Alexander Schnitzler <git@alexanderschnitzler.de> Date: Mon, 11 May 2020 17:33:41 +0200 Subject: [PATCH] [TASK] Fix phpstan checkFunctionArgumentTypes errors in ext:core Utility This patch fixes incompatible type usage in function arguments and is preparatory work for introducing native type hints and strict mode in all core files. Releases: master, 10.4 Resolves: #92279 Change-Id: I469892a56334a13ab19df17aeaa39a68226b7510 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/65679 Tested-by: Alexander Schnitzler <git@alexanderschnitzler.de> Tested-by: TYPO3com <noreply@typo3.com> Tested-by: Daniel Goerz <daniel.goerz@posteo.de> Reviewed-by: Alexander Schnitzler <git@alexanderschnitzler.de> Reviewed-by: Daniel Goerz <daniel.goerz@posteo.de> --- .../core/Classes/Utility/ArrayUtility.php | 4 +- .../core/Classes/Utility/CommandUtility.php | 2 +- .../core/Classes/Utility/CsvUtility.php | 1 + .../Utility/ExtensionManagementUtility.php | 4 +- .../Classes/Utility/File/BasicFileUtility.php | 4 +- .../core/Classes/Utility/GeneralUtility.php | 75 +++++++++++-------- .../core/Classes/Utility/PathUtility.php | 10 +-- .../Classes/Utility/VersionNumberUtility.php | 4 +- 8 files changed, 59 insertions(+), 45 deletions(-) diff --git a/typo3/sysext/core/Classes/Utility/ArrayUtility.php b/typo3/sysext/core/Classes/Utility/ArrayUtility.php index f15692ea0a84..6b638725fa93 100644 --- a/typo3/sysext/core/Classes/Utility/ArrayUtility.php +++ b/typo3/sysext/core/Classes/Utility/ArrayUtility.php @@ -679,7 +679,7 @@ class ArrayUtility * * @param array $array The initial array to be filtered/reduced * @param mixed $keepItems The items which are allowed/kept in the array - accepts array or csv string - * @param string $getValueFunc (optional) Callback function used to get the value to keep + * @param callable|null $getValueFunc (optional) Callback function used to get the value to keep * @return array The filtered/reduced array with the kept items */ public static function keepItemsInArray(array $array, $keepItems, $getValueFunc = null) @@ -837,7 +837,7 @@ class ArrayUtility if (is_array($value)) { $result[$key] = self::stripTagsFromValuesRecursive($value); } elseif (is_string($value) || (is_object($value) && method_exists($value, '__toString'))) { - $result[$key] = strip_tags($value); + $result[$key] = strip_tags((string)$value); } } return $result; diff --git a/typo3/sysext/core/Classes/Utility/CommandUtility.php b/typo3/sysext/core/Classes/Utility/CommandUtility.php index 69a2b8698a3f..bf1c47874bcd 100644 --- a/typo3/sysext/core/Classes/Utility/CommandUtility.php +++ b/typo3/sysext/core/Classes/Utility/CommandUtility.php @@ -453,7 +453,7 @@ class CommandUtility $isUTF8Filesystem = !empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']); $currentLocale = false; if ($isUTF8Filesystem) { - $currentLocale = setlocale(LC_CTYPE, 0); + $currentLocale = setlocale(LC_CTYPE, '0'); setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']); } diff --git a/typo3/sysext/core/Classes/Utility/CsvUtility.php b/typo3/sysext/core/Classes/Utility/CsvUtility.php index 458b0749bc05..c64c21996fbd 100644 --- a/typo3/sysext/core/Classes/Utility/CsvUtility.php +++ b/typo3/sysext/core/Classes/Utility/CsvUtility.php @@ -40,6 +40,7 @@ class CsvUtility fwrite($handle, $input); rewind($handle); while (($cells = fgetcsv($handle, 0, $fieldDelimiter, $fieldEnclosure)) !== false) { + $cells = is_array($cells) ? $cells : []; $maximumCellCount = max(count($cells), $maximumCellCount); $multiArray[] = preg_replace('|<br */?>|i', LF, $cells); } diff --git a/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php b/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php index 2c3ca40d4e00..22724cfa09a8 100644 --- a/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php +++ b/typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php @@ -1596,7 +1596,7 @@ tt_content.' . $key . $suffix . ' { $phpCodeToCache[] = ' */'; $phpCodeToCache[] = ''; // Add ext_localconf.php content of extension - $phpCodeToCache[] = trim(file_get_contents($extLocalconfPath)); + $phpCodeToCache[] = trim((string)file_get_contents($extLocalconfPath)); $phpCodeToCache[] = ''; $phpCodeToCache[] = ''; } @@ -1820,7 +1820,7 @@ tt_content.' . $key . $suffix . ' { $phpCodeToCache[] = ' */'; $phpCodeToCache[] = ''; // Add ext_tables.php content of extension - $phpCodeToCache[] = trim(file_get_contents($extTablesPath)); + $phpCodeToCache[] = trim((string)file_get_contents($extTablesPath)); $phpCodeToCache[] = ''; } } diff --git a/typo3/sysext/core/Classes/Utility/File/BasicFileUtility.php b/typo3/sysext/core/Classes/Utility/File/BasicFileUtility.php index 60271210488d..f1a557717699 100644 --- a/typo3/sysext/core/Classes/Utility/File/BasicFileUtility.php +++ b/typo3/sysext/core/Classes/Utility/File/BasicFileUtility.php @@ -136,11 +136,11 @@ class BasicFileUtility // Handle UTF-8 characters if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) { // allow ".", "-", 0-9, a-z, A-Z and everything beyond U+C0 (latin capital letter a with grave) - $cleanFileName = preg_replace('/[' . self::UNSAFE_FILENAME_CHARACTER_EXPRESSION . ']/u', '_', trim($fileName)); + $cleanFileName = preg_replace('/[' . self::UNSAFE_FILENAME_CHARACTER_EXPRESSION . ']/u', '_', trim($fileName)) ?? ''; } else { $fileName = GeneralUtility::makeInstance(CharsetConverter::class)->utf8_char_mapping($fileName); // Replace unwanted characters by underscores - $cleanFileName = preg_replace('/[' . self::UNSAFE_FILENAME_CHARACTER_EXPRESSION . '\\xC0-\\xFF]/', '_', trim($fileName)); + $cleanFileName = preg_replace('/[' . self::UNSAFE_FILENAME_CHARACTER_EXPRESSION . '\\xC0-\\xFF]/', '_', trim($fileName)) ?? ''; } // Strip trailing dots and return return rtrim($cleanFileName, '.'); diff --git a/typo3/sysext/core/Classes/Utility/GeneralUtility.php b/typo3/sysext/core/Classes/Utility/GeneralUtility.php index 7e338a00007c..bef0f6cda9c6 100644 --- a/typo3/sysext/core/Classes/Utility/GeneralUtility.php +++ b/typo3/sysext/core/Classes/Utility/GeneralUtility.php @@ -251,9 +251,10 @@ class GeneralUtility $mask = false; } if ((int)$mask) { + $mask = (int)$mask; // "192.168.3.0/24" - $lnet = ip2long($test); - $lip = ip2long($baseIP); + $lnet = (int)ip2long($test); + $lip = (int)ip2long($baseIP); $binnet = str_pad(decbin($lnet), 32, '0', STR_PAD_LEFT); $firstpart = substr($binnet, 0, $mask); $binip = str_pad(decbin($lip), 32, '0', STR_PAD_LEFT); @@ -307,13 +308,15 @@ class GeneralUtility } elseif ($maskInt == 128) { $success = $test === $baseIP; } else { - $testBin = inet_pton($test); - $baseIPBin = inet_pton($baseIP); + $testBin = (string)inet_pton($test); + $baseIPBin = (string)inet_pton($baseIP); + $success = true; // Modulo is 0 if this is a 8-bit-boundary $maskIntModulo = $maskInt % 8; $numFullCharactersUntilBoundary = (int)($maskInt / 8); - if (strpos($testBin, substr($baseIPBin, 0, $numFullCharactersUntilBoundary)) !== 0) { + $substring = (string)substr($baseIPBin, 0, $numFullCharactersUntilBoundary); + if (strpos($testBin, $substring) !== 0) { $success = false; } elseif ($maskIntModulo > 0) { // If not an 8-bit-boundary, check bits of last character @@ -450,7 +453,7 @@ class GeneralUtility // Resolve hostname // Note: this is reverse-lookup and can be randomly set as soon as somebody is able to set // the reverse-DNS for his IP (security when for example used with REMOTE_ADDR) - $baseHostName = gethostbyaddr($baseHost); + $baseHostName = (string)gethostbyaddr($baseHost); if ($baseHostName === $baseHost) { // Unable to resolve hostname return false; @@ -835,7 +838,7 @@ class GeneralUtility */ public static function camelCaseToLowerCaseUnderscored($string) { - $value = preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $string); + $value = preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $string) ?? ''; return mb_strtolower($value, 'utf-8'); } @@ -909,7 +912,7 @@ class GeneralUtility */ public static function intExplode($delimiter, $string, $removeEmptyValues = false, $limit = 0) { - $result = explode($delimiter, $string); + $result = explode($delimiter, $string) ?: []; foreach ($result as $key => &$value) { if ($removeEmptyValues && ($value === '' || trim($value) === '')) { unset($result[$key]); @@ -957,7 +960,7 @@ class GeneralUtility if ($count <= 1) { return [$string]; } - $explodedValues = explode($delimiter, strrev($string), $count); + $explodedValues = explode($delimiter, strrev($string), $count) ?: []; $explodedValues = array_map('strrev', $explodedValues); return array_reverse($explodedValues); } @@ -976,7 +979,7 @@ class GeneralUtility */ public static function trimExplode($delim, $string, $removeEmptyValues = false, $limit = 0) { - $result = explode($delim, $string); + $result = explode($delim, $string) ?: []; if ($removeEmptyValues) { $temp = []; foreach ($result as $value) { @@ -1106,7 +1109,7 @@ class GeneralUtility * * @param string $tag HTML-tag string (or attributes only) * @param bool $decodeEntities Whether to decode HTML entities - * @return string[] Array with the attribute values. + * @return array<string, string> Array with the attribute values. */ public static function get_tag_attributes($tag, bool $decodeEntities = false) { @@ -1124,7 +1127,7 @@ class GeneralUtility $name = ''; } } else { - if ($key = strtolower(preg_replace('/[^[:alnum:]_\\:\\-]/', '', $val))) { + if ($key = strtolower(preg_replace('/[^[:alnum:]_\\:\\-]/', '', $val) ?? '')) { $attributes[$key] = ''; $name = $key; } @@ -1146,7 +1149,7 @@ class GeneralUtility */ public static function split_tag_attributes($tag) { - $tag_tmp = trim(preg_replace('/^<[^[:space:]]*/', '', trim($tag))); + $tag_tmp = trim(preg_replace('/^<[^[:space:]]*/', '', trim($tag)) ?? ''); // Removes any > in the end of the string $tag_tmp = trim(rtrim($tag_tmp, '>')); $value = []; @@ -1709,13 +1712,13 @@ class GeneralUtility } if (static::isAllowedAbsPath($path)) { if (@is_file($path)) { - $targetPermissions = $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] ?? '0644'; + $targetPermissions = (string)($GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] ?? '0644'); } elseif (@is_dir($path)) { - $targetPermissions = $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] ?? '0755'; + $targetPermissions = (string)($GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] ?? '0755'); } if (!empty($targetPermissions)) { // make sure it's always 4 digits - $targetPermissions = str_pad($targetPermissions, 4, 0, STR_PAD_LEFT); + $targetPermissions = str_pad($targetPermissions, 4, '0', STR_PAD_LEFT); $targetPermissions = octdec($targetPermissions); // "@" is there because file is not necessarily OWNED by the user $result = @chmod($path, $targetPermissions); @@ -1891,9 +1894,9 @@ class GeneralUtility if (!@is_dir($currentPath)) { do { $firstCreatedPath = $currentPath; - $separatorPosition = strrpos($currentPath, DIRECTORY_SEPARATOR); + $separatorPosition = (int)strrpos($currentPath, DIRECTORY_SEPARATOR); $currentPath = substr($currentPath, 0, $separatorPosition); - } while (!is_dir($currentPath) && $separatorPosition !== false); + } while (!is_dir($currentPath) && $separatorPosition > 0); $result = @mkdir($fullDirectoryPath, $permissionMask, true); // Check existence of directory again to avoid race condition. Directory could have get created by another process between previous is_dir() and mkdir() if (!$result && !@is_dir($fullDirectoryPath)) { @@ -1914,7 +1917,7 @@ class GeneralUtility { $OK = false; // Remove trailing slash - $path = preg_replace('|/$|', '', $path); + $path = preg_replace('|/$|', '', $path) ?? ''; $isWindows = DIRECTORY_SEPARATOR === '\\'; if (file_exists($path)) { $OK = true; @@ -2068,7 +2071,7 @@ class GeneralUtility if ($regDirs) { $fileArr[md5($path)] = $path; } - $fileArr = array_merge($fileArr, self::getFilesInDir($path, $extList, 1, 1, $excludePattern)); + $fileArr = array_merge($fileArr, (array)self::getFilesInDir($path, $extList, true, '', $excludePattern)); $dirs = self::get_dirs($path); if ($recursivityLevels > 0 && is_array($dirs)) { foreach ($dirs as $subdirs) { @@ -2180,10 +2183,12 @@ class GeneralUtility */ public static function getMaxUploadFileSize() { + $uploadMaxFilesize = (string)ini_get('upload_max_filesize'); + $postMaxSize = (string)ini_get('post_max_size'); // Check for PHP restrictions of the maximum size of one of the $_FILES - $phpUploadLimit = self::getBytesFromSizeMeasurement(ini_get('upload_max_filesize')); + $phpUploadLimit = self::getBytesFromSizeMeasurement($uploadMaxFilesize); // Check for PHP restrictions of the maximum $_POST size - $phpPostLimit = self::getBytesFromSizeMeasurement(ini_get('post_max_size')); + $phpPostLimit = self::getBytesFromSizeMeasurement($postMaxSize); // If the total amount of post data is smaller (!) than the upload_max_filesize directive, // then this is the real limit in PHP $phpUploadLimit = $phpPostLimit > 0 && $phpPostLimit < $phpUploadLimit ? $phpPostLimit : $phpUploadLimit; @@ -2206,7 +2211,7 @@ class GeneralUtility } elseif (stripos($measurement, 'K')) { $bytes *= 1024; } - return $bytes; + return (int)$bytes; } /** @@ -2478,7 +2483,7 @@ class GeneralUtility $ip = ''; } } - if (self::validIP($ip)) { + if (self::validIP((string)$ip)) { $retVal = $ip; } } @@ -2991,13 +2996,14 @@ class GeneralUtility self::mkdir_deep($temporaryPath); } if ($fileSuffix === '') { - $tempFileName = $temporaryPath . PathUtility::basename(tempnam($temporaryPath, $filePrefix)); + $path = (string)tempnam($temporaryPath, $filePrefix); + $tempFileName = $temporaryPath . PathUtility::basename($path); } else { do { $tempFileName = $temporaryPath . $filePrefix . random_int(1, PHP_INT_MAX) . $fileSuffix; } while (file_exists($tempFileName)); touch($tempFileName); - clearstatcache(null, $tempFileName); + clearstatcache(false, $tempFileName); } return $tempFileName; } @@ -3079,16 +3085,18 @@ class GeneralUtility if (class_exists($parts[0])) { // Create object $classObj = self::makeInstance($parts[0]); - if (method_exists($classObj, $parts[1])) { + $methodName = (string)$parts[1]; + $callable = [$classObj, $methodName]; + if (is_callable($callable)) { // Call method: - $content = call_user_func_array([&$classObj, $parts[1]], [&$params, &$ref]); + $content = call_user_func_array($callable, [&$params, &$ref]); } else { throw new \InvalidArgumentException('No method name \'' . $parts[1] . '\' in class ' . $parts[0], 1294585865); } } else { throw new \InvalidArgumentException('No class named ' . $parts[0], 1294585866); } - } elseif (function_exists($funcName)) { + } elseif (function_exists($funcName) && is_callable($funcName)) { // It's a function $content = call_user_func_array($funcName, [&$params, &$ref]); } else { @@ -3478,8 +3486,13 @@ class GeneralUtility */ public static function quoteJSvalue($value) { + $json = (string)json_encode( + (string)$value, + JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG + ); + return strtr( - json_encode((string)$value, JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG), + $json, [ '"' => '\'', '\\\\' => '\\u005C', @@ -3499,7 +3512,7 @@ class GeneralUtility */ public static function jsonEncodeForHtmlAttribute($value, bool $useHtmlEntities = true): string { - $json = json_encode($value, JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG); + $json = (string)json_encode($value, JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG); return $useHtmlEntities ? htmlspecialchars($json) : $json; } diff --git a/typo3/sysext/core/Classes/Utility/PathUtility.php b/typo3/sysext/core/Classes/Utility/PathUtility.php index b20f8ed22363..8b43e7d23197 100644 --- a/typo3/sysext/core/Classes/Utility/PathUtility.php +++ b/typo3/sysext/core/Classes/Utility/PathUtility.php @@ -114,7 +114,7 @@ class PathUtility if (count($paths) === 1) { $commonPath = array_shift($paths); } elseif (count($paths) > 1) { - $parts = explode('/', array_shift($paths)); + $parts = explode('/', (string)array_shift($paths)); $comparePath = ''; $break = false; foreach ($parts as $part) { @@ -164,7 +164,7 @@ class PathUtility */ public static function basename($path) { - $currentLocale = setlocale(LC_CTYPE, 0); + $currentLocale = (string)setlocale(LC_CTYPE, '0'); setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']); $basename = basename($path); setlocale(LC_CTYPE, $currentLocale); @@ -185,7 +185,7 @@ class PathUtility */ public static function dirname($path) { - $currentLocale = setlocale(LC_CTYPE, 0); + $currentLocale = (string)setlocale(LC_CTYPE, '0'); setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']); $dirname = dirname($path); setlocale(LC_CTYPE, $currentLocale); @@ -203,11 +203,11 @@ class PathUtility * @param string $path * @param int $options * - * @return string|array + * @return string|string[] */ public static function pathinfo($path, $options = null) { - $currentLocale = setlocale(LC_CTYPE, 0); + $currentLocale = (string)setlocale(LC_CTYPE, '0'); setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']); $pathinfo = $options == null ? pathinfo($path) : pathinfo($path, $options); setlocale(LC_CTYPE, $currentLocale); diff --git a/typo3/sysext/core/Classes/Utility/VersionNumberUtility.php b/typo3/sysext/core/Classes/Utility/VersionNumberUtility.php index e787858769c4..441ef2ac07a0 100644 --- a/typo3/sysext/core/Classes/Utility/VersionNumberUtility.php +++ b/typo3/sysext/core/Classes/Utility/VersionNumberUtility.php @@ -34,7 +34,7 @@ class VersionNumberUtility $version = $versionParts[0]; for ($i = 1; $i < 3; $i++) { if (!empty($versionParts[$i])) { - $version .= str_pad((int)$versionParts[$i], 3, '0', STR_PAD_LEFT); + $version .= str_pad((string)(int)$versionParts[$i], 3, '0', STR_PAD_LEFT); } else { $version .= '000'; } @@ -86,7 +86,7 @@ class VersionNumberUtility $cleanedVersion = GeneralUtility::trimExplode('.', $versions[$i]); $cleanedVersionCount = count($cleanedVersion); for ($j = 0; $j < $cleanedVersionCount; $j++) { - $cleanedVersion[$j] = MathUtility::forceIntegerInRange($cleanedVersion[$j], 0, 999); + $cleanedVersion[$j] = MathUtility::forceIntegerInRange((int)$cleanedVersion[$j], 0, 999); } $cleanedVersionString = implode('.', $cleanedVersion); if (static::convertVersionNumberToInteger($cleanedVersionString) === 0) { -- GitLab