diff --git a/conf/config.neon b/conf/config.neon index e946b92542..6f18952254 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -1360,11 +1360,6 @@ services: tags: - phpstan.broker.dynamicFunctionReturnTypeExtension - - - class: PHPStan\Type\Php\CurlInitReturnTypeExtension - tags: - - phpstan.broker.dynamicFunctionReturnTypeExtension - - class: PHPStan\Type\Php\DateFunctionReturnTypeHelper diff --git a/resources/functionMap.php b/resources/functionMap.php index 375c3d38d3..d7f2c1f8ec 100644 --- a/resources/functionMap.php +++ b/resources/functionMap.php @@ -1494,7 +1494,7 @@ 'curl_exec' => ['bool|string', 'ch'=>'resource'], 'curl_file_create' => ['CURLFile', 'filename'=>'string', 'mimetype='=>'string', 'postfilename='=>'string'], 'curl_getinfo' => ['mixed', 'ch'=>'resource', 'option='=>'int'], -'curl_init' => ['resource|false', 'url='=>'string'], +'curl_init' => ['__benevolent', 'url='=>'string'], 'curl_multi_add_handle' => ['int', 'mh'=>'resource', 'ch'=>'resource'], 'curl_multi_close' => ['void', 'mh'=>'resource'], 'curl_multi_errno' => ['int', 'mh'=>'resource'], diff --git a/resources/functionMap_php80delta.php b/resources/functionMap_php80delta.php index 529d433dc1..1b234d2280 100644 --- a/resources/functionMap_php80delta.php +++ b/resources/functionMap_php80delta.php @@ -31,6 +31,7 @@ 'ceil' => ['float', 'number'=>'float'], 'com_load_typelib' => ['bool', 'typelib_name'=>'string', 'case_insensitive='=>'true'], 'count_chars' => ['array|string', 'input'=>'string', 'mode='=>'int'], + 'curl_init' => ['__benevolent', 'url='=>'string'], 'date_add' => ['DateTime', 'object'=>'DateTime', 'interval'=>'DateInterval'], 'date_date_set' => ['DateTime', 'object'=>'DateTime', 'year'=>'int', 'month'=>'int', 'day'=>'int'], 'date_diff' => ['DateInterval', 'obj1'=>'DateTimeInterface', 'obj2'=>'DateTimeInterface', 'absolute='=>'bool'], @@ -169,6 +170,7 @@ 'convert_cyr_string' => ['string', 'str'=>'string', 'from'=>'string', 'to'=>'string'], 'com_load_typelib' => ['bool', 'typelib_name'=>'string', 'case_insensitive='=>'bool'], 'count_chars' => ['array|false|string', 'input'=>'string', 'mode='=>'int'], + 'curl_init' => ['__benevolent', 'url='=>'string'], 'date_add' => ['DateTime|false', 'object'=>'DateTime', 'interval'=>'DateInterval'], 'date_date_set' => ['DateTime|false', 'object'=>'DateTime', 'year'=>'int', 'month'=>'int', 'day'=>'int'], 'date_diff' => ['DateInterval|false', 'obj1'=>'DateTimeInterface', 'obj2'=>'DateTimeInterface', 'absolute='=>'bool'], diff --git a/src/Type/Php/CurlInitReturnTypeExtension.php b/src/Type/Php/CurlInitReturnTypeExtension.php deleted file mode 100644 index a53cbbc685..0000000000 --- a/src/Type/Php/CurlInitReturnTypeExtension.php +++ /dev/null @@ -1,102 +0,0 @@ -getName() === 'curl_init'; - } - - public function getTypeFromFunctionCall( - FunctionReflection $functionReflection, - Node\Expr\FuncCall $functionCall, - Scope $scope, - ): Type - { - $args = $functionCall->getArgs(); - $argsCount = count($args); - $returnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType(); - $notFalseReturnType = TypeCombinator::remove($returnType, new ConstantBooleanType(false)); - if ($argsCount === 0) { - return $notFalseReturnType; - } - - $urlArgType = $scope->getType($args[0]->value); - if ($urlArgType->isConstantScalarValue()->yes() && (new UnionType([new NullType(), new StringType()]))->isSuperTypeOf($urlArgType)->yes()) { - $urlArgReturnTypes = array_map( - fn ($value) => $this->getUrlArgValueReturnType($value, $returnType, $notFalseReturnType), - $urlArgType->getConstantScalarValues(), - ); - return TypeCombinator::union(...$urlArgReturnTypes); - } - - return $returnType; - } - - private function getUrlArgValueReturnType(mixed $urlArgValue, Type $returnType, Type $notFalseReturnType): Type - { - if ($urlArgValue === null) { - return $notFalseReturnType; - } - if (!is_string($urlArgValue)) { - throw new ShouldNotHappenException(); - } - if (str_contains($urlArgValue, "\0")) { - if (!$this->phpVersion->throwsValueErrorForInternalFunctions()) { - // https://github.com/php/php-src/blob/php-7.4.33/ext/curl/interface.c#L112-L115 - return new ConstantBooleanType(false); - } - // https://github.com/php/php-src/blob/php-8.0.0/ext/curl/interface.c#L104-L107 - return new NeverType(); - } - if ($this->phpVersion->isCurloptUrlCheckingFileSchemeWithOpenBasedir()) { - // Before PHP 8.0 an unparsable URL or a file:// scheme would fail if open_basedir is used - // Since we can't detect open_basedir properly, we'll always consider a failure possible if these - // conditions are given - // https://github.com/php/php-src/blob/php-7.4.33/ext/curl/interface.c#L139-L158 - $parsedUrlArgValue = parse_url($urlArgValue); - if ($parsedUrlArgValue === false || (isset($parsedUrlArgValue['scheme']) && strcasecmp($parsedUrlArgValue['scheme'], 'file') === 0)) { - return $returnType; - } - } - if (strlen($urlArgValue) > self::CURL_MAX_INPUT_LENGTH) { - // Since libcurl 7.65.0 this would always fail, but no current PHP version requires it at the moment - // https://github.com/curl/curl/commit/5fc28510a4664f46459d9a40187d81cc08571e60 - return $returnType; - } - return $notFalseReturnType; - } - -} diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index b84ff5feb0..236c066b72 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -1437,6 +1437,12 @@ public function testBug11511(): void $this->assertSame('Access to an undefined property object::$bar.', $errors[0]->getMessage()); } + public function testBug11640(): void + { + $errors = $this->runAnalyse(__DIR__ . '/data/bug-11640.php'); + $this->assertNoErrors($errors); + } + /** * @param string[]|null $allAnalysedFiles * @return Error[] diff --git a/tests/PHPStan/Analyser/data/bug-11640.php b/tests/PHPStan/Analyser/data/bug-11640.php new file mode 100644 index 0000000000..62b1748d2e --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-11640.php @@ -0,0 +1,9 @@ + false, ], ], - new UnionType([ + new BenevolentUnionType([ new ObjectType('CurlHandle'), new ConstantBooleanType(false), ]), diff --git a/tests/PHPStan/Type/Php/CurlInitReturnTypeExtensionTest.php b/tests/PHPStan/Type/Php/CurlInitReturnTypeExtensionTest.php deleted file mode 100644 index 7749b327f1..0000000000 --- a/tests/PHPStan/Type/Php/CurlInitReturnTypeExtensionTest.php +++ /dev/null @@ -1,32 +0,0 @@ -assertFileAsserts($assertType, $file, ...$args); - } - -} diff --git a/tests/PHPStan/Type/Php/data/curl-init-php-7.php b/tests/PHPStan/Type/Php/data/curl-init-php-7.php deleted file mode 100644 index 9778b786e0..0000000000 --- a/tests/PHPStan/Type/Php/data/curl-init-php-7.php +++ /dev/null @@ -1,65 +0,0 @@ -