diff --git a/composer.json b/composer.json index b8b9c6c..50051ff 100644 --- a/composer.json +++ b/composer.json @@ -28,11 +28,12 @@ } ], "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "fig/http-message-util": "^1.1.4", "psr/http-factory": "^1.0", "psr/http-message": "^1.0", - "ralouphie/getallheaders": "^3" + "ralouphie/getallheaders": "^3", + "symfony/polyfill-php80": "^1.18" }, "require-dev": { "ext-json": "*", @@ -40,8 +41,9 @@ "http-interop/http-factory-tests": "^0.7.0", "php-http/psr7-integration-tests": "dev-master", "phpstan/phpstan": "^0.12", - "phpunit/phpunit": "^8.5", - "squizlabs/php_codesniffer": "^3.5" + "phpunit/phpunit": "^8.5 || ^9.3", + "squizlabs/php_codesniffer": "^3.5", + "weirdan/prophecy-shim": "^1.0 || ^2.0.2" }, "provide": { "psr/http-message-implementation": "1.0", diff --git a/src/Factory/StreamFactory.php b/src/Factory/StreamFactory.php index dd1d1b1..caeab21 100644 --- a/src/Factory/StreamFactory.php +++ b/src/Factory/StreamFactory.php @@ -15,6 +15,7 @@ use Psr\Http\Message\StreamInterface; use RuntimeException; use Slim\Psr7\Stream; +use ValueError; use function fopen; use function fwrite; @@ -53,20 +54,35 @@ public function createStreamFromFile( string $mode = 'r', StreamInterface $cache = null ): StreamInterface { - // When fopen fails, PHP normally raises a warning. Add an error + // When fopen fails, PHP 7 normally raises a warning. Add an error // handler to check for errors and throw an exception instead. + // On PHP 8, exceptions are thrown. $exc = null; - set_error_handler(function (int $errno, string $errstr) use ($filename, $mode, &$exc) { + // Would not be initialized if fopen throws on PHP >= 8.0 + $resource = null; + + $errorHandler = function (string $errorMessage) use ($filename, $mode, &$exc) { $exc = new RuntimeException(sprintf( 'Unable to open %s using mode %s: %s', $filename, $mode, - $errstr + $errorMessage )); + }; + + set_error_handler(function (int $errno, string $errstr) use ($errorHandler) { + $errorHandler($errstr); }); - $resource = fopen($filename, $mode); + try { + $resource = fopen($filename, $mode); + // @codeCoverageIgnoreStart + // (Can only be executed in PHP >= 8.0) + } catch (ValueError $exception) { + $errorHandler($exception->getMessage()); + } + // @codeCoverageIgnoreEnd restore_error_handler(); if ($exc) { diff --git a/tests/Factory/UploadedFileFactoryTest.php b/tests/Factory/UploadedFileFactoryTest.php index 9c14d18..1c23225 100644 --- a/tests/Factory/UploadedFileFactoryTest.php +++ b/tests/Factory/UploadedFileFactoryTest.php @@ -12,6 +12,7 @@ use Interop\Http\Factory\UploadedFileFactoryTestCase; use InvalidArgumentException; +use Prophecy\PhpUnit\ProphecyTrait; use Psr\Http\Message\StreamInterface; use Slim\Psr7\Factory\StreamFactory; use Slim\Psr7\Factory\UploadedFileFactory; @@ -24,6 +25,8 @@ class UploadedFileFactoryTest extends UploadedFileFactoryTestCase { + use ProphecyTrait; + /** * @return UploadedFileFactory */ diff --git a/tests/StreamTest.php b/tests/StreamTest.php index 1bcdaab..ad1e3ca 100644 --- a/tests/StreamTest.php +++ b/tests/StreamTest.php @@ -11,6 +11,7 @@ namespace Slim\Tests\Psr7; use PHPUnit\Framework\TestCase; +use Prophecy\PhpUnit\ProphecyTrait; use ReflectionException; use ReflectionMethod; use ReflectionProperty; @@ -24,6 +25,8 @@ class StreamTest extends TestCase { + use ProphecyTrait; + /** * @var resource pipe stream file handle */ diff --git a/tests/UploadedFileTest.php b/tests/UploadedFileTest.php index adeefaa..4a4ffaf 100644 --- a/tests/UploadedFileTest.php +++ b/tests/UploadedFileTest.php @@ -12,6 +12,7 @@ use InvalidArgumentException; use PHPUnit\Framework\TestCase; +use Prophecy\PhpUnit\ProphecyTrait; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; use ReflectionProperty; @@ -42,6 +43,8 @@ class UploadedFileTest extends TestCase { + use ProphecyTrait; + private static $filename = './phpUxcOty'; private static $tmpFiles = ['./phpUxcOty']; @@ -245,7 +248,7 @@ public function testMoveTo(UploadedFile $uploadedFile) public function testMoveToRenameFailure() { $this->expectException(RuntimeException::class); - $this->expectExceptionMessageRegExp('/^Error moving uploaded file .* to .*$/'); + $this->expectExceptionMessageMatches('/^Error moving uploaded file .* to .*$/'); $uploadedFile = $this->generateNewTmpFile(); @@ -280,7 +283,7 @@ public function testMoveToSapiNonUploadedFile(UploadedFile $uploadedFile) public function testMoveToSapiMoveUploadedFileFails(UploadedFile $uploadedFile) { $this->expectException(RuntimeException::class); - $this->expectExceptionMessageRegExp('~Error moving uploaded file.*~'); + $this->expectExceptionMessageMatches('~Error moving uploaded file.*~'); $GLOBALS['is_uploaded_file_return'] = true;