From 4cf4635e259d37cee07effda42c94e6508de2f1c Mon Sep 17 00:00:00 2001 From: Zach Borboa Date: Wed, 19 Feb 2025 21:40:56 -0500 Subject: [PATCH 1/3] Increase psalm strictness (#925) * Fix PossiblyUndefinedArrayOffset ERROR: PossiblyUndefinedArrayOffset - ../src/Curl/Curl.php:1890:28 - Possibly undefined array key (see https://psalm.dev/167) list($key, $value) = explode(':', $raw_headers[$i], 2); * Fix PossiblyUndefinedArrayOffset ERROR: PossiblyUndefinedArrayOffset - ../src/Curl/Curl.php:1034:28 - Possibly undefined array key (see https://psalm.dev/167) list($key, $value) = explode(':', $header, 2); * Fix PossiblyUndefinedArrayOffset ERROR: PossiblyUndefinedArrayOffset - ../src/Curl/MultiCurl.php:465:28 - Possibly undefined array key (see https://psalm.dev/167) list($key, $value) = explode(':', $header, 2); * Fix PossiblyInvalidOperand ERROR: PossiblyInvalidOperand - ../src/Curl/Curl.php:1407:69 - Cannot concatenate with a int<0, max>|string (see https://psalm.dev/163) echo 'Response content length (calculated): ' . $response_calculated_length . "\n"; * Fix PossiblyInvalidArgument ERROR: PossiblyInvalidArgument - ../src/Curl/BaseCurl.php:408:34 - Argument 2 of define expects array|null|scalar, but possibly different type false|resource provided (see https://psalm.dev/092) define('STDERR', fopen('php://stderr', 'wb')); * Fix ArgumentTypeCoercion ERROR: ArgumentTypeCoercion - ../src/Curl/MultiCurl.php:956:16 - Argument 1 of usleep expects int<0, max>, but parent type int provided (see https://psalm.dev/193) usleep((int) $sleep_seconds * 1000000); * Fix PossiblyFalseArgument ERROR: PossiblyFalseArgument - ../src/Curl/MultiCurl.php:131:50 - Argument 2 of file_put_contents cannot be false, possibly array|resource|string value expected (see https://psalm.dev/104) file_put_contents($filename, stream_get_contents($fh)); * Fix PossiblyFalseArgument ERROR: PossiblyFalseArgument - ../src/Curl/Curl.php:437:49 - Argument 2 of stream_copy_to_stream cannot be false, possibly resource value expected (see https://psalm.dev/104) stream_copy_to_stream($tmpfile, $fh); ERROR: PossiblyFalseArgument - ../src/Curl/Curl.php:438:24 - Argument 1 of fclose cannot be false, possibly resource value expected (see https://psalm.dev/104) fclose($fh); * Fix PossiblyFalseArgument ERROR: PossiblyFalseArgument - ../src/Curl/Curl.php:463:49 - Argument 2 of stream_copy_to_stream cannot be false, possibly resource value expected (see https://psalm.dev/104) stream_copy_to_stream($file_handle, $main_file_handle); ERROR: PossiblyFalseArgument - ../src/Curl/Curl.php:468:16 - Argument 1 of fclose cannot be false, possibly resource value expected (see https://psalm.dev/104) fclose($main_file_handle); * Fix PossiblyFalseArgument ERROR: PossiblyFalseArgument - ../src/Curl/Curl.php:1891:36 - Argument 1 of count cannot be false, possibly Countable|array value expected (see https://psalm.dev/104) $raw_headers_count = count($raw_headers); ERROR: PossiblyInvalidArrayAccess - ../src/Curl/Curl.php:1893:24 - Cannot access array value on non-array variable $raw_headers of type false (see https://psalm.dev/109) if (strpos($raw_headers[$i], ':') !== false) { * Fix PossiblyInvalidArgument ERROR: PossiblyInvalidArgument - ../src/Curl/Curl.php:1868:30 - Argument 2 of define expects array|null|scalar, but possibly different type false|resource provided (see https://psalm.dev/092) define('STDOUT', fopen('php://stdout', 'w')); * Update psalm baseline --- src/Curl/BaseCurl.php | 7 ++++--- src/Curl/Curl.php | 28 +++++++++++++++++++--------- src/Curl/MultiCurl.php | 15 ++++++++++++--- tests/psalm-baseline.xml | 17 +++++++++++++++++ 4 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/Curl/BaseCurl.php b/src/Curl/BaseCurl.php index f2032b004e..54d4a5072e 100644 --- a/src/Curl/BaseCurl.php +++ b/src/Curl/BaseCurl.php @@ -404,10 +404,11 @@ public function unsetProxy() public function verbose($on = true, $output = 'STDERR') { if ($output === 'STDERR') { - if (!defined('STDERR')) { - define('STDERR', fopen('php://stderr', 'wb')); + if (defined('STDERR')) { + $output = STDERR; + } else { + $output = fopen('php://stderr', 'wb'); } - $output = STDERR; } // Turn off CURLINFO_HEADER_OUT for verbose to work. This has the side diff --git a/src/Curl/Curl.php b/src/Curl/Curl.php index d4b6c70fd4..b744b1506c 100644 --- a/src/Curl/Curl.php +++ b/src/Curl/Curl.php @@ -430,8 +430,10 @@ public function fastDownload($url, $filename, $connections = 4) $curl->downloadCompleteCallback = function ($instance, $tmpfile) use ($part_file_name) { $fh = fopen($part_file_name, 'wb'); - stream_copy_to_stream($tmpfile, $fh); - fclose($fh); + if ($fh !== false) { + stream_copy_to_stream($tmpfile, $fh); + fclose($fh); + } }; $multi_curl->addCurl($curl); @@ -447,6 +449,9 @@ public function fastDownload($url, $filename, $connections = 4) // Combine downloaded chunks into a single file. $main_file_handle = fopen($filename, 'w'); + if ($main_file_handle === false) { + return false; + } foreach ($part_file_names as $part_file_name) { if (!is_file($part_file_name)) { @@ -1031,7 +1036,7 @@ public function setHeaders($headers) } } else { foreach ($headers as $header) { - list($key, $value) = explode(':', $header, 2); + list($key, $value) = array_pad(explode(':', $header, 2), 2, ''); $key = trim($key); $value = trim($value); $this->headers[$key] = $value; @@ -1404,7 +1409,7 @@ public function diagnose($return = false) if (isset($this->responseHeaders['Content-Length'])) { echo 'Response content length (from content-length header): ' . $response_header_length . "\n"; } else { - echo 'Response content length (calculated): ' . $response_calculated_length . "\n"; + echo 'Response content length (calculated): ' . (string)$response_calculated_length . "\n"; } if ( @@ -1859,13 +1864,15 @@ private function downloadComplete($fh) // Fix "PHP Notice: Use of undefined constant STDOUT" when reading the // PHP script from stdin. Using null causes "Warning: curl_setopt(): // supplied argument is not a valid File-Handle resource". - if (!defined('STDOUT')) { - define('STDOUT', fopen('php://stdout', 'w')); + if (defined('STDOUT')) { + $output = STDOUT; + } else { + $output = fopen('php://stdout', 'w'); } // Reset CURLOPT_FILE with STDOUT to avoid: "curl_exec(): CURLOPT_FILE // resource has gone away, resetting to default". - $this->setFile(STDOUT); + $this->setFile($output); // Reset CURLOPT_RETURNTRANSFER to tell cURL to return subsequent // responses as the return value of curl_exec(). Without this, @@ -1881,13 +1888,16 @@ private function downloadComplete($fh) */ private function parseHeaders($raw_headers) { - $raw_headers = preg_split('/\r\n/', (string) $raw_headers, -1, PREG_SPLIT_NO_EMPTY); $http_headers = new CaseInsensitiveArray(); + $raw_headers = preg_split('/\r\n/', (string) $raw_headers, -1, PREG_SPLIT_NO_EMPTY); + if ($raw_headers === false) { + return ['', $http_headers]; + } $raw_headers_count = count($raw_headers); for ($i = 1; $i < $raw_headers_count; $i++) { if (strpos($raw_headers[$i], ':') !== false) { - list($key, $value) = explode(':', $raw_headers[$i], 2); + list($key, $value) = array_pad(explode(':', $raw_headers[$i], 2), 2, ''); $key = trim($key); $value = trim($value); // Use isset() as array_key_exists() and ArrayAccess are not compatible. diff --git a/src/Curl/MultiCurl.php b/src/Curl/MultiCurl.php index 6baa347d5a..ba87f99aab 100644 --- a/src/Curl/MultiCurl.php +++ b/src/Curl/MultiCurl.php @@ -127,7 +127,10 @@ public function addDownload($url, $mixed_filename) } else { $curl->fileHandle = fopen('php://temp', 'wb'); $curl->downloadCompleteCallback = function ($instance, $fh) use ($filename) { - file_put_contents($filename, stream_get_contents($fh)); + $contents = stream_get_contents($fh); + if ($contents !== false) { + file_put_contents($filename, $contents); + } }; } } @@ -462,7 +465,7 @@ public function setHeaders($headers) } } else { foreach ($headers as $header) { - list($key, $value) = explode(':', $header, 2); + list($key, $value) = array_pad(explode(':', $header, 2), 2, ''); $key = trim($key); $value = trim($value); $this->headers[$key] = $value; @@ -946,7 +949,13 @@ private function waitUntilRequestQuotaAvailable() $sleep_seconds = $sleep_until - microtime(true); // Avoid using time_sleep_until() as it appears to be less precise and not sleep long enough. - usleep((int) $sleep_seconds * 1000000); + // Avoid using usleep(): "Values larger than 1000000 (i.e. sleeping for + // more than a second) may not be supported by the operating system. + // Use sleep() instead." + $sleep_seconds_int = (int)$sleep_seconds; + if ($sleep_seconds_int >= 1) { + sleep($sleep_seconds_int); + } // Ensure that enough time has passed as usleep() may not have waited long enough. $this->currentStartTime = microtime(true); diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml index 867a21c21d..7b21802229 100644 --- a/tests/psalm-baseline.xml +++ b/tests/psalm-baseline.xml @@ -5,5 +5,22 @@ + + curl]]> + curl]]> + + + + + + + + + multiCurl]]> + multiCurl]]> + multiCurl]]> + multiCurl]]> + multiCurl]]> + From 2cc50bd15e617ed27e0912c4df1769caa0b3d536 Mon Sep 17 00:00:00 2001 From: Zach Borboa Date: Wed, 19 Feb 2025 22:13:10 -0500 Subject: [PATCH 2/3] Actually increase psalm strictness (#926) --- tests/psalm.xml | 2 +- tests/psalm_7.4.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/psalm.xml b/tests/psalm.xml index e2f098d3be..2a56ee25db 100644 --- a/tests/psalm.xml +++ b/tests/psalm.xml @@ -1,7 +1,7 @@ Date: Thu, 20 Feb 2025 20:42:49 +0000 Subject: [PATCH 3/3] =?UTF-8?q?Bump=20version:=2011.0.3=20=E2=86=92=2011.0?= =?UTF-8?q?.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 ++++ src/Curl/Curl.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae12a517fb..629f9cc364 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ backwards-incompatible changes that will affect existing usage. +## 11.0.4 - 2025-02-20 + +- Increase psalm strictness ([#925](https://github.com/php-curl-class/php-curl-class/pull/925)) + ## 11.0.3 - 2025-02-19 - Use default for Psalm ensureOverrideAttribute ([#923](https://github.com/php-curl-class/php-curl-class/pull/923)) diff --git a/src/Curl/Curl.php b/src/Curl/Curl.php index b744b1506c..8c1a9e94cd 100644 --- a/src/Curl/Curl.php +++ b/src/Curl/Curl.php @@ -6,7 +6,7 @@ class Curl extends BaseCurl { - public const VERSION = '11.0.3'; + public const VERSION = '11.0.4'; public const DEFAULT_TIMEOUT = 30; public $curl = null;