diff --git a/library/Requests/Exception/InvalidArgument.php b/library/Requests/Exception/InvalidArgument.php new file mode 100644 index 000000000..7f43d595f --- /dev/null +++ b/library/Requests/Exception/InvalidArgument.php @@ -0,0 +1,8 @@ +hooks = $options['hooks']; $this->setup_handle($url, $headers, $data, $options); diff --git a/library/Requests/Transport/fsockopen.php b/library/Requests/Transport/fsockopen.php index 34b65d4a6..c6ff4ad33 100644 --- a/library/Requests/Transport/fsockopen.php +++ b/library/Requests/Transport/fsockopen.php @@ -56,6 +56,25 @@ class Requests_Transport_fsockopen implements Requests_Transport { * @return string Raw HTTP result */ public function request($url, $headers = array(), $data = array(), $options = array()) { + if (is_array($data) === false && is_string($data) === false) { + if ($data === null) { + $data = ''; + } elseif (is_int($data) || is_float($data)) { + $data = (string) $data; + } else { + throw new Requests_Exception_InvalidArgument( + sprintf( + '%s: Argument #%d (%s) must be of type %s, %s given', + __METHOD__, + 3, + '$data', + 'array|string', + gettype($data) + ) + ); + } + } + $options['hooks']->dispatch('fsockopen.before_request'); $url_parts = parse_url($url); diff --git a/tests/Transport/Base.php b/tests/Transport/Base.php index 066c5ff5a..68b5336c7 100644 --- a/tests/Transport/Base.php +++ b/tests/Transport/Base.php @@ -167,6 +167,77 @@ public function testEmptyPOST() { } } + /** + * Test that when a $data parameter of an incorrect type gets passed, it gets handled correctly. + * + * Only string/array are officially supported as accepted data types, but null, integers and floats + * will also be handled (cast to string). + * + * Original test passing `null` was added in response to issue #248. + * The test was expanded to additional data types in response to changes in PHP 8.1. + * + * @dataProvider dataIncorrectDataTypeAccepted + * + * @param mixed $data Input to be used as the $data parameter. + * @param string $expected Expected content-length header. + * + * @return void + */ + public function testIncorrectDataTypeAcceptedPOST($data, $expected) { + $request = Requests::post(httpbin('/post'), array(), $data, $this->getOptions()); + $this->assertIsObject($request, 'POST request did not return an object'); + $this->assertObjectHasAttribute('status_code', $request, 'POST request object does not have a "status_code" property'); + $this->assertSame(200, $request->status_code, 'POST request status code is not 200'); + + $this->assertObjectHasAttribute('body', $request, 'POST request object does not have a "body" property'); + $result = json_decode($request->body, true); + + $this->assertIsArray($result, 'Json decoded POST request body is not an array'); + $this->assertArrayHasKey('data', $result, 'Json decoded POST request body does not contain array key "data"'); + $this->assertSame($expected, $result['data'],'Json decoded POST request body "data" key did not match expected contents' ); + } + + /** + * Data provider. + * + * @return array + */ + public function dataIncorrectDataTypeAccepted() { + return array( + 'null' => array(null, ''), + 'integer' => array(12345, '12345'), + 'float' => array(12.345, '12.345'), + ); + } + + /** + * Test that when a $data parameter of an unhandled incorrect type gets passed, an exception gets thrown. + * + * @dataProvider dataIncorrectDataTypeException + * + * @param mixed $data Input to be used as the $data parameter. + * + * @return void + */ + public function testIncorrectDataTypeExceptionPOST($data) { + $this->expectException('Requests_Exception_InvalidArgument'); + $this->expectExceptionMessage('Argument #3 ($data) must be of type array|string'); + + $request = Requests::post(httpbin('/post'), array(), $data, $this->getOptions()); + } + + /** + * Data provider. + * + * @return array + */ + public function dataIncorrectDataTypeException() { + return array( + 'boolean' => array(true), + 'object' => array(new stdClass()), + ); + } + public function testFormPost() { $data = 'test=true&test2=test'; $request = Requests::post(httpbin('/post'), array(), $data, $this->getOptions());