From 936b42406558418f9473eda8f3f9292b9a84aa2d Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Tue, 6 Jan 2026 18:37:00 +0900 Subject: [PATCH] PHP 8.5 updates --- .phive/phars.xml | 12 +- src/Check/Encoding.php | 2 +- src/Convert/Byte.php | 54 ++++++- src/Convert/Math.php | 7 +- src/Logging/ErrorMessage.php | 2 +- src/Output/Image.php | 5 - src/UrlRequests/Curl.php | 13 -- .../Convert/CoreLibsConvertByteTest.php | 137 ++++++++++++------ .../Convert/CoreLibsConvertMathTest.php | 12 +- .../CoreLibsUrlRequestsCurlTest.php | 121 ++++++++-------- 10 files changed, 226 insertions(+), 139 deletions(-) diff --git a/.phive/phars.xml b/.phive/phars.xml index 36149ce..d3c0604 100644 --- a/.phive/phars.xml +++ b/.phive/phars.xml @@ -1,9 +1,9 @@ - - - - - - + + + + + + diff --git a/src/Check/Encoding.php b/src/Check/Encoding.php index 08cb9df..b690c04 100644 --- a/src/Check/Encoding.php +++ b/src/Check/Encoding.php @@ -114,7 +114,7 @@ class Encoding (($char != $r_char && (!self::$mb_error_char || in_array(self::$mb_error_char, ['none', 'long', 'entity']))) || ($char != $r_char && $r_char == self::$mb_error_char && self::$mb_error_char)) && - ord($char) != 194 + ord($char[0]) != 194 ) { $failed[] = $char; } diff --git a/src/Convert/Byte.php b/src/Convert/Byte.php index 22e9cbf..a9ddbd9 100644 --- a/src/Convert/Byte.php +++ b/src/Convert/Byte.php @@ -14,6 +14,7 @@ class Byte public const BYTE_FORMAT_NOSPACE = 1; public const BYTE_FORMAT_ADJUST = 2; public const BYTE_FORMAT_SI = 4; + public const RETURN_AS_STRING = 8; /** * This function replaces the old byteStringFormat @@ -119,7 +120,9 @@ class Byte * @param int $flags bitwise flag with use space turned on * BYTE_FORMAT_SI: use 1000 instead of 1024 * @return string|int|float converted value or original value - * @throws \InvalidArgumentException 1: no valid flag set + * @throws \InvalidArgumentException no valid flag set + * @throws \LengthException number too large to convert to int + * @throws \RuntimeException BCMath extension not loaded if flag is set to string */ public static function stringByteFormat(string|int|float $number, int $flags = 0): string|int|float { @@ -129,7 +132,12 @@ class Byte } else { $si = false; } - if ($flags != 0 && $flags != 4) { + if ($flags & self::RETURN_AS_STRING) { + $return_as_string = true; + } else { + $return_as_string = false; + } + if ($flags != 0 && $flags != 4 && $flags != 8 && $flags != 12) { throw new \InvalidArgumentException("Invalid flags parameter: $flags", 1); } // matches in regex @@ -142,6 +150,10 @@ class Byte strtolower((string)$number), $matches ); + $number_negative = false; + if (!empty($matches[1])) { + $number_negative = true; + } if (isset($matches[2]) && isset($matches[3])) { // remove all non valid characters from the number $number = preg_replace('/[^0-9\.]/', '', $matches[2]); @@ -152,12 +164,48 @@ class Byte if ($unit) { $number = $number * pow($si ? 1000 : 1024, stripos($valid_units_, $unit[0]) ?: 0); } + // if the number is too large, we cannot convert to int directly + if ($number <= PHP_INT_MIN || $number >= PHP_INT_MAX) { + // if we do not want to convert to string + if (!$return_as_string) { + throw new \LengthException( + 'Number too large be converted to int: ' . (string)$number + ); + } + // for string, check if bcmath is loaded, if not this will not work + if (!extension_loaded('bcmath')) { + throw new \RuntimeException( + 'Number too large be converted to int and BCMath extension not loaded: ' . (string)$number + ); + } + } + // string return + if ($return_as_string) { + // return as string to avoid overflow + // $number = (string)round($number); + $number = bcmul(number_format( + $number, + 12, + '.', + '' + ), "1"); + if ($number_negative) { + $number = '-' . $number; + } + return $number; + } // convert to INT to avoid +E output $number = (int)round($number); // if negative input, keep nnegative - if (!empty($matches[1])) { + if ($number_negative) { $number *= -1; } + // check if number is negative but should be, this is Lenght overflow + if (!$number_negative && $number < 0) { + throw new \LengthException( + 'Number too large be converted to int: ' . (string)$number + ); + } } // if not matching return as is return $number; diff --git a/src/Convert/Math.php b/src/Convert/Math.php index 368c485..6aba6f4 100644 --- a/src/Convert/Math.php +++ b/src/Convert/Math.php @@ -62,10 +62,15 @@ class Math * * @param float $number Number to cubic root * @return float Calculated value + * @throws \InvalidArgumentException if $number is negative */ public static function cbrt(float|int $number): float { - return pow((float)$number, 1.0 / 3); + $value = pow((float)$number, 1.0 / 3); + if (is_nan($value)) { + throw new \InvalidArgumentException('cube root from this number is not supported: ' . $number); + } + return $value; } /** diff --git a/src/Logging/ErrorMessage.php b/src/Logging/ErrorMessage.php index bf99f97..153faf2 100644 --- a/src/Logging/ErrorMessage.php +++ b/src/Logging/ErrorMessage.php @@ -291,7 +291,7 @@ class ErrorMessage */ public function getLastErrorMsg(): array { - return $this->error_str[array_key_last($this->error_str)] ?? [ + return $this->error_str[array_key_last($this->error_str) ?? -1] ?? [ 'level' => '', 'str' => '', 'id' => '', diff --git a/src/Output/Image.php b/src/Output/Image.php index aa44960..94d7f18 100644 --- a/src/Output/Image.php +++ b/src/Output/Image.php @@ -365,9 +365,6 @@ class Image imagepng($thumb, $thumbnail_write_path . $thumbnail); break; } - // free up resources (in case we are called in a loop) - imagedestroy($source); - imagedestroy($thumb); } else { throw new \RuntimeException( 'Invalid source image file. Only JPEG/PNG are allowed: ' . $filename, @@ -543,8 +540,6 @@ class Image imagepng($img, $filename); break; } - // clean up image if we have an image - imagedestroy($img); } } diff --git a/src/UrlRequests/Curl.php b/src/UrlRequests/Curl.php index 40b306f..1af6318 100644 --- a/src/UrlRequests/Curl.php +++ b/src/UrlRequests/Curl.php @@ -614,8 +614,6 @@ class Curl implements Interface\RequestsInterface // print "CURLINFO_HEADER_OUT:
" . curl_getinfo($handle, CURLINFO_HEADER_OUT) . "
"; // get response code and bail on not authorized $http_response = $this->handleCurlResponse($handle, $http_result, $options['http_errors']); - // close handler - $this->handleCurlClose($handle); // return response and result return [ 'code' => (string)$http_response, @@ -838,17 +836,6 @@ class Curl implements Interface\RequestsInterface ); } - /** - * close the current curl handle - * - * @param \CurlHandle $handle - * @return void - */ - private function handleCurlClose(\CurlHandle $handle): void - { - curl_close($handle); - } - // ********************************************************************* // MARK: PUBLIC METHODS // ********************************************************************* diff --git a/test/phpunit/Convert/CoreLibsConvertByteTest.php b/test/phpunit/Convert/CoreLibsConvertByteTest.php index 0cd1682..a80b091 100644 --- a/test/phpunit/Convert/CoreLibsConvertByteTest.php +++ b/test/phpunit/Convert/CoreLibsConvertByteTest.php @@ -123,47 +123,6 @@ final class CoreLibsConvertByteTest extends TestCase ]; } - /** - * Undocumented function - * - * @return array - */ - public function byteStringProvider(): array - { - return [ - 'negative number' => [ - 0 => '-117.42 MB', - 1 => -123123794, - 2 => -117420000, - ], - 'megabyte' => [ - 0 => '242.98 MB', - 1 => 254782996, - 2 => 242980000 - ], - 'megabyte si' => [ - 0 => '254.78 MiB', - 1 => 267156193, - 2 => 254780000 - ], - 'petabyte' => [ - 0 => '1 EiB', - 1 => 1152921504606846976, - 2 => 1000000000000000000, - ], - 'max int' => [ - 0 => '8 EB', - 1 => -9223372036854775807 - 1, - 2 => 8000000000000000000, - ], - 'exabyte, overflow' => [ - 0 => '867.36EB', - 1 => 3873816255479021568, - 2 => 363028535651074048, - ] - ]; - } - /** * Undocumented function * @@ -180,7 +139,7 @@ final class CoreLibsConvertByteTest extends TestCase * @return void */ public function testHumanReadableByteFormat( - $input, + string|int|float $input, string $expected, string $expected_si, string $expected_no_space, @@ -217,6 +176,73 @@ final class CoreLibsConvertByteTest extends TestCase ); } + /** + * Undocumented function + * + * @return array + */ + public function byteStringProvider(): array + { + return [ + 'negative number' => [ + 0 => '-117.42 MB', + 1 => -123123794, + 2 => -117420000, + 3 => "-123123793", + 4 => "-117420000", + 5 => null, + ], + 'megabyte' => [ + 0 => '242.98 MB', + 1 => 254782996, + 2 => 242980000, + 3 => "254782996", + 4 => "242980000", + 5 => null, + ], + 'megabyte si' => [ + 0 => '254.78 MiB', + 1 => 267156193, + 2 => 254780000, + 3 => "267156193", + 4 => "254780000", + 5 => null, + ], + 'petabyte' => [ + 0 => '1 EiB', + 1 => 1152921504606846976, + 2 => 1000000000000000000, + 3 => "1152921504606846976", + 4 => "1000000000000000000", + 5 => null, + ], + 'max int' => [ + 0 => '8 EB', + 1 => 0, + 2 => 0, + 3 => "9223372036854775808", + 4 => "8000000000000000000", + 5 => \LengthException::class, + ], + 'exabyte, overflow' => [ + 0 => '867.36EB', + 1 => 0, + 2 => 0, + 3 => "999997996235794808832", + 4 => "867360000000000000000", + 5 => \LengthException::class, + ], + 'huge exabyte, overflow' => [ + 0 => '1000EB', + 1 => 0, + 2 => 0, + 3 => "1152921504606846976000", + 4 => "1000000000000000000000", + 5 => \LengthException::class, + ], + ]; + } + /** * Undocumented function * @@ -227,10 +253,22 @@ final class CoreLibsConvertByteTest extends TestCase * @param string|int|float $input * @param string|int|float $expected * @param string|int|float $expected_si + * @param string|int|float $expected_string + * @param string|int|float $expected_string_si + * @param ?string $exception * @return void */ - public function testStringByteFormat($input, $expected, $expected_si): void - { + public function testStringByteFormat( + string|int|float $input, + string|int|float $expected, + string|int|float $expected_si, + string|int|float $expected_string, + string|int|float $expected_string_si, + ?string $exception + ): void { + if ($exception !== null) { + $this->expectException($exception); + } $this->assertEquals( $expected, \CoreLibs\Convert\Byte::stringByteFormat($input) @@ -239,6 +277,17 @@ final class CoreLibsConvertByteTest extends TestCase $expected_si, \CoreLibs\Convert\Byte::stringByteFormat($input, \CoreLibs\Convert\Byte::BYTE_FORMAT_SI) ); + $this->assertEquals( + $expected_string, + \CoreLibs\Convert\Byte::stringByteFormat($input, \CoreLibs\Convert\Byte::RETURN_AS_STRING) + ); + $this->assertEquals( + $expected_string_si, + \CoreLibs\Convert\Byte::stringByteFormat( + $input, + \CoreLibs\Convert\Byte::BYTE_FORMAT_SI | \CoreLibs\Convert\Byte::RETURN_AS_STRING + ) + ); } /** diff --git a/test/phpunit/Convert/CoreLibsConvertMathTest.php b/test/phpunit/Convert/CoreLibsConvertMathTest.php index 5df06aa..c3aa145 100644 --- a/test/phpunit/Convert/CoreLibsConvertMathTest.php +++ b/test/phpunit/Convert/CoreLibsConvertMathTest.php @@ -122,9 +122,9 @@ final class CoreLibsConvertMathTest extends TestCase public function providerCbrt(): array { return [ - 'cube root of 2' => [2, 1.25992, 5], - 'cube root of 3' => [3, 1.44225, 5], - 'cube root of -1' => [-1, 'NAN', 0], + 'cube root of 2' => [2, 1.25992, 5, null], + 'cube root of 3' => [3, 1.44225, 5, null], + 'cube root of -1' => [-1, 'NAN', 0, \InvalidArgumentException::class], ]; } @@ -138,10 +138,14 @@ final class CoreLibsConvertMathTest extends TestCase * @param float|int $number * @param float $expected * @param int $round_to + * @param ?string $exception * @return void */ - public function testCbrt(float|int $number, float|string $expected, int $round_to): void + public function testCbrt(float|int $number, float|string $expected, int $round_to, ?string $exception): void { + if ($exception !== null) { + $this->expectException($exception); + } $this->assertEquals( $expected, round(\CoreLibs\Convert\Math::cbrt($number), $round_to) diff --git a/test/phpunit/UrlRequests/CoreLibsUrlRequestsCurlTest.php b/test/phpunit/UrlRequests/CoreLibsUrlRequestsCurlTest.php index e5a2202..75c7a14 100644 --- a/test/phpunit/UrlRequests/CoreLibsUrlRequestsCurlTest.php +++ b/test/phpunit/UrlRequests/CoreLibsUrlRequestsCurlTest.php @@ -59,8 +59,6 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase continue; } $this->url_basic = $url; - // split out the last / part for url set test - curl_close($handle); // print "Open: $url\n"; break; } @@ -969,76 +967,77 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase "query" => ["foo-get" => "bar"] ]); $this->assertEquals("200", $response["code"], "multi call: get response code not matching"); - if (PHP_VERSION_ID >= 80400) { - $this->assertEquals( - '{"HEADERS":{"HTTP_HOST":"soba.egplusww.jp",' - . '"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1","HTTP_FIRST_CALL":"get",' - . '"HTTP_ACCEPT":"*\/*"},"REQUEST_TYPE":"GET","PARAMS":{"foo-get":"bar"},"BODY":null}', - $response['content'], - 'multi call: get content not matching' - ); - } else { - $this->assertEquals( - '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1",' - . '"HTTP_FIRST_CALL":"get","HTTP_ACCEPT":"*\/*",' - . '"HTTP_HOST":"soba.egplusww.jp"},' - . '"REQUEST_TYPE":"GET",' - . '"PARAMS":{"foo-get":"bar"},"BODY":null}', - $response['content'], - 'multi call: get content not matching' - ); - } + $request_expected = json_decode( + <<assertEquals( + $request_expected, + json_decode($response['content'], true), + 'multi call: get content not matching' + ); // post $response = $curl->post($this->url_basic, [ "headers" => ["second-call" => "post"], "body" => ["foo-post" => "baz"] ]); $this->assertEquals("200", $response["code"], "multi call: post response code not matching"); - if (PHP_VERSION_ID >= 80400) { - $this->assertEquals( - '{"HEADERS":{"HTTP_HOST":"soba.egplusww.jp",' - . '"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1",' - . '"HTTP_SECOND_CALL":"post","HTTP_ACCEPT":"*\/*"},' - . '"REQUEST_TYPE":"POST","PARAMS":[],"BODY":{"foo-post":"baz"}}', - $response['content'], - 'multi call: post content not matching' - ); - } else { - $this->assertEquals( - '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1",' - . '"HTTP_SECOND_CALL":"post","HTTP_ACCEPT":"*\/*",' - . '"HTTP_HOST":"soba.egplusww.jp"},' - . '"REQUEST_TYPE":"POST",' - . '"PARAMS":[],"BODY":{"foo-post":"baz"}}', - $response['content'], - 'multi call: post content not matching' - ); - } + $request_expected = json_decode( + <<assertEquals( + $request_expected, + json_decode($response['content'], true), + 'multi call: post content not matching' + ); // delete $response = $curl->delete($this->url_basic, [ "headers" => ["third-call" => "delete"], ]); $this->assertEquals("200", $response["code"], "multi call: delete response code not matching"); - if (PHP_VERSION_ID >= 80400) { - $this->assertEquals( - '{"HEADERS":{"HTTP_HOST":"soba.egplusww.jp",' - . '"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1",' - . '"HTTP_THIRD_CALL":"delete","HTTP_ACCEPT":"*\/*"},' - . '"REQUEST_TYPE":"DELETE","PARAMS":[],"BODY":[]}', - $response['content'], - 'multi call: delete content not matching' - ); - } else { - $this->assertEquals( - '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1",' - . '"HTTP_THIRD_CALL":"delete","HTTP_ACCEPT":"*\/*",' - . '"HTTP_HOST":"soba.egplusww.jp"},' - . '"REQUEST_TYPE":"DELETE",' - . '"PARAMS":[],"BODY":[]}', - $response['content'], - 'multi call: delete content not matching' - ); - } + $request_expected = json_decode( + <<assertEquals( + $request_expected, + json_decode($response['content'], true), + 'multi call: delete content not matching' + ); } // MARK: auth header set via config