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/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..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;
@@ -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]]>
+
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 @@