diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..971de2d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{json,xml,yml}] +indent_size = 2 + +[*.{md,yml}] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index 9667df9..6db3ce1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store -/vendor +build +vendor composer.lock -composer.phar \ No newline at end of file +composer.phar diff --git a/.travis.yml b/.travis.yml index 98d9b2b..31212d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,18 @@ language: php php: - - 5.3 - 5.4 - 5.5 + - 5.6 + - hhvm -before_script: - - sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.2' ]; then wget http://iweb.dl.sourceforge.net/project/simpletest/simpletest/simpletest_1.1/simpletest_1.1.0.tar.gz; tar xf simpletest_1.1.0.tar.gz -C test; else composer install --dev --prefer-source; fi" +after_script: + - vendor/bin/test-reporter -script: php test/Unirest.php +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/802f417bb6e3e1e8b20d + on_success: always + on_failure: always + on_start: false diff --git a/LICENSE b/LICENSE index d57c528..78fe11e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2013 Mashape (http://mashape.com) +Copyright (c) 2013-2015 Mashape (https://www.mashape.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index ffff4a9..a944682 100644 --- a/README.md +++ b/README.md @@ -1,94 +1,109 @@ -# Unirest for PHP [![Build Status](https://api.travis-ci.org/Mashape/unirest-php.png)](https://travis-ci.org/Mashape/unirest-php) +# Unirest for PHP ![GitHub version][github-image] [![version][composer-image]][composer-url] + +[![Build Status][travis-image]][travis-url] +[![Code Climate][codeclimate-image]][codeclimate-url] +[![Coverage Status][codecoverage-image]][codecoverage-url] +[![Dependency Status][dependency-image]][dependency-url] +[![Gitter][gitter-image]][gitter-url] Unirest is a set of lightweight HTTP libraries available in multiple languages, ideal for most applications: -* Make `GET`, `POST`, `PUT`, `PATCH`, `DELETE` requests -* It supports form parameters, file uploads and custom body entities +## Features + +* Utility methods to call `GET`, `HEAD`, `POST`, `PUT`, `DELETE`, `CONNECT`, `OPTIONS`, `TRACE`, `PATCH` requests +* Supports form parameters, file uploads and custom body entities * Supports gzip * Supports Basic Authentication natively * Customizable timeout * Customizable default headers for every request (DRY) * Automatic JSON parsing into a native object for JSON responses -Created with love by [thefosk](https://github.com/thefosk) @ [mashape.com](https://mashape.com) +## Installation ---- +### Using [Composer](https://getcomposer.org) -**To the community**: At this time Unirest-PHP only support syncronous requests, and I would really love to implement asynchronous support. If you guys have any feedback or ideas please comment on issue #23. +To install unirest-php with Composer, just add the following to your `composer.json` file: ---- - -### Install with Composer -If you're using [Composer](https://github.com/composer/composer) to manage -dependencies, you can add Unirest with it. - -```javascript +```json +// composer.json { - "require" : { - "mashape/unirest-php" : "dev-master" - }, - "autoload": { - "psr-0": {"Unirest": "lib/"} - } + "require-dev": { + "mashape/unirest-php": "2.*" + } } ``` -### Install source from GitHub -Unirest-PHP requires PHP `v5.3+`. Download the PHP library from Github, and require in your script like so: +or by running the following command: -To install the source code: - -```bash -$ git clone git@github.com:Mashape/unirest-php.git +```shell +composer require mashape/unirest-php ``` -And include it in your scripts: +This will get you the latest version of the reporter and install it. If you do want the master, untagged, version you may use the command below: -```bash -require_once '/path/to/unirest-php/lib/Unirest.php'; +```shell +composer require mashape/php-test-reporter:@dev-master ``` -## Creating Request +Composer installs autoloader at `./vendor/autoloader.php`. to include the library in your script, add: + +```php +require_once 'vendor/autoload.php'; +``` + +If you use Symfony2, autoloader has to be detected automatically. + +*You can see this library on [Packagist](https://packagist.org/packages/mashape/unirest-php).* + +### Install from source + +Unirest-PHP requires PHP `v5.4+`. Download the PHP library from Github, then include `Unirest.php` in your script: + +```shell +git clone git@github.com:Mashape/unirest-php.git +``` + +```php +require_once '/path/to/unirest-php/src/Unirest.php'; +``` + +## Usage + +### Creating a Request So you're probably wondering how using Unirest makes creating requests in PHP easier, let's look at a working example: ```php -$response = Unirest::post("http://httpbin.org/post", array( "Accept" => "application/json" ), - array( - "parameter" => 23, - "foo" => "bar" - ) -); +$headers = array("Accept" => "application/json"); +$body = array("foo" => "hellow", "bar" => "world"); -$response->code; // HTTP Status code -$response->headers; // Headers -$response->body; // Parsed body -$response->raw_body; // Unparsed body +$response = Unirest\Request::post("http://httpbin.org/post", $headers, $body); + +$response->code; // HTTP Status code +$response->headers; // Headers +$response->body; // Parsed body +$response->raw_body; // Unparsed body ``` ### File Uploads -To upload files in a multipart form representation use the return value of `Unirest::file($path)` as the value of a parameter: +To upload files in a multipart form representation use the return value of `Unirest\File::add($path)` as the value of a parameter: ```php -$response = Unirest::post("http://httpbin.org/post", array( "Accept" => "application/json" ), - array( - "file" => Unirest::file("/tmp/file.txt") // Tells Unirest where the file is located - ) -); +$headers = array("Accept" => "application/json"); +$body = array("file" => Unirest\File::add("/tmp/file.txt")); + +$response = Unirest\Request::post("http://httpbin.org/post", $headers, $body); ``` ### Custom Entity Body + Sending a custom body such as a JSON Object rather than a string or form style parameters we utilize json_encode for the body: ```php -$response = Unirest::post("http://httpbin.org/post", array( "Accept" => "application/json" ), - json_encode( - array( - "parameter" => "value", - "foo" => "bar" - ) - ) -); +$headers = array("Accept" => "application/json"); +$body = json_encode(array("foo" => "hellow", "bar" => "world")); + +$response = Unirest\Request::post("http://httpbin.org/post", $headers, $body); ``` ### Basic Authentication @@ -96,16 +111,17 @@ $response = Unirest::post("http://httpbin.org/post", array( "Accept" => "applica Authenticating the request with basic authentication can be done by providing the `username` and `password` arguments: ```php -$response = Unirest::get("http://httpbin.org/get", null, null, "username", "password"); +$response = Unirest\Request::get("http://httpbin.org/get", null, null, "username", "password"); ``` -# Request +### Request Object + ```php -Unirest::get($url, $headers = array(), $parameters = NULL, $username = NULL, $password = NULL) -Unirest::post($url, $headers = array(), $body = NULL, $username = NULL, $password = NULL) -Unirest::put($url, $headers = array(), $body = NULL, $username = NULL, $password = NULL) -Unirest::patch($url, $headers = array(), $body = NULL, $username = NULL, $password = NULL) -Unirest::delete($url, $headers = array(), $body = NULL, $username = NULL, $password = NULL) +Unirest\Request::get($url, $headers = array(), $parameters = NULL, $username = NULL, $password = NULL) +Unirest\Request::post($url, $headers = array(), $body = NULL, $username = NULL, $password = NULL) +Unirest\Request::put($url, $headers = array(), $body = NULL, $username = NULL, $password = NULL) +Unirest\Request::patch($url, $headers = array(), $body = NULL, $username = NULL, $password = NULL) +Unirest\Request::delete($url, $headers = array(), $body = NULL, $username = NULL, $password = NULL) ``` - `url` - Endpoint, address, or uri to be acted upon and requested information from. @@ -114,7 +130,8 @@ Unirest::delete($url, $headers = array(), $body = NULL, $username = NULL, $passw - `username` - Basic Authentication username - `password` - Basic Authentication password -# Response +### Response Object + Upon recieving a response Unirest returns the result in the form of an Object, this object should always have the same keys for each language regarding to the response details. - `code` - HTTP Response Status Code (Example `200`) @@ -122,39 +139,67 @@ Upon recieving a response Unirest returns the result in the form of an Object, t - `body` - Parsed response body where applicable, for example JSON responses are parsed to Objects / Associative Arrays. - `raw_body` - Un-parsed response body -# Advanced Configuration +### Advanced Configuration You can set some advanced configuration to tune Unirest-PHP: -### Timeout +#### Timeout You can set a custom timeout value (in **seconds**): ```php -Unirest::timeout(5); // 5s timeout +Unirest\Request::timeout(5); // 5s timeout ``` -### Default Request Headers +#### Default Request Headers You can set default headers that will be sent on every request: ```php -Unirest::defaultHeader("Header1", "Value1"); -Unirest::defaultHeader("Header2", "Value2"); +Unirest\Request::defaultHeader("Header1", "Value1"); +Unirest\Request::defaultHeader("Header2", "Value2"); ``` You can clear the default headers anytime with: ```php -Unirest::clearDefaultHeaders(); +Unirest\Request::clearDefaultHeaders(); ``` -### SSL validation +#### SSL validation You can explicitly enable or disable SSL certificate validation when consuming an SSL protected endpoint: ```php -Unirest::verifyPeer(false); // Disables SSL cert validation +Unirest\Request::verifyPeer(false); // Disables SSL cert validation ``` By default is `true`. + +## License + +Licensed under [the MIT license](LICENSE). + +Created with love by [![Mashape Logo][mashape-logo]](https://www.mashape.com/) + +[github-image]: https://badge.fury.io/gh/mashape%2Funirest-php.svg + +[gitter-url]: https://gitter.im/Mashape +[gitter-image]: https://badges.gitter.im/Mashape.png + +[composer-url]: http://badge.fury.io/ph/mashape%2Funirest-php +[composer-image]: https://badge.fury.io/ph/mashape%2Funirest-php.svg + +[travis-url]: https://travis-ci.org/Mashape/unirest-php +[travis-image]: https://travis-ci.org/Mashape/unirest-php.png?branch=master + +[codeclimate-url]: https://codeclimate.com/github/Mashape/unirest-php +[codeclimate-image]: https://codeclimate.com/github/Mashape/unirest-php/badges/gpa.svg + +[codecoverage-url]: https://codeclimate.com/github/Mashape/unirest-php +[codecoverage-image]: https://codeclimate.com/github/Mashape/unirest-php/badges/coverage.svg + +[dependency-url]: https://www.versioneye.com/user/projects/54b702db050646ca5c00019d +[dependency-image]: https://www.versioneye.com/user/projects/54b702db050646ca5c00019d/badge.svg?style=flat + +[mashape-logo]: https://cloud.githubusercontent.com/assets/183195/5750736/c94e178c-9c26-11e4-91b2-84bcd5d33e28.png diff --git a/composer.json b/composer.json index 9cc280c..3251532 100644 --- a/composer.json +++ b/composer.json @@ -1,31 +1,27 @@ { - "name" : "mashape/unirest-php", - "description" : "Unirest PHP", - "keywords" : ["rest", "curl", "http", "client"], - "type" : "library", - "homepage" : "https://github.com/Mashape/unirest-php", - "license" : "MIT", - "authors" : [ - { - "name" : "Mashape", - "email" : "support@mashape.com", - "homepage" : "http://mashape.com" - } - ], - "require" : { - "php" : ">=5.3.0", - "ext-curl" : "*", - "ext-json" : "*" - }, - "require-dev": { - "vierbergenlars/simpletest": "*" - }, - "autoload" : { - "psr-0" : { - "Unirest" : "lib" - } - }, - "support" : { - "email" : "support@mashape.com" + "name": "mashape/unirest-php", + "description": "Unirest PHP", + "keywords": ["rest", "curl", "http", "https", "client"], + "type": "library", + "homepage": "https://github.com/Mashape/unirest-php", + "license": "MIT", + "author": "Mashape (https://www.mashape.com)", + "require": { + "php": ">=5.4.0", + "ext-curl": "0.0.0.*", + "ext-json": "~1.3" + }, + "require-dev": { + "ext-xdebug": "~2.2", + "phpunit/phpunit": "~4.4", + "codeclimate/php-test-reporter": "0.1.*" + }, + "autoload": { + "psr-0": { + "Unirest": "src" } -} \ No newline at end of file + }, + "support": { + "email": "opensource@mashape.com" + } +} diff --git a/lib/Unirest.php b/lib/Unirest.php deleted file mode 100644 index ca05faa..0000000 --- a/lib/Unirest.php +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file diff --git a/lib/Unirest/HttpMethod.php b/lib/Unirest/HttpMethod.php deleted file mode 100644 index 9252405..0000000 --- a/lib/Unirest/HttpMethod.php +++ /dev/null @@ -1,14 +0,0 @@ -code = $code; - $this->headers = $this->get_headers_from_curl_response($headers); - $this->raw_body = $raw_body; - $this->body = $raw_body; - $json = json_decode($raw_body); - - if (json_last_error() == JSON_ERROR_NONE) { - $this->body = $json; - } - } - - /** - * Return a property of the response if it exists. - * Possibilities include: code, raw_body, headers, body (if the response is json-decodable) - * @return mixed - */ - public function __get($property) - { - if (property_exists($this, $property)) { - return $this->$property; - } - } - - /** - * Set the properties of this object - * @param string $property the property name - * @param mixed $value the property value - */ - public function __set($property, $value) - { - if (property_exists($this, $property)) { - $this->$property = $value; - } - return $this; - } - - /** - * Retrieve the cURL response headers from the - * header string and convert it into an array - * @param string $headers header string from cURL response - * @return array - */ - private function get_headers_from_curl_response($headers) - { - $headers = explode("\r\n", $headers); - array_shift($headers); - - foreach ($headers as $line) { - if (strstr($line, ': ')) { - list($key, $value) = explode(': ', $line); - $result[$key] = $value; - } - } - - return $result; - } - -} \ No newline at end of file diff --git a/lib/Unirest/Unirest.php b/lib/Unirest/Unirest.php deleted file mode 100644 index 8cb109e..0000000 --- a/lib/Unirest/Unirest.php +++ /dev/null @@ -1,319 +0,0 @@ - $value) { - $k = isset($prefix) ? $prefix . '[' . $key . ']' : $key; - if (!$value instanceof \CURLFile AND (is_array($value) OR is_object($value))) { - Unirest::http_build_query_for_curl($value, $new, $k); - } else { - $new[$k] = $value; - } - } - } - - /** - * Send a cURL request - * @param string $httpMethod HTTP method to use (based off \Unirest\HttpMethod constants) - * @param string $url URL to send the request to - * @param mixed $body request body - * @param array $headers additional headers to send - * @param string $username Basic Authentication username - * @param string $password Basic Authentication password - * @throws Exception if a cURL error occurs - * @return HttpResponse - */ - private static function request($httpMethod, $url, $body = NULL, $headers = array(), $username = NULL, $password = NULL) - { - if ($headers == NULL) - $headers = array(); - - $lowercaseHeaders = array(); - $finalHeaders = array_merge($headers, Unirest::$defaultHeaders); - foreach ($finalHeaders as $key => $val) { - $lowercaseHeaders[] = Unirest::getHeader($key, $val); - } - - $lowerCaseFinalHeaders = array_change_key_case($finalHeaders); - if (!array_key_exists("user-agent", $lowerCaseFinalHeaders)) { - $lowercaseHeaders[] = "user-agent: unirest-php/1.1"; - } - if (!array_key_exists("expect", $lowerCaseFinalHeaders)) { - $lowercaseHeaders[] = "expect:"; - } - - $ch = curl_init(); - if ($httpMethod != HttpMethod::GET) { - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $httpMethod); - if (is_array($body) || $body instanceof Traversable) { - Unirest::http_build_query_for_curl($body, $postBody); - curl_setopt($ch, CURLOPT_POSTFIELDS, $postBody); - } else { - curl_setopt($ch, CURLOPT_POSTFIELDS, $body); - } - } else if (is_array($body)) { - if (strpos($url, '?') !== false) { - $url .= "&"; - } else { - $url .= "?"; - } - Unirest::http_build_query_for_curl($body, $postBody); - $url .= urldecode(http_build_query($postBody)); - } - - curl_setopt($ch, CURLOPT_URL, Unirest::encodeUrl($url)); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($ch, CURLOPT_MAXREDIRS, 10); - curl_setopt($ch, CURLOPT_HTTPHEADER, $lowercaseHeaders); - curl_setopt($ch, CURLOPT_HEADER, true); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, Unirest::$verifyPeer); - curl_setopt($ch, CURLOPT_ENCODING, ""); // If an empty string, "", is set, a header containing all supported encoding types is sent. - if (Unirest::$socketTimeout != null) { - curl_setopt($ch, CURLOPT_TIMEOUT, Unirest::$socketTimeout); - } - if (!empty($username)) { - curl_setopt($ch, CURLOPT_USERPWD, $username . ":" . ((empty($password)) ? "" : $password)); - } - - $response = curl_exec($ch); - $error = curl_error($ch); - if ($error) { - throw new Exception($error); - } - - // Split the full response in its headers and body - $curl_info = curl_getinfo($ch); - $header_size = $curl_info["header_size"]; - $header = substr($response, 0, $header_size); - $body = substr($response, $header_size); - $httpCode = $curl_info["http_code"]; - - return new HttpResponse($httpCode, $body, $header); - } - - private static function getArrayFromQuerystring($querystring) - { - $pairs = explode("&", $querystring); - $vars = array(); - foreach ($pairs as $pair) { - $nv = explode("=", $pair, 2); - $name = $nv[0]; - $value = $nv[1]; - $vars[$name] = $value; - } - return $vars; - } - - /** - * Ensure that a URL is encoded and safe to use with cURL - * @param string $url URL to encode - * @return string - */ - private static function encodeUrl($url) - { - $url_parsed = parse_url($url); - - $scheme = $url_parsed['scheme'] . '://'; - $host = $url_parsed['host']; - $port = (isset($url_parsed['port']) ? $url_parsed['port'] : null); - $path = (isset($url_parsed['path']) ? $url_parsed['path'] : null); - $query = (isset($url_parsed['query']) ? $url_parsed['query'] : null); - - if ($query != null) { - $query = '?' . http_build_query(Unirest::getArrayFromQuerystring($url_parsed['query'])); - } - - if ($port && $port[0] != ":") - $port = ":" . $port; - - $result = $scheme . $host . $port . $path . $query; - return $result; - } - - private static function getHeader($key, $val) - { - $key = trim(strtolower($key)); - return $key . ": " . $val; - } - -} - -if (!function_exists('http_chunked_decode')) { - /** - * Dechunk an http 'transfer-encoding: chunked' message - * @param string $chunk the encoded message - * @return string the decoded message - */ - function http_chunked_decode($chunk) - { - $pos = 0; - $len = strlen($chunk); - $dechunk = null; - - while (($pos < $len) && ($chunkLenHex = substr($chunk, $pos, ($newlineAt = strpos($chunk, "\n", $pos + 1)) - $pos))) { - - if (!is_hex($chunkLenHex)) { - trigger_error('Value is not properly chunk encoded', E_USER_WARNING); - return $chunk; - } - - $pos = $newlineAt + 1; - $chunkLen = hexdec(rtrim($chunkLenHex, "\r\n")); - $dechunk .= substr($chunk, $pos, $chunkLen); - $pos = strpos($chunk, "\n", $pos + $chunkLen) + 1; - } - - return $dechunk; - } -} - -/** - * determine if a string can represent a number in hexadecimal - * @link http://uk1.php.net/ctype_xdigit - * @param string $hex - * @return boolean true if the string is a hex, otherwise false - */ -function is_hex($hex) -{ - return ctype_xdigit($hex); -} - -?> diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..0966344 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,16 @@ + + + + + + + + + ./tests + + + + + + + diff --git a/src/Unirest.php b/src/Unirest.php new file mode 100644 index 0000000..a75eb85 --- /dev/null +++ b/src/Unirest.php @@ -0,0 +1,6 @@ + $value) { + if ($parent) { + $new_key = sprintf('%s[%s]', $parent, $key); + } else { + $new_key = $key; + } + + if (!$value instanceof \CURLFile and (is_array($value) or is_object($value))) { + $result = array_merge($result, self::buildHTTPCurlQuery($value, $new_key)); + } else { + $result[$new_key] = $value; + } + } + + return $result; + } + + /** + * Send a cURL request + * @param Unirest\Method $method HTTP method to use + * @param string $url URL to send the request to + * @param mixed $body request body + * @param array $headers additional headers to send + * @param string $username Basic Authentication username + * @param string $password Basic Authentication password + * @throws Exception if a cURL error occurs + * @return Unirest\Response + */ + private static function send($method, $url, $body = null, $headers = array(), $username = null, $password = null) + { + if ($headers == null) { + $headers = array(); + } + + $lowercaseHeaders = array(); + $finalHeaders = array_merge($headers, self::$defaultHeaders); + foreach ($finalHeaders as $key => $val) { + $lowercaseHeaders[] = self::getHeader($key, $val); + } + + $lowerCaseFinalHeaders = array_change_key_case($finalHeaders); + + if (!array_key_exists('user-agent', $lowerCaseFinalHeaders)) { + $lowercaseHeaders[] = 'user-agent: unirest-php/2.0'; + } + + if (!array_key_exists('expect', $lowerCaseFinalHeaders)) { + $lowercaseHeaders[] = 'expect:'; + } + + $ch = curl_init(); + + if ($method != Method::GET) { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + + if (is_array($body) || $body instanceof \Traversable) { + curl_setopt($ch, CURLOPT_POSTFIELDS, self::buildHTTPCurlQuery($body)); + } else { + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + } + } elseif (is_array($body)) { + if (strpos($url, '?') !== false) { + $url .= '&'; + } else { + $url .= '?'; + } + + $url .= urldecode(http_build_query(self::buildHTTPCurlQuery($body))); + } + + curl_setopt($ch, CURLOPT_URL, self::encodeUrl($url)); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_MAXREDIRS, 10); + curl_setopt($ch, CURLOPT_HTTPHEADER, $lowercaseHeaders); + curl_setopt($ch, CURLOPT_HEADER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, self::$verifyPeer); + curl_setopt($ch, CURLOPT_ENCODING, ''); // If an empty string, '', is set, a header containing all supported encoding types is sent. + + if (self::$socketTimeout != null) { + curl_setopt($ch, CURLOPT_TIMEOUT, self::$socketTimeout); + } + + if (!empty($username)) { + curl_setopt($ch, CURLOPT_USERPWD, $username . ':' . ((empty($password)) ? '' : $password)); + } + + $response = curl_exec($ch); + $error = curl_error($ch); + + if ($error) { + throw new \Exception($error); + } + + // Split the full response in its headers and body + $curl_info = curl_getinfo($ch); + $header_size = $curl_info['header_size']; + $header = substr($response, 0, $header_size); + $body = substr($response, $header_size); + $httpCode = $curl_info['http_code']; + + return new Response($httpCode, $body, $header); + } + + private static function getArrayFromQuerystring($query) + { + $query = preg_replace_callback('/(?:^|(?<=&))[^=[]+/', function ($match) { + return bin2hex(urldecode($match[0])); + }, $query); + + parse_str($query, $values); + + return array_combine(array_map('hex2bin', array_keys($values)), $values); + } + + /** + * Ensure that a URL is encoded and safe to use with cURL + * @param string $url URL to encode + * @return string + */ + private static function encodeUrl($url) + { + $url_parsed = parse_url($url); + + $scheme = $url_parsed['scheme'] . '://'; + $host = $url_parsed['host']; + $port = (isset($url_parsed['port']) ? $url_parsed['port'] : null); + $path = (isset($url_parsed['path']) ? $url_parsed['path'] : null); + $query = (isset($url_parsed['query']) ? $url_parsed['query'] : null); + + if ($query != null) { + $query = '?' . http_build_query(self::getArrayFromQuerystring($query)); + } + + if ($port && $port[0] != ':') { + $port = ':' . $port; + } + + $result = $scheme . $host . $port . $path . $query; + return $result; + } + + private static function getHeader($key, $val) + { + $key = trim(strtolower($key)); + return $key . ': ' . $val; + } +} diff --git a/src/Unirest/Response.php b/src/Unirest/Response.php new file mode 100644 index 0000000..d0b4b0b --- /dev/null +++ b/src/Unirest/Response.php @@ -0,0 +1,69 @@ +code = $code; + $this->headers = $this->parseHeaders($headers); + $this->raw_body = $raw_body; + $this->body = $raw_body; + $json = json_decode($raw_body); + + if (json_last_error() === JSON_ERROR_NONE) { + $this->body = $json; + } + } + + /** + * if PECL_HTTP is not available use a fall back function + * + * thanks to ricardovermeltfoort@gmail.com + * http://php.net/manual/en/function.http-parse-headers.php#112986 + */ + private function parseHeaders($raw_headers) + { + if (function_exists('http_parse_headers')) { + return http_parse_headers($raw_headers); + } else { + $key = ''; + $headers = array(); + + foreach (explode("\n", $raw_headers) as $i => $h) { + $h = explode(':', $h, 2); + + if (isset($h[1])) { + if (!isset($headers[$h[0]])) { + $headers[$h[0]] = trim($h[1]); + } elseif (is_array($headers[$h[0]])) { + $headers[$h[0]] = array_merge($headers[$h[0]], array(trim($h[1]))); + } else { + $headers[$h[0]] = array_merge(array($headers[$h[0]]), array(trim($h[1]))); + } + + $key = $h[0]; + } else { + if (substr($h[0], 0, 1) == "\t") { + $headers[$key] .= "\r\n\t".trim($h[0]); + } elseif (!$key) { + $headers[0] = trim($h[0]); + } + } + } + + return $headers; + } + } +} diff --git a/test/.gitignore b/test/.gitignore deleted file mode 100644 index d875a72..0000000 --- a/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -simpletest diff --git a/test/Unirest.php b/test/Unirest.php deleted file mode 100644 index 031c389..0000000 --- a/test/Unirest.php +++ /dev/null @@ -1,27 +0,0 @@ -, and either install it " . "in your PHP include_path or put it in the test/ directory.\n"; - exit(1); -} - -// Throw an exception on any error -function exception_error_handler($errno, $errstr, $errfile, $errline) -{ - throw new ErrorException($errstr, $errno, 0, $errfile, $errline); -} - -set_error_handler('exception_error_handler'); -error_reporting(E_ALL | E_STRICT); - -require_once(dirname(__FILE__) . '/../lib/Unirest.php'); - -require_once(dirname(__FILE__) . '/Unirest/UnirestTest.php'); - -?> \ No newline at end of file diff --git a/test/Unirest/UnirestTest.php b/test/Unirest/UnirestTest.php deleted file mode 100644 index 188fa85..0000000 --- a/test/Unirest/UnirestTest.php +++ /dev/null @@ -1,374 +0,0 @@ - "application/json" - ), array( - "nick" => "thefosk" - )); - - $this->assertEqual(200, $response->code); - - $args = $response->body->args; - $this->assertEqual("Mark", $args->name); - $this->assertEqual("thefosk", $args->nick); - } - - public function testGetMultidimensionalArray() - { - $response = Unirest::get("http://httpbin.org/get", array( - "Accept" => "application/json" - ), array( - 'key' => 'value', - 'items' => array( - 'item1', - 'item2' - ) - )); - - $this->assertEqual(200, $response->code); - - $args = $response->body->args; - - $this->assertEqual("value", $args->key); - $this->assertEqual("item1", $args->{"items[0]"}); - $this->assertEqual("item2", $args->{"items[1]"}); - } - - public function testGetWithDots() - { - $response = Unirest::get("http://httpbin.org/get", array( - "Accept" => "application/json" - ), array( - "user.name" => "Mark", - "nick" => "thefosk" - )); - - $this->assertEqual(200, $response->code); - - $args = $response->body->args; - $this->assertEqual("Mark", $args->{"user.name"}); - $this->assertEqual("thefosk", $args->nick); - } - - public function testGetWithDots2() - { - $response = Unirest::get("http://httpbin.org/get", array( - "Accept" => "application/json" - ), array( - "user.name" => "Mark Bond", - "nick" => "thefosk" - )); - - $this->assertEqual(200, $response->code); - - $args = $response->body->args; - $this->assertEqual("Mark Bond", $args->{"user.name"}); - $this->assertEqual("thefosk", $args->nick); - } - - public function testPost() - { - $response = Unirest::post("http://httpbin.org/post", array( - "Accept" => "application/json" - ), array( - "name" => "Mark", - "nick" => "thefosk" - )); - - $this->assertEqual(200, $response->code); - - $form = $response->body->form; - $this->assertEqual("Mark", $form->name); - $this->assertEqual("thefosk", $form->nick); - } - - public function testPostWithEqualSign() - { - $response = Unirest::post("http://httpbin.org/post", array( - "Accept" => "application/json" - ), array( - "name" => "Mark=Hello" - )); - - $this->assertEqual(200, $response->code); - - $form = $response->body->form; - $this->assertEqual("Mark=Hello", $form->name); - } - - public function testGetWithEqualSign() - { - $response = Unirest::get("http://httpbin.org/get", array( - "Accept" => "application/json" - ), array( - "name" => "Mark=Hello" - )); - - $this->assertEqual(200, $response->code); - - $args = $response->body->args; - $this->assertEqual("Mark=Hello", $args->name); - - $response = Unirest::get("http://httpbin.org/get", array( - "Accept" => "application/json" - ), array( - "name" => "Mark=Hello=John" - )); - - $this->assertEqual(200, $response->code); - - $args = $response->body->args; - $this->assertEqual("Mark=Hello=John", $args->name); - } - - public function testPostArray() - { - $response = Unirest::post("http://httpbin.org/post", array( - "Accept" => "application/json" - ), array( - "name[0]" => "Mark", - "name[1]" => "John" - )); - - $this->assertEqual(200, $response->code); - - $form = $response->body->form; - - $this->assertEqual("Mark", $form->{"name[0]"}); - $this->assertEqual("John", $form->{"name[1]"}); - } - - public function testGetArray() - { - $response = Unirest::get("http://httpbin.org/get", array(), array( - "name[0]" => "Mark", - "name[1]" => "John" - )); - - $this->assertEqual(200, $response->code); - - $args = $response->body->args; - $this->assertEqual("Mark", $args->{"name[0]"}); - $this->assertEqual("John", $args->{"name[1]"}); - } - - public function testPostWithDots() - { - $response = Unirest::post("http://httpbin.org/post", array( - "Accept" => "application/json" - ), array( - "user.name" => "Mark", - "nick" => "thefosk" - )); - - $this->assertEqual(200, $response->code); - - $form = $response->body->form; - $this->assertEqual("Mark", $form->{"user.name"}); - $this->assertEqual("thefosk", $form->nick); - } - - public function testRawPost() - { - $response = Unirest::post("http://httpbin.org/post", array( - "Accept" => "application/json" - ), json_encode(array( - "author" => "Sam Sullivan" - ))); - - $this->assertEqual(200, $response->code); - - $json = $response->body->json; - $this->assertEqual("Sam Sullivan", $json->author); - } - - public function testUpload() - { - $response = Unirest::post("http://httpbin.org/post", array( - "Accept" => "application/json" - ), array( - "name" => "Mark", - "file" => Unirest::file(dirname(__FILE__) . "/test_upload.txt") - )); - $this->assertEqual(200, $response->code); - - $files = $response->body->files; - $this->assertEqual("This is a test", $files->file); - - $form = $response->body->form; - $this->assertEqual("Mark", $form->name); - } - - public function testUploadIfFilePartOfData() - { - $response = Unirest::post("http://httpbin.org/post", array( - "Accept" => "application/json" - ), array( - "name" => "Mark", - "files[owl.gif]" => Unirest::file(dirname(__FILE__) . "/test_upload.txt") - )); - $this->assertEqual(200, $response->code); - - //$files = $response->body->files; - //$this->assertEqual("This is a test", $files->file); - - $form = $response->body->form; - $this->assertEqual("Mark", $form->name); - } - - public function testPostMultidimensionalArray() - { - $response = Unirest::post("http://httpbin.org/post", array( - "Accept" => "application/json" - ), array( - 'key' => 'value', - 'items' => array( - 'item1', - 'item2' - ) - )); - - $this->assertEqual(200, $response->code); - - $form = $response->body->form; - $this->assertEqual("value", $form->key); - $this->assertEqual("item1", $form->{"items[0]"}); - $this->assertEqual("item2", $form->{"items[1]"}); - } - - public function testPut() - { - $response = Unirest::put("http://httpbin.org/put", array( - "Accept" => "application/json" - ), array( - "name" => "Mark", - "nick" => "thefosk" - )); - - $this->assertEqual(200, $response->code); - - $form = $response->body->form; - $this->assertEqual("Mark", $form->name); - $this->assertEqual("thefosk", $form->nick); - } - - public function testPatch() - { - $response = Unirest::patch("http://httpbin.org/patch", array( - "Accept" => "application/json" - ), array( - "name" => "Mark", - "nick" => "thefosk" - )); - - $this->assertEqual(200, $response->code); - - $form = $response->body->form; - $this->assertEqual("Mark", $form->name); - $this->assertEqual("thefosk", $form->nick); - } - - public function testDelete() - { - $response = Unirest::delete("http://httpbin.org/delete", array( - "Accept" => "application/json", - "Content-Type" => "application/x-www-form-urlencoded" - ), array( - "name" => "Mark", - "nick" => "thefosk" - )); - - $this->assertEqual(200, $response->code); - $data = $response->body->data; - $this->assertFalse(empty($data)); - } - - public function testTimeoutFail() - { - Unirest::timeout(1); - - $this->expectException(); - $response = Unirest::get("http://httpbin.org/delay/3"); - - Unirest::timeout(null); // Cleaning timeout for the other tests - } - - public function testTimeoutSuccess() - { - Unirest::timeout(3); - - $response = Unirest::get("http://httpbin.org/delay/1"); - $this->assertEqual(200, $response->code); - - Unirest::timeout(null); // Cleaning timeout for the other tests - } - - public function testDefaultHeader() - { - Unirest::defaultHeader("Hello", "custom"); - $response = Unirest::get("http://httpbin.org/get"); - - $this->assertEqual(200, $response->code); - $headers = $response->body->headers; - $properties = get_object_vars($headers); - $this->assertTrue(array_key_exists("Hello", $properties)); - $this->assertEqual("custom", $headers->Hello); - $response = Unirest::get("http://httpbin.org/get"); - - $this->assertEqual(200, $response->code); - $headers = $response->body->headers; - $properties = get_object_vars($headers); - $this->assertTrue(array_key_exists("Hello", $properties)); - $this->assertEqual("custom", $headers->Hello); - Unirest::clearDefaultHeaders(); - $response = Unirest::get("http://httpbin.org/get"); - - $this->assertEqual(200, $response->code); - $headers = $response->body->headers; - $properties = get_object_vars($headers); - $this->assertFalse(array_key_exists("Hello", $properties)); - } - - public function testGzip() - { - $response = Unirest::get("http://httpbin.org/gzip"); - $args = $response->body; - $this->assertEqual(true, $args->gzipped); - } - - public function testBasicAuthentication() - { - $response = Unirest::get("http://httpbin.org/get", null, null, "user", "password"); - $headers = $response->body->headers; - $this->assertEqual("Basic dXNlcjpwYXNzd29yZA==", $headers->Authorization); - } - - public function testCustomHeaders() - { - $response = Unirest::get('http://httpbin.org/get', array( - 'user-agent' => 'ciao', - )); - - $this->assertEqual(200, $response->code); - - $headers = $response->body->headers; - $this->assertEqual("ciao", $headers->{'User-Agent'}); - } - - public function testHttpBuildQueryWhenCurlFile() - { - $file = Unirest::file(dirname(__FILE__) . "/test_upload.txt"); - $body = array( - "to" => "mail@mailinator.com", - "from" => "mail@mailinator.com", - "file" => $file - ); - Unirest::http_build_query_for_curl($body, $postBody); - $this->assertEqual($postBody['file'], $file); - } -} diff --git a/tests/Unirest/FileTest.php b/tests/Unirest/FileTest.php new file mode 100644 index 0000000..b7316a3 --- /dev/null +++ b/tests/Unirest/FileTest.php @@ -0,0 +1,17 @@ +assertEquals($file, sprintf('@%s;filename=%s;type=', UPLOAD_FIXTURE, basename(UPLOAD_FIXTURE))); + } else { + $this->assertTrue($file instanceof \CURLFile); + } + } +} diff --git a/tests/Unirest/RequestTest.php b/tests/Unirest/RequestTest.php new file mode 100644 index 0000000..00a68aa --- /dev/null +++ b/tests/Unirest/RequestTest.php @@ -0,0 +1,385 @@ + 'mail@mailinator.com', + 'from' => 'mail@mailinator.com', + 'file' => $file + ); + + $result = Unirest\Request::buildHTTPCurlQuery($body); + $this->assertEquals($result['file'], $file); + } + + /** + * @expectedException Exception + */ + public function testTimeoutFail() + { + Unirest\Request::timeout(1); + + Unirest\Request::get('http://httpbin.org/delay/3'); + + Unirest\Request::timeout(null); // Cleaning timeout for the other tests + } + + public function testTimeoutSuccess() + { + Unirest\Request::timeout(3); + + $response = Unirest\Request::get('http://httpbin.org/delay/1'); + $this->assertEquals(200, $response->code); + + Unirest\Request::timeout(null); // Cleaning timeout for the other tests + } + + public function testDefaultHeader() + { + Unirest\Request::defaultHeader('Hello', 'custom'); + $response = Unirest\Request::get('http://httpbin.org/get'); + + $this->assertEquals(200, $response->code); + $headers = $response->body->headers; + $properties = get_object_vars($headers); + $this->assertTrue(array_key_exists('Hello', $properties)); + $this->assertEquals('custom', $headers->Hello); + $response = Unirest\Request::get('http://httpbin.org/get'); + + $this->assertEquals(200, $response->code); + $headers = $response->body->headers; + $properties = get_object_vars($headers); + $this->assertTrue(array_key_exists('Hello', $properties)); + $this->assertEquals('custom', $headers->Hello); + Unirest\Request::clearDefaultHeaders(); + $response = Unirest\Request::get('http://httpbin.org/get'); + + $this->assertEquals(200, $response->code); + $headers = $response->body->headers; + $properties = get_object_vars($headers); + $this->assertFalse(array_key_exists('Hello', $properties)); + } + + public function testGzip() + { + $response = Unirest\Request::get('http://httpbin.org/gzip'); + $args = $response->body; + $this->assertEquals(true, $args->gzipped); + } + + public function testBasicAuthentication() + { + $response = Unirest\Request::get('http://httpbin.org/get', array(), array(), 'user', 'password'); + $headers = $response->body->headers; + $this->assertEquals('Basic dXNlcjpwYXNzd29yZA==', $headers->Authorization); + } + + public function testCustomHeaders() + { + $response = Unirest\Request::get('http://httpbin.org/get', array( + 'user-agent' => 'ciao', + )); + + $this->assertEquals(200, $response->code); + + $headers = $response->body->headers; + $this->assertEquals('ciao', $headers->{'User-Agent'}); + } + + // GET + public function testGet() + { + $response = Unirest\Request::get('http://httpbin.org/get?name=Mark', array( + 'Accept' => 'application/json' + ), array( + 'nick' => 'thefosk' + )); + + $this->assertEquals(200, $response->code); + + $args = $response->body->args; + $this->assertEquals('Mark', $args->name); + $this->assertEquals('thefosk', $args->nick); + } + + public function testGetMultidimensionalArray() + { + $response = Unirest\Request::get('http://httpbin.org/get', array( + 'Accept' => 'application/json' + ), array( + 'key' => 'value', + 'items' => array( + 'item1', + 'item2' + ) + )); + + $this->assertEquals(200, $response->code); + + $args = $response->body->args; + + $this->assertEquals('value', $args->key); + $this->assertEquals('item1', $args->{'items[0]'}); + $this->assertEquals('item2', $args->{'items[1]'}); + } + + public function testGetWithDots() + { + $response = Unirest\Request::get('http://httpbin.org/get', array( + 'Accept' => 'application/json' + ), array( + 'user.name' => 'Mark', + 'nick' => 'thefosk' + )); + + $this->assertEquals(200, $response->code); + + $args = $response->body->args; + $this->assertEquals('Mark', $args->{'user.name'}); + $this->assertEquals('thefosk', $args->nick); + } + + public function testGetWithDotsAlt() + { + $response = Unirest\Request::get('http://httpbin.org/get', array( + 'Accept' => 'application/json' + ), array( + 'user.name' => 'Mark Bond', + 'nick' => 'thefosk' + )); + + $this->assertEquals(200, $response->code); + + $args = $response->body->args; + $this->assertEquals('Mark Bond', $args->{'user.name'}); + $this->assertEquals('thefosk', $args->nick); + } + + public function testGetWithEqualSign() + { + $response = Unirest\Request::get('http://httpbin.org/get', array( + 'Accept' => 'application/json' + ), array( + 'name' => 'Mark=Hello' + )); + + $this->assertEquals(200, $response->code); + + $args = $response->body->args; + $this->assertEquals('Mark=Hello', $args->name); + + $response = Unirest\Request::get('http://httpbin.org/get', array( + 'Accept' => 'application/json' + ), array( + 'name' => 'Mark=Hello=John' + )); + + $this->assertEquals(200, $response->code); + + $args = $response->body->args; + $this->assertEquals('Mark=Hello=John', $args->name); + } + + public function testGetArray() + { + $response = Unirest\Request::get('http://httpbin.org/get', array(), array( + 'name[0]' => 'Mark', + 'name[1]' => 'John' + )); + + $this->assertEquals(200, $response->code); + + $args = $response->body->args; + $this->assertEquals('Mark', $args->{'name[0]'}); + $this->assertEquals('John', $args->{'name[1]'}); + } + + // POST + public function testPost() + { + $response = Unirest\Request::post('http://httpbin.org/post', array( + 'Accept' => 'application/json' + ), array( + 'name' => 'Mark', + 'nick' => 'thefosk' + )); + + $this->assertEquals(200, $response->code); + + $form = $response->body->form; + $this->assertEquals('Mark', $form->name); + $this->assertEquals('thefosk', $form->nick); + } + + public function testPostWithEqualSign() + { + $response = Unirest\Request::post('http://httpbin.org/post', array( + 'Accept' => 'application/json' + ), array( + 'name' => 'Mark=Hello' + )); + + $this->assertEquals(200, $response->code); + + $form = $response->body->form; + $this->assertEquals('Mark=Hello', $form->name); + } + + public function testPostArray() + { + $response = Unirest\Request::post('http://httpbin.org/post', array( + 'Accept' => 'application/json' + ), array( + 'name[0]' => 'Mark', + 'name[1]' => 'John' + )); + + $this->assertEquals(200, $response->code); + + $form = $response->body->form; + + $this->assertEquals('Mark', $form->{'name[0]'}); + $this->assertEquals('John', $form->{'name[1]'}); + } + + public function testPostWithDots() + { + $response = Unirest\Request::post('http://httpbin.org/post', array( + 'Accept' => 'application/json' + ), array( + 'user.name' => 'Mark', + 'nick' => 'thefosk' + )); + + $this->assertEquals(200, $response->code); + + $form = $response->body->form; + $this->assertEquals('Mark', $form->{'user.name'}); + $this->assertEquals('thefosk', $form->nick); + } + + public function testRawPost() + { + $response = Unirest\Request::post('http://httpbin.org/post', array( + 'Accept' => 'application/json', + 'Content-Type' => 'application/json' + ), json_encode(array( + 'author' => 'Sam Sullivan' + ))); + + $this->assertEquals(200, $response->code); + + $json = $response->body->json; + + $this->assertEquals('Sam Sullivan', $json->author); + } + + public function testPostMultidimensionalArray() + { + $response = Unirest\Request::post('http://httpbin.org/post', array( + 'Accept' => 'application/json' + ), array( + 'key' => 'value', + 'items' => array( + 'item1', + 'item2' + ) + )); + + $this->assertEquals(200, $response->code); + + $form = $response->body->form; + $this->assertEquals('value', $form->key); + $this->assertEquals('item1', $form->{'items[0]'}); + $this->assertEquals('item2', $form->{'items[1]'}); + } + + // PUT + public function testPut() + { + $response = Unirest\Request::put('http://httpbin.org/put', array( + 'Accept' => 'application/json' + ), array( + 'name' => 'Mark', + 'nick' => 'thefosk' + )); + + $this->assertEquals(200, $response->code); + + $form = $response->body->form; + $this->assertEquals('Mark', $form->name); + $this->assertEquals('thefosk', $form->nick); + } + + // PATCH + public function testPatch() + { + $response = Unirest\Request::patch('http://httpbin.org/patch', array( + 'Accept' => 'application/json' + ), array( + 'name' => 'Mark', + 'nick' => 'thefosk' + )); + + $this->assertEquals(200, $response->code); + + $form = $response->body->form; + $this->assertEquals('Mark', $form->name); + $this->assertEquals('thefosk', $form->nick); + } + + // DELETE + public function testDelete() + { + $response = Unirest\Request::delete('http://httpbin.org/delete', array( + 'Accept' => 'application/json', + 'Content-Type' => 'application/x-www-form-urlencoded' + ), array( + 'name' => 'Mark', + 'nick' => 'thefosk' + )); + + $this->assertEquals(200, $response->code); + $data = $response->body->data; + $this->assertTrue(empty($data)); + } + + // Upload + public function testUpload() + { + $response = Unirest\Request::post('http://httpbin.org/post', array( + 'Accept' => 'application/json' + ), array( + 'name' => 'Mark', + 'file' => Unirest\File::add(UPLOAD_FIXTURE) + )); + $this->assertEquals(200, $response->code); + + $files = $response->body->files; + $this->assertEquals('This is a test', $files->file); + + $form = $response->body->form; + $this->assertEquals('Mark', $form->name); + } + + public function testUploadIfFilePartOfData() + { + $response = Unirest\Request::post('http://httpbin.org/post', array( + 'Accept' => 'application/json' + ), array( + 'name' => 'Mark', + 'files[owl.gif]' => Unirest\File::add(UPLOAD_FIXTURE) + )); + $this->assertEquals(200, $response->code); + + //$files = $response->body->files; + //$this->assertEquals('This is a test', $files->file); + + $form = $response->body->form; + $this->assertEquals('Mark', $form->name); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..1753d82 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,5 @@ +