diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3666cd47..6f9cfb41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,11 +19,6 @@ jobs: - 7.3 - 7.2 - 7.1 - - 7.0 - - 5.6 - - 5.5 - - 5.4 - - 5.3 steps: - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 @@ -36,19 +31,3 @@ jobs: if: ${{ matrix.php >= 7.3 }} - run: vendor/bin/phpunit --coverage-text -c phpunit.xml.legacy if: ${{ matrix.php < 7.3 }} - - PHPUnit-hhvm: - name: PHPUnit (HHVM) - runs-on: ubuntu-22.04 - continue-on-error: true - steps: - - uses: actions/checkout@v4 - - run: cp "$(which composer)" composer.phar && ./composer.phar self-update --2.2 # downgrade Composer for HHVM - - name: Run hhvm composer.phar install - uses: docker://hhvm/hhvm:3.30-lts-latest - with: - args: hhvm composer.phar install - - name: Run hhvm vendor/bin/phpunit - uses: docker://hhvm/hhvm:3.30-lts-latest - with: - args: hhvm vendor/bin/phpunit diff --git a/README.md b/README.md index 46da303d..9cdf7c09 100644 --- a/README.md +++ b/README.md @@ -2990,8 +2990,7 @@ composer require react/http:^3@dev See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades. This project aims to run on any platform and thus does not require any PHP -extensions and supports running on legacy PHP 5.3 through current PHP 8+ and -HHVM. +extensions and supports running on PHP 7.1 through current PHP 8+. It's *highly recommended to use the latest supported PHP version* for this project. ## Tests diff --git a/composer.json b/composer.json index 23783c0c..33919186 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ } ], "require": { - "php": ">=5.3.0", + "php": ">=7.1", "evenement/evenement": "^3.0 || ^2.0 || ^1.0", "fig/http-message-util": "^1.1", "psr/http-message": "^1.0", @@ -39,8 +39,8 @@ "clue/http-proxy-react": "^1.8", "clue/reactphp-ssh-proxy": "^1.4", "clue/socks-react": "^1.4", - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/async": "^4 || ^3 || ^2", + "phpunit/phpunit": "^9.6 || ^5.7", + "react/async": "^4 || ^3", "react/promise-stream": "^1.4", "react/promise-timer": "^1.9" }, diff --git a/phpunit.xml.legacy b/phpunit.xml.legacy index 89161168..a018d7ab 100644 --- a/phpunit.xml.legacy +++ b/phpunit.xml.legacy @@ -2,7 +2,7 @@ diff --git a/src/Io/ClientRequestStream.php b/src/Io/ClientRequestStream.php index ff9bf2d4..3bdf9b1f 100644 --- a/src/Io/ClientRequestStream.php +++ b/src/Io/ClientRequestStream.php @@ -69,8 +69,7 @@ private function writeHead() } } - /** @var array $m legacy PHP 5.3 only */ - if (!\preg_match('#^\S+ \S+ HTTP/1\.[01]\r\n#m', $headers) || \substr_count($headers, "\n") !== ($expected + 1) || (\PHP_VERSION_ID >= 50400 ? \preg_match_all(AbstractMessage::REGEX_HEADERS, $headers) : \preg_match_all(AbstractMessage::REGEX_HEADERS, $headers, $m)) !== $expected) { + if (!\preg_match('#^\S+ \S+ HTTP/1\.[01]\r\n#m', $headers) || \substr_count($headers, "\n") !== ($expected + 1) || \preg_match_all(AbstractMessage::REGEX_HEADERS, $headers) !== $expected) { $this->closeError(new \InvalidArgumentException('Unable to send request with invalid request headers')); return; } diff --git a/src/Io/MultipartParser.php b/src/Io/MultipartParser.php index 539107ae..c65bb655 100644 --- a/src/Io/MultipartParser.php +++ b/src/Io/MultipartParser.php @@ -36,7 +36,7 @@ final class MultipartParser /** * ini setting "max_input_vars" * - * Does not exist in PHP < 5.3.9 or HHVM, so assume PHP's default 1000 here. + * Assume PHP' default of 1000 here. * * @var int * @link http://php.net/manual/en/info.configuration.php#ini.max-input-vars @@ -46,7 +46,7 @@ final class MultipartParser /** * ini setting "max_input_nesting_level" * - * Does not exist in HHVM, but assumes hard coded to 64 (PHP's default). + * Assume PHP's default of 64 here. * * @var int * @link http://php.net/manual/en/info.configuration.php#ini.max-input-nesting-level @@ -81,14 +81,8 @@ final class MultipartParser */ public function __construct($uploadMaxFilesize = null, $maxFileUploads = null) { - $var = \ini_get('max_input_vars'); - if ($var !== false) { - $this->maxInputVars = (int)$var; - } - $var = \ini_get('max_input_nesting_level'); - if ($var !== false) { - $this->maxInputNestingLevel = (int)$var; - } + $this->maxInputVars = (int) \ini_get('max_input_vars'); + $this->maxInputNestingLevel = (int) \ini_get('max_input_nesting_level'); if ($uploadMaxFilesize === null) { $uploadMaxFilesize = \ini_get('upload_max_filesize'); diff --git a/src/Io/StreamingServer.php b/src/Io/StreamingServer.php index 143edaa8..eee9f900 100644 --- a/src/Io/StreamingServer.php +++ b/src/Io/StreamingServer.php @@ -346,8 +346,7 @@ public function handleResponse(ConnectionInterface $connection, ServerRequestInt } } - /** @var array $m legacy PHP 5.3 only */ - if ($code < 100 || $code > 999 || \substr_count($headers, "\n") !== ($expected + 1) || (\PHP_VERSION_ID >= 50400 ? \preg_match_all(AbstractMessage::REGEX_HEADERS, $headers) : \preg_match_all(AbstractMessage::REGEX_HEADERS, $headers, $m)) !== $expected) { + if ($code < 100 || $code > 999 || \substr_count($headers, "\n") !== ($expected + 1) || \preg_match_all(AbstractMessage::REGEX_HEADERS, $headers) !== $expected) { $this->emit('error', array(new \InvalidArgumentException('Unable to send response with invalid response headers'))); $this->writeError($connection, Response::STATUS_INTERNAL_SERVER_ERROR, $request); return; diff --git a/src/Message/Response.php b/src/Message/Response.php index fa6366ed..107508a9 100644 --- a/src/Message/Response.php +++ b/src/Message/Response.php @@ -151,8 +151,7 @@ public static function json($data) (\defined('JSON_PRETTY_PRINT') ? \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE : 0) | (\defined('JSON_PRESERVE_ZERO_FRACTION') ? \JSON_PRESERVE_ZERO_FRACTION : 0) ); - // throw on error, now `false` but used to be `(string) "null"` before PHP 5.5 - if ($json === false || (\PHP_VERSION_ID < 50500 && \json_last_error() !== \JSON_ERROR_NONE)) { + if ($json === false) { throw new \InvalidArgumentException( 'Unable to encode given data as JSON' . (\function_exists('json_last_error_msg') ? ': ' . \json_last_error_msg() : ''), \json_last_error() diff --git a/src/Message/Uri.php b/src/Message/Uri.php index 4309bbed..6b77d3e7 100644 --- a/src/Message/Uri.php +++ b/src/Message/Uri.php @@ -45,16 +45,7 @@ final class Uri implements UriInterface */ public function __construct($uri) { - // @codeCoverageIgnoreStart - if (\PHP_VERSION_ID < 50407 && \strpos($uri, '//') === 0) { - // @link https://3v4l.org/UrAQP - $parts = \parse_url('http:' . $uri); - unset($parts['schema']); - } else { - $parts = \parse_url($uri); - } - // @codeCoverageIgnoreEnd - + $parts = \parse_url($uri); if ($parts === false || (isset($parts['scheme']) && !\preg_match('#^[a-z]+$#i', $parts['scheme'])) || (isset($parts['host']) && \preg_match('#[\s_%+]#', $parts['host']))) { throw new \InvalidArgumentException('Invalid URI given'); } diff --git a/tests/Client/FunctionalIntegrationTest.php b/tests/Client/FunctionalIntegrationTest.php index 5405874e..6c49c127 100644 --- a/tests/Client/FunctionalIntegrationTest.php +++ b/tests/Client/FunctionalIntegrationTest.php @@ -134,9 +134,6 @@ public function testRequestLegacyHttpServerWithOnlyLineFeedReturnsSuccessfulResp /** @group internet */ public function testSuccessfulResponseEmitsEnd() { - // max_nesting_level was set to 100 for PHP Versions < 5.4 which resulted in failing test for legacy PHP - ini_set('xdebug.max_nesting_level', 256); - $client = new Client(new ClientConnectionManager(new Connector(), Loop::get())); $request = $client->request(new Request('GET', 'http://www.google.com/', array(), '', '1.0')); @@ -155,9 +152,6 @@ public function testSuccessfulResponseEmitsEnd() /** @group internet */ public function testCancelPendingConnectionEmitsClose() { - // max_nesting_level was set to 100 for PHP Versions < 5.4 which resulted in failing test for legacy PHP - ini_set('xdebug.max_nesting_level', 256); - $client = new Client(new ClientConnectionManager(new Connector(), Loop::get())); $request = $client->request(new Request('GET', 'http://www.google.com/', array(), '', '1.0')); diff --git a/tests/FunctionalBrowserTest.php b/tests/FunctionalBrowserTest.php index 7b8ff84b..6a235703 100644 --- a/tests/FunctionalBrowserTest.php +++ b/tests/FunctionalBrowserTest.php @@ -389,10 +389,6 @@ public function testGetRequestWithResponseBufferExceededDuringStreamingRejects() */ public function testCanAccessHttps() { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported on HHVM'); - } - \React\Async\await($this->browser->get('https://www.google.com/')); } @@ -401,10 +397,6 @@ public function testCanAccessHttps() */ public function testVerifyPeerEnabledForBadSslRejects() { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported on HHVM'); - } - $connector = new Connector(array( 'tls' => array( 'verify_peer' => true @@ -423,10 +415,6 @@ public function testVerifyPeerEnabledForBadSslRejects() */ public function testVerifyPeerDisabledForBadSslResolves() { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported on HHVM'); - } - $connector = new Connector(array( 'tls' => array( 'verify_peer' => false diff --git a/tests/FunctionalHttpServerTest.php b/tests/FunctionalHttpServerTest.php index dcd79b3e..6b153b81 100644 --- a/tests/FunctionalHttpServerTest.php +++ b/tests/FunctionalHttpServerTest.php @@ -122,10 +122,6 @@ public function testPlainHttpOnRandomPortWithOtherHostHeaderTakesPrecedence() public function testSecureHttpsOnRandomPort() { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported on HHVM'); - } - $connector = new Connector(array( 'tls' => array('verify_peer' => false) )); @@ -155,10 +151,6 @@ public function testSecureHttpsOnRandomPort() public function testSecureHttpsReturnsData() { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported on HHVM'); - } - $http = new HttpServer(function (RequestInterface $request) { return new Response( 200, @@ -193,10 +185,6 @@ public function testSecureHttpsReturnsData() public function testSecureHttpsOnRandomPortWithoutHostHeaderUsesSocketUri() { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported on HHVM'); - } - $connector = new Connector(array( 'tls' => array('verify_peer' => false) )); @@ -284,10 +272,6 @@ public function testPlainHttpOnStandardPortWithoutHostHeaderReturnsUriWithNoPort public function testSecureHttpsOnStandardPortReturnsUriWithNoPort() { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported on HHVM'); - } - try { $socket = new SocketServer('tls://127.0.0.1:443', array('tls' => array( 'local_cert' => __DIR__ . '/../examples/localhost.pem' @@ -322,10 +306,6 @@ public function testSecureHttpsOnStandardPortReturnsUriWithNoPort() public function testSecureHttpsOnStandardPortWithoutHostHeaderUsesSocketUri() { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported on HHVM'); - } - try { $socket = new SocketServer('tls://127.0.0.1:443', array('tls' => array( 'local_cert' => __DIR__ . '/../examples/localhost.pem' @@ -389,10 +369,6 @@ public function testPlainHttpOnHttpsStandardPortReturnsUriWithPort() public function testSecureHttpsOnHttpStandardPortReturnsUriWithPort() { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported on HHVM'); - } - try { $socket = new SocketServer('tls://127.0.0.1:80', array('tls' => array( 'local_cert' => __DIR__ . '/../examples/localhost.pem' @@ -726,10 +702,6 @@ public function testConnectWithClosedThroughStreamReturnsNoData() public function testLimitConcurrentRequestsMiddlewareRequestStreamPausing() { - if (defined('HHVM_VERSION') && !interface_exists('React\Promise\PromisorInterface')) { - $this->markTestSkipped('Not supported on legacy HHVM with Promise v3'); - } - $connector = new Connector(); $http = new HttpServer( diff --git a/tests/HttpServerTest.php b/tests/HttpServerTest.php index 72d48468..606c50a6 100644 --- a/tests/HttpServerTest.php +++ b/tests/HttpServerTest.php @@ -87,9 +87,6 @@ public function testSimpleRequestCallsRequestHandlerOnce() $this->assertSame(1, $called); } - /** - * @requires PHP 5.4 - */ public function testSimpleRequestCallsArrayRequestHandlerOnce() { $this->called = null; diff --git a/tests/Io/MiddlewareRunnerTest.php b/tests/Io/MiddlewareRunnerTest.php index 762d7bdb..e742ef6d 100644 --- a/tests/Io/MiddlewareRunnerTest.php +++ b/tests/Io/MiddlewareRunnerTest.php @@ -76,9 +76,6 @@ function (ServerRequestInterface $request) { $middleware($request); } - /** - * @requires PHP 7 - */ public function testThrowsIfHandlerThrowsThrowable() { $middleware = new MiddlewareRunner(array( diff --git a/tests/Io/RequestHeaderParserTest.php b/tests/Io/RequestHeaderParserTest.php index 87d6bf1b..1ed994b7 100644 --- a/tests/Io/RequestHeaderParserTest.php +++ b/tests/Io/RequestHeaderParserTest.php @@ -776,10 +776,6 @@ public function testServerParamsWillNotSetRemoteAddressForUnixDomainSockets() public function testServerParamsWontBeSetOnMissingUrls() { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported on HHVM'); - } - $request = null; $clock = $this->getMockBuilder('React\Http\Io\Clock')->disableOriginalConstructor()->getMock(); diff --git a/tests/Io/StreamingServerTest.php b/tests/Io/StreamingServerTest.php index b4e3f2f8..152fece6 100644 --- a/tests/Io/StreamingServerTest.php +++ b/tests/Io/StreamingServerTest.php @@ -82,9 +82,6 @@ public function testRequestEventIsEmitted() $this->connection->emit('data', array($data)); } - /** - * @requires PHP 5.4 - */ public function testRequestEventIsEmittedForArrayCallable() { $this->called = null; @@ -2845,9 +2842,6 @@ function ($data) use (&$buffer) { $this->assertEquals('hello', $exception->getPrevious()->getMessage()); } - /** - * @requires PHP 7 - */ public function testResponseThrowableThrowInCallBackFunctionWillResultInErrorMessage() { $server = new StreamingServer(Loop::get(), function (ServerRequestInterface $request) { diff --git a/tests/Message/ResponseTest.php b/tests/Message/ResponseTest.php index a9a244c2..1c70ae3a 100644 --- a/tests/Message/ResponseTest.php +++ b/tests/Message/ResponseTest.php @@ -97,9 +97,6 @@ public function testHtmlMethodReturnsHtmlResponse() $this->assertEquals('Hello wörld!', (string) $response->getBody()); } - /** - * @requires PHP 5.4 - */ public function testJsonMethodReturnsPrettyPrintedJsonResponse() { $response = Response::json(array('text' => 'Hello wörld!')); @@ -109,9 +106,6 @@ public function testJsonMethodReturnsPrettyPrintedJsonResponse() $this->assertEquals("{\n \"text\": \"Hello wörld!\"\n}\n", (string) $response->getBody()); } - /** - * @requires PHP 5.6.6 - */ public function testJsonMethodReturnsZeroFractionsInJsonResponse() { $response = Response::json(1.0); @@ -132,11 +126,7 @@ public function testJsonMethodReturnsJsonTextForSimpleString() public function testJsonMethodThrowsForInvalidString() { - if (PHP_VERSION_ID < 50500) { - $this->setExpectedException('InvalidArgumentException', 'Unable to encode given data as JSON'); - } else { - $this->setExpectedException('InvalidArgumentException', 'Unable to encode given data as JSON: Malformed UTF-8 characters, possibly incorrectly encoded'); - } + $this->setExpectedException('InvalidArgumentException', 'Unable to encode given data as JSON: Malformed UTF-8 characters, possibly incorrectly encoded'); Response::json("Hello w\xF6rld!"); } diff --git a/tests/Message/UriTest.php b/tests/Message/UriTest.php index 05eec723..10f355df 100644 --- a/tests/Message/UriTest.php +++ b/tests/Message/UriTest.php @@ -130,11 +130,6 @@ public static function provideValidUris() */ public function testToStringReturnsOriginalUriGivenToCtor($string) { - if (PHP_VERSION_ID < 50519 || (PHP_VERSION_ID < 50603 && PHP_VERSION_ID >= 50606)) { - // @link https://3v4l.org/HdoPG - $this->markTestSkipped('Empty password not supported on legacy PHP'); - } - $uri = new Uri($string); $this->assertEquals($string, (string) $uri); diff --git a/tests/Middleware/LimitConcurrentRequestsMiddlewareTest.php b/tests/Middleware/LimitConcurrentRequestsMiddlewareTest.php index faf27cb6..23455e6c 100644 --- a/tests/Middleware/LimitConcurrentRequestsMiddlewareTest.php +++ b/tests/Middleware/LimitConcurrentRequestsMiddlewareTest.php @@ -120,9 +120,6 @@ public function testThrowsExceptionDirectlyFromMiddlewareWhenBelowLimit() }); } - /** - * @requires PHP 7 - */ public function testThrowsErrorDirectlyFromMiddlewareWhenBelowLimit() { $middleware = new LimitConcurrentRequestsMiddleware(1); diff --git a/tests/Middleware/RequestBodyBufferMiddlewareTest.php b/tests/Middleware/RequestBodyBufferMiddlewareTest.php index 40c23378..1c3b0b33 100644 --- a/tests/Middleware/RequestBodyBufferMiddlewareTest.php +++ b/tests/Middleware/RequestBodyBufferMiddlewareTest.php @@ -277,9 +277,6 @@ function (ServerRequestInterface $request) { $this->assertNull($exception->getPrevious()); } - /** - * @requires PHP 7 - */ public function testBufferingRejectsWhenNextHandlerThrowsErrorWhenStreamEnds() { $stream = new ThroughStream(); diff --git a/tests/Middleware/RequestBodyParserMiddlewareTest.php b/tests/Middleware/RequestBodyParserMiddlewareTest.php index 989abc81..b588bdd5 100644 --- a/tests/Middleware/RequestBodyParserMiddlewareTest.php +++ b/tests/Middleware/RequestBodyParserMiddlewareTest.php @@ -109,13 +109,6 @@ function (ServerRequestInterface $request) { public function testFormUrlencodedIgnoresBodyWithExcessiveNesting() { - // supported in all Zend PHP versions and HHVM - // ini setting does exist everywhere but HHVM: https://3v4l.org/hXLiK - // HHVM limits to 64 and returns an empty array structure: https://3v4l.org/j3DK2 - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Not supported on HHVM (limited to depth 64, but keeps empty array structure)'); - } - $allowed = (int)ini_get('max_input_nesting_level'); $middleware = new RequestBodyParserMiddleware(); @@ -144,12 +137,6 @@ function (ServerRequestInterface $request) { public function testFormUrlencodedTruncatesBodyWithExcessiveLength() { - // supported as of PHP 5.3.11, no HHVM support: https://3v4l.org/PiqnQ - // ini setting already exists in PHP 5.3.9: https://3v4l.org/VF6oV - if (defined('HHVM_VERSION') || PHP_VERSION_ID < 50311) { - $this->markTestSkipped('Not supported on HHVM and PHP < 5.3.11 (unlimited length)'); - } - $allowed = (int)ini_get('max_input_vars'); $middleware = new RequestBodyParserMiddleware(); @@ -243,13 +230,7 @@ function (ServerRequestInterface $request) { public function testMultipartFormDataIgnoresFieldWithExcessiveNesting() { - // supported in all Zend PHP versions and HHVM - // ini setting does exist everywhere but HHVM: https://3v4l.org/hXLiK - // HHVM limits to 64 and otherwise returns an empty array structure - $allowed = (int)ini_get('max_input_nesting_level'); - if ($allowed === 0) { - $allowed = 64; - } + $allowed = (int) ini_get('max_input_nesting_level'); $middleware = new RequestBodyParserMiddleware(); @@ -278,12 +259,7 @@ function (ServerRequestInterface $request) { public function testMultipartFormDataTruncatesBodyWithExcessiveLength() { - // ini setting exists in PHP 5.3.9, not in HHVM: https://3v4l.org/VF6oV - // otherwise default to 1000 as implemented within - $allowed = (int)ini_get('max_input_vars'); - if ($allowed === 0) { - $allowed = 1000; - } + $allowed = (int) ini_get('max_input_vars'); $middleware = new RequestBodyParserMiddleware(); @@ -319,12 +295,7 @@ function (ServerRequestInterface $request) { public function testMultipartFormDataTruncatesExcessiveNumberOfEmptyFileUploads() { - // ini setting exists in PHP 5.3.9, not in HHVM: https://3v4l.org/VF6oV - // otherwise default to 1000 as implemented within - $allowed = (int)ini_get('max_input_vars'); - if ($allowed === 0) { - $allowed = 1000; - } + $allowed = (int) ini_get('max_input_vars'); $middleware = new RequestBodyParserMiddleware(); diff --git a/tests/TestCase.php b/tests/TestCase.php index 72b7be8d..88d8a3df 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -72,18 +72,12 @@ public function assertNotContainsString($needle, $haystack) public function setExpectedException($exception, $exceptionMessage = '', $exceptionCode = null) { - if (method_exists($this, 'expectException')) { - // PHPUnit 5+ - $this->expectException($exception); - if ($exceptionMessage !== '') { - $this->expectExceptionMessage($exceptionMessage); - } - if ($exceptionCode !== null) { - $this->expectExceptionCode($exceptionCode); - } - } else { - // legacy PHPUnit 4 - parent::setExpectedException($exception, $exceptionMessage, $exceptionCode); + $this->expectException($exception); + if ($exceptionMessage !== '') { + $this->expectExceptionMessage($exceptionMessage); + } + if ($exceptionCode !== null) { + $this->expectExceptionCode($exceptionCode); } }