├── .editorconfig ├── .styleci.yml ├── LICENSE.md ├── README.md ├── composer.json └── src ├── Events ├── RequestEvent.php ├── RequestExceptionEvent.php └── ResponseEvent.php ├── Exception ├── BaseException.php ├── LushException.php └── LushRequestException.php ├── Lush.php ├── LushFacade.php ├── Request ├── Adapter │ ├── AdapterInterface.php │ ├── Curl.php │ └── CurlMock.php ├── CurlRequest.php ├── LushRequest.php ├── RequestGetters.php └── RequestOptions.php └── Response ├── LushResponse.php └── ResponseGetters.php /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: laravel 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) Appstract 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lush Http 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/appstract/lush-http.svg?style=flat-square)](https://packagist.org/packages/appstract/lush-http) 4 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 5 | [![Build Status](https://img.shields.io/travis/appstract/lush-http/master.svg?style=flat-square)](https://travis-ci.org/appstract/lush-http) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/appstract/lush-http.svg?style=flat-square)](https://packagist.org/packages/appstract/lush-http) 7 | 8 | ## Smart Http Client for PHP. 9 | 10 | Lush is a small Http client that focuses on the most basic use cases. It also tries to format the responses to objects, so you don't have to. 11 | This makes Lush great for API requests. 12 | 13 | Lush can be installed in any PHP application through composer, but has some extras when used in combination with Laravel. 14 | 15 | ### Wip 16 | 17 | This package is still in development, you are free to try it, without any warranty. 18 | 19 | Todo 20 | - Support cookies 21 | - Docs 22 | 23 | ## Requirements 24 | - PHP 5.6+ 25 | - php_curl 26 | 27 | ## Installation 28 | 29 | You can install the package via composer: 30 | 31 | ``` bash 32 | composer require appstract/lush-http 33 | ``` 34 | 35 | ## Usage 36 | The most basic usage: 37 | 38 | ``` php 39 | // Create a new instance 40 | $lush = new Lush(); 41 | 42 | // Make a requests 43 | $response = $lush->url('http://example.com', ['id' => 3]) 44 | ->headers(['X-some-header' => 'some-value']) 45 | ->get(); // Method (get, post, put, etc.) 46 | 47 | // Response returns JSON or XML? 48 | // then you can directly access it's properties 49 | echo $response->name; 50 | ``` 51 | 52 | Link to the docs will be added soon! 53 | 54 | ## Contributing 55 | 56 | Contributions are welcome, [thanks to y'all](https://github.com/appstract/lush-http/graphs/contributors) :) 57 | 58 | ## About Appstract 59 | 60 | Appstract is a small team from The Netherlands. We create (open source) tools for webdevelopment and write about related subjects on [Medium](https://medium.com/appstract). You can [follow us on Twitter](https://twitter.com/teamappstract), [buy us a beer](https://www.paypal.me/teamappstract/10) or [support us on Patreon](https://www.patreon.com/appstract). 61 | 62 | ## License 63 | 64 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 65 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "appstract/lush-http", 3 | "description": "Smart Http Client for PHP.", 4 | "keywords": [ 5 | "php", 6 | "appstract", 7 | "lush-http", 8 | "lush", 9 | "curl", 10 | "http", 11 | "client" 12 | ], 13 | "homepage": "https://github.com/appstract/lush-http", 14 | "license": "MIT", 15 | "authors": [ 16 | { 17 | "name": "Olav van Schie", 18 | "email": "hello@appstract.team", 19 | "homepage": "https://appstract.team", 20 | "role": "Developer" 21 | } 22 | ], 23 | "require": { 24 | "php": ">=5.6", 25 | "illuminate/support": ">=5.4" 26 | }, 27 | "require-dev": { 28 | "phpunit/phpunit": "^5.7" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "Appstract\\LushHttp\\": "src" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "Appstract\\LushHttp\\Test\\": "tests" 38 | } 39 | }, 40 | "scripts": { 41 | "test": "vendor/bin/phpunit" 42 | }, 43 | "config": { 44 | "sort-packages": true 45 | }, 46 | "extra": { 47 | "laravel": { 48 | "aliases": { 49 | "Lush": "Appstract\\LushHttp\\LushFacade" 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Events/RequestEvent.php: -------------------------------------------------------------------------------- 1 | request = $request; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Events/RequestExceptionEvent.php: -------------------------------------------------------------------------------- 1 | exception = $exception; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Events/ResponseEvent.php: -------------------------------------------------------------------------------- 1 | response = $response; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Exception/BaseException.php: -------------------------------------------------------------------------------- 1 | request = $request; 24 | $this->response = $error['response']; 25 | $this->message = $error['message']; 26 | 27 | if (! isset($error['message']) || empty($error['message'])) { 28 | $this->message = json_encode($this->getContent()); 29 | } 30 | 31 | if (function_exists('event')) { 32 | event(new RequestExceptionEvent($this)); 33 | } 34 | 35 | parent::__construct($this->message, $error['code']); 36 | } 37 | 38 | /** 39 | * @return string 40 | */ 41 | public function getRequest() 42 | { 43 | return $this->request; 44 | } 45 | 46 | /** 47 | * @return string 48 | */ 49 | public function getResponse() 50 | { 51 | return $this->response; 52 | } 53 | 54 | /** 55 | * @return string 56 | */ 57 | public function getContent() 58 | { 59 | return $this->response->getResult(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Lush.php: -------------------------------------------------------------------------------- 1 | baseload = [ 35 | 'base_url' => trim($baseUrl), 36 | 'options' => $options, 37 | 'headers' => $headers, 38 | ]; 39 | } 40 | 41 | /** 42 | * Set the url with parameters. 43 | * 44 | * @param $url 45 | * @param array|object $parameters 46 | * 47 | * @return $this 48 | */ 49 | public function url($url, $parameters = []) 50 | { 51 | $this->url = $url; 52 | $this->parameters = $parameters; 53 | 54 | return $this; 55 | } 56 | 57 | /** 58 | * Set headers. 59 | * 60 | * @param array $headers 61 | * 62 | * @return $this 63 | */ 64 | public function headers(array $headers) 65 | { 66 | $this->headers = $headers; 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * Set options. 73 | * 74 | * @param array $options 75 | * 76 | * @return $this 77 | */ 78 | public function options(array $options) 79 | { 80 | $this->options = $options; 81 | 82 | return $this; 83 | } 84 | 85 | /** 86 | * Reset all request options. 87 | * 88 | * @return $this 89 | */ 90 | public function reset() 91 | { 92 | $this->url = ''; 93 | $this->parameters = []; 94 | $this->headers = []; 95 | $this->options = []; 96 | 97 | return $this; 98 | } 99 | 100 | /** 101 | * Post as Json. 102 | * 103 | * @return $this 104 | */ 105 | public function asJson() 106 | { 107 | $this->addOption('body_format', 'json'); 108 | $this->addHeader('content_type', 'application/json'); 109 | 110 | return $this; 111 | } 112 | 113 | /** 114 | * Post as form params. 115 | * 116 | * @return $this 117 | */ 118 | public function asFormParams() 119 | { 120 | $this->addHeader('content_type', 'application/x-www-form-urlencoded'); 121 | 122 | return $this; 123 | } 124 | 125 | /** 126 | * Create a request. 127 | * 128 | * @param $method 129 | * 130 | * @return \Appstract\LushHttp\Response\LushResponse 131 | */ 132 | public function request($method) 133 | { 134 | $request = new LushRequest([ 135 | 'method' => strtoupper($method), 136 | 'base_url' => $this->baseload['base_url'], 137 | 'url' => trim($this->url), 138 | 'parameters' => $this->parameters, 139 | 'headers' => array_merge($this->baseload['headers'], $this->headers), 140 | 'options' => array_merge($this->baseload['options'], $this->options), 141 | ]); 142 | 143 | return $request->send(); 144 | } 145 | 146 | /** 147 | * Magic shorthand method. 148 | * 149 | * @param string $method 150 | * @param array $arguments 151 | * 152 | * @return \Appstract\LushHttp\Response\LushResponse 153 | */ 154 | public function __call($method, $arguments) 155 | { 156 | $scope = $this; 157 | 158 | if (isset($arguments[0])) { 159 | $scope = $this->url($arguments[0], isset($arguments[1]) ? $arguments[1] : []); 160 | } 161 | 162 | return $scope->request($method); 163 | } 164 | 165 | /** 166 | * Add header. 167 | * 168 | * @param $name 169 | * @param $value 170 | */ 171 | protected function addHeader($name, $value) 172 | { 173 | $this->baseload['headers'] = array_merge($this->baseload['headers'], [$name => $value]); 174 | } 175 | 176 | /** 177 | * Add option. 178 | * 179 | * @param $name 180 | * @param $value 181 | */ 182 | protected function addOption($name, $value) 183 | { 184 | $this->baseload['options'] = array_merge($this->baseload['options'], [$name => $value]); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/LushFacade.php: -------------------------------------------------------------------------------- 1 | ch = curl_init($url); 22 | } 23 | 24 | /** 25 | * Set options array. 26 | * 27 | * @param array $curlOptions 28 | * @param array $lushOptions 29 | */ 30 | public function setOptions(array $curlOptions, array $lushOptions = null) 31 | { 32 | curl_setopt_array($this->ch, $curlOptions); 33 | } 34 | 35 | /** 36 | * Execute the request. 37 | * 38 | * @return mixed 39 | */ 40 | public function execute() 41 | { 42 | return curl_exec($this->ch); 43 | } 44 | 45 | /** 46 | * Get request info (headers). 47 | * 48 | * @return mixed 49 | */ 50 | public function getInfo() 51 | { 52 | return curl_getinfo($this->ch); 53 | } 54 | 55 | /** 56 | * Get curl error code. 57 | * 58 | * @return int 59 | */ 60 | public function getErrorCode() 61 | { 62 | return curl_errno($this->ch); 63 | } 64 | 65 | /** 66 | * Get curl error message. 67 | * 68 | * @return string 69 | */ 70 | public function getErrorMessage() 71 | { 72 | return curl_error($this->ch); 73 | } 74 | 75 | /** 76 | * Close the connection. 77 | */ 78 | public function close() 79 | { 80 | curl_close($this->ch); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Request/Adapter/CurlMock.php: -------------------------------------------------------------------------------- 1 | 'text/html; charset=UTF-8', 37 | 'header_size' => 611, 38 | 'request_size' => 235, 39 | 'ssl_verify_result' => 0, 40 | 'redirect_count' => 0, 41 | 'size_upload' => 0.0, 42 | 'size_download' => 219.0, 43 | 'speed_download' => 11810.0, 44 | 'speed_upload' => 0.0, 45 | 'download_content_length' => -1.0, 46 | 'upload_content_length' => -1.0, 47 | 'starttransfer_time' => 0.018515, 48 | 'redirect_time' => 0.0, 49 | 'redirect_url' => '', 50 | 'primary_ip' => '127.0.0.1', 51 | 'certinfo' => [], 52 | 'primary_port' => 80, 53 | 'local_ip' => '127.0.0.1', 54 | 'local_port' => 51148, 55 | ]; 56 | 57 | /** 58 | * Init curl object with url. 59 | * 60 | * @param $url 61 | */ 62 | public function init($url) 63 | { 64 | $this->ch = $url; 65 | } 66 | 67 | /** 68 | * Set options array. 69 | * 70 | * @param array $curlOptions 71 | * @param array $lushOptions 72 | */ 73 | public function setOptions(array $curlOptions, array $lushOptions = null) 74 | { 75 | $this->curlOptions = $curlOptions; 76 | $this->lushOptions = $lushOptions; 77 | } 78 | 79 | /** 80 | * Execute the request. 81 | * 82 | * @return mixed 83 | * @throws Exception 84 | */ 85 | public function execute() 86 | { 87 | if (! $this->ch) { 88 | throw new Exception('Curl request not initiated'); 89 | } 90 | 91 | $statusCode = (int) isset($this->lushOptions['return_status']) ? $this->lushOptions['return_status'] : 200; 92 | $contentType = isset($this->lushOptions['return_content_type']) ? $this->lushOptions['return_content_type'] : 'text'; 93 | 94 | $this->headers['url'] = $this->ch; 95 | $this->headers['http_code'] = $statusCode; 96 | 97 | $this->executed = true; 98 | 99 | return $this->createResponse($statusCode, $contentType); 100 | } 101 | 102 | /** 103 | * Get request info (headers). 104 | * 105 | * @return mixed 106 | * @throws Exception 107 | */ 108 | public function getInfo() 109 | { 110 | if (! $this->executed) { 111 | throw new Exception('Curl request not executed'); 112 | } 113 | 114 | return $this->headers; 115 | } 116 | 117 | /** 118 | * Get curl error code. 119 | * 120 | * @return int 121 | * @throws Exception 122 | */ 123 | public function getErrorCode() 124 | { 125 | if (! $this->executed) { 126 | throw new Exception('Curl request not executed'); 127 | } 128 | 129 | return 0; 130 | } 131 | 132 | /** 133 | * Get curl error message. 134 | * 135 | * @return string 136 | * @throws Exception 137 | */ 138 | public function getErrorMessage() 139 | { 140 | if (! $this->executed) { 141 | throw new Exception('Curl request not executed'); 142 | } 143 | 144 | return ''; 145 | } 146 | 147 | /** 148 | * Close the connection. 149 | */ 150 | public function close() 151 | { 152 | $this->ch = null; 153 | } 154 | 155 | /** 156 | * Create a example response based on statuscode. 157 | * 158 | * @param $statusCode 159 | * @param $contentType 160 | * 161 | * @return string 162 | */ 163 | protected function createResponse($statusCode, $contentType) 164 | { 165 | switch ($statusCode) { 166 | case 200: 167 | case 201: 168 | return $this->createContent($contentType); 169 | default: 170 | // fail on error 171 | if ($this->curlOptions[45]) { 172 | throw new LushRequestException($this, ['message' => sprintf('%d - Mocked server error', $statusCode), 'code' => $statusCode, 'response' => 'false']); 173 | } 174 | 175 | return json_encode(['url' => $this->ch, 'status' => sprintf('Error: %d', $statusCode)]); 176 | } 177 | } 178 | 179 | /** 180 | * Create sample content for response. 181 | * 182 | * @param $type 183 | * 184 | * @return string 185 | */ 186 | protected function createContent($type) 187 | { 188 | if ($type == 'json') { 189 | $this->headers['content_type'] = 'application/json; charset=UTF-8'; 190 | 191 | return json_encode(['url' => $this->ch, 'status' => 'ok']); 192 | } elseif ($type == 'xml') { 193 | $this->headers['content_type'] = 'text/xml; charset=UTF-8'; 194 | 195 | return ''.$this->ch.'ok'; 196 | } 197 | 198 | return 'ok'; 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/Request/CurlRequest.php: -------------------------------------------------------------------------------- 1 | adapter = LUSH_ADAPTER; 45 | } 46 | 47 | $this->client = new $this->adapter(); 48 | } 49 | 50 | /** 51 | * Merge default Curl options with given options. 52 | */ 53 | protected function mergeCurlOptions() 54 | { 55 | $this->curlOptions = array_replace(RequestOptions::$defaultCurlOptions, $this->curlOptions); 56 | } 57 | 58 | /** 59 | * Sends the Curl requests and returns result array. 60 | * 61 | * @return \Appstract\LushHttp\Response\LushResponse 62 | */ 63 | protected function makeRequest() 64 | { 65 | // init Curl 66 | $this->client->init($this->payload['url']); 67 | $this->client->setOptions($this->curlOptions, $this->options); 68 | 69 | // get results 70 | $content = $this->client->execute(); 71 | $headers = $this->client->getInfo(); 72 | 73 | $response = new LushResponse(compact('content', 'headers'), $this); 74 | 75 | // handle errors 76 | if ($content === false || substr($headers['http_code'], 0, 1) != 2) { 77 | $error = [ 78 | 'code' => $this->client->getErrorCode(), 79 | 'message' => $this->client->getErrorMessage(), 80 | 'response' => $response, 81 | ]; 82 | 83 | $this->client->close(); 84 | 85 | throw new LushRequestException($this, $error); 86 | } 87 | 88 | $this->client->close(); 89 | 90 | return $response; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Request/LushRequest.php: -------------------------------------------------------------------------------- 1 | payload = $payload; 31 | $this->method = $payload['method']; 32 | 33 | $this->prepareRequest(); 34 | } 35 | 36 | /** 37 | * Prepare the request. 38 | */ 39 | protected function prepareRequest() 40 | { 41 | $this->formatUrl(); 42 | $this->validateInput(); 43 | $this->addHeaders(); 44 | $this->addRequestBody(); 45 | $this->initOptions(); 46 | } 47 | 48 | /** 49 | * Format url. 50 | */ 51 | protected function formatUrl() 52 | { 53 | // append trailing slash to the 54 | // baseUrl if it is missing 55 | if (! empty($this->payload['base_url']) && substr($this->payload['base_url'], -1) !== '/') { 56 | $this->payload['base_url'] = $this->payload['base_url'].'/'; 57 | } 58 | 59 | // append the base url 60 | $this->payload['url'] = trim($this->payload['base_url'].$this->payload['url']); 61 | } 62 | 63 | /** 64 | * Validate given options. 65 | */ 66 | protected function validateInput() 67 | { 68 | if (! filter_var($this->payload['url'], FILTER_VALIDATE_URL)) { 69 | throw new LushException('URL is invalid', 100); 70 | } 71 | 72 | if (! in_array($this->method, $this->allowedMethods)) { 73 | throw new LushException(sprintf("Method '%s' is not supported", $this->method), 101); 74 | } 75 | } 76 | 77 | /** 78 | * Add request headers. 79 | */ 80 | protected function addHeaders() 81 | { 82 | $userHeaders = array_map(function ($key, $value) { 83 | // format header like this 'x-header: value' 84 | return sprintf('%s: %s', $key, $value); 85 | }, array_keys($this->payload['headers']), $this->payload['headers']); 86 | 87 | $headers = array_merge($this->defaultHeaders, $userHeaders); 88 | 89 | $this->addCurlOption(CURLOPT_HTTPHEADER, $headers); 90 | } 91 | 92 | /** 93 | * Add request body. 94 | */ 95 | protected function addRequestBody() 96 | { 97 | if (! empty($this->payload['parameters'])) { 98 | if (in_array($this->method, ['DELETE', 'PATCH', 'POST', 'PUT'])) { 99 | $this->addCurlOption(CURLOPT_POSTFIELDS, $this->formattedRequestBody()); 100 | } elseif (is_array($this->payload['parameters'])) { 101 | // append parameters in the url 102 | $this->payload['url'] = sprintf('%s?%s', $this->payload['url'], $this->formattedRequestBody()); 103 | } 104 | } 105 | } 106 | 107 | /** 108 | * Get formatted request body based on body_format. 109 | * 110 | * @return null|string 111 | */ 112 | protected function formattedRequestBody() 113 | { 114 | if (isset($this->payload['options']['body_format']) && $this->payload['options']['body_format'] == 'json') { 115 | return json_encode($this->payload['parameters']); 116 | } 117 | 118 | return http_build_query($this->payload['parameters']); 119 | } 120 | 121 | /** 122 | * Add Lush option. 123 | * 124 | * @param string $key 125 | * @param mixed $value 126 | */ 127 | protected function addOption($key, $value) 128 | { 129 | $this->options[$key] = $value; 130 | } 131 | 132 | /** 133 | * Add Curl option. 134 | * 135 | * @param string $key 136 | * @param mixed $value 137 | */ 138 | protected function addCurlOption($key, $value) 139 | { 140 | $this->curlOptions[$key] = $value; 141 | } 142 | 143 | /** 144 | * Set request options. 145 | */ 146 | protected function initOptions() 147 | { 148 | // Set method 149 | if ($this->method == 'POST') { 150 | $this->addCurlOption(CURLOPT_POST, true); 151 | } elseif (in_array($this->method, ['DELETE', 'HEAD', 'PATCH', 'PUT'])) { 152 | if ($this->method == 'HEAD') { 153 | $this->addCurlOption(CURLOPT_NOBODY, true); 154 | } 155 | 156 | $this->addCurlOption(CURLOPT_CUSTOMREQUEST, $this->method); 157 | } 158 | 159 | // Set allowed protocols 160 | if (defined('CURLOPT_PROTOCOLS')) { 161 | $this->addCurlOption(CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); 162 | } 163 | 164 | // Handle options from payload 165 | if (! empty($this->payload['options']) && is_array($this->payload['options'])) { 166 | // Add authentication 167 | $this->handleAuthentication(); 168 | 169 | // Add user options 170 | $this->handleUserOptions(); 171 | } 172 | 173 | $this->mergeCurlOptions(); 174 | } 175 | 176 | /** 177 | * Handle authentication. 178 | */ 179 | protected function handleAuthentication() 180 | { 181 | if (isset($this->payload['options']['username'], $this->payload['options']['password'])) { 182 | $this->addCurlOption(CURLOPT_USERPWD, sprintf('%s:%s', $this->payload['options']['username'], $this->payload['options']['password'])); 183 | } 184 | } 185 | 186 | /** 187 | * Handle user options. 188 | */ 189 | protected function handleUserOptions() 190 | { 191 | foreach ($this->payload['options'] as $option => $value) { 192 | $resolvedOption = RequestOptions::resolve($option); 193 | 194 | if ($resolvedOption['type'] == 'curl_option') { 195 | $this->addCurlOption($resolvedOption['option'], $value); 196 | } else { 197 | $this->addOption($option, $value); 198 | } 199 | } 200 | } 201 | 202 | /** 203 | * Send the Curl request. 204 | * 205 | * @return \Appstract\LushHttp\Response\LushResponse 206 | */ 207 | public function send() 208 | { 209 | if (function_exists('event')) { 210 | event(new RequestEvent($this)); 211 | } 212 | 213 | return $this->makeRequest(); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/Request/RequestGetters.php: -------------------------------------------------------------------------------- 1 | payload; 15 | } 16 | 17 | /** 18 | * Get the URL. 19 | * 20 | * @return mixed|string 21 | */ 22 | public function getUrl() 23 | { 24 | return isset($this->payload['url']) ? $this->payload['url'] : null; 25 | } 26 | 27 | /** 28 | * Get all parameters. 29 | * 30 | * @return array|mixed 31 | */ 32 | public function getParameters() 33 | { 34 | return isset($this->payload['parameters']) ? $this->payload['parameters'] : []; 35 | } 36 | 37 | /** 38 | * Get a specific parameter. 39 | * 40 | * @param $parameter 41 | * 42 | * @return mixed 43 | */ 44 | public function getParameter($parameter) 45 | { 46 | return isset($this->getParameters()[$parameter]) ? $this->getParameters()[$parameter] : null; 47 | } 48 | 49 | /** 50 | * Get all options. 51 | * 52 | * @return array|mixed 53 | */ 54 | public function getOptions() 55 | { 56 | return isset($this->payload['options']) ? $this->payload['options'] : []; 57 | } 58 | 59 | /** 60 | * Get a specific option. 61 | * 62 | * @param $option 63 | * 64 | * @return mixed 65 | */ 66 | public function getOption($option) 67 | { 68 | return isset($this->getOptions()[$option]) ? $this->getOptions()[$option] : null; 69 | } 70 | 71 | /** 72 | * Get all headers. 73 | * 74 | * @return array|mixed 75 | */ 76 | public function getHeaders() 77 | { 78 | return isset($this->payload['headers']) ? $this->payload['headers'] : []; 79 | } 80 | 81 | /** 82 | * Get a specific header. 83 | * 84 | * @param $header 85 | * 86 | * @return mixed 87 | */ 88 | public function getHeader($header) 89 | { 90 | return isset($this->getHeaders()[$header]) ? $this->getHeaders()[$header] : null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Request/RequestOptions.php: -------------------------------------------------------------------------------- 1 | CURLOPT_USERAGENT, // custom user agent 16 | 'ua' => CURLOPT_USERAGENT, // alias for custom user agent 17 | 'timeout' => CURLOPT_TIMEOUT, // timeout 18 | 'connect_timeout' => CURLOPT_CONNECTTIMEOUT, // timeout for connection 19 | 'encoding' => CURLOPT_ENCODING, // custom encoding 20 | 'follow_redirects' => CURLOPT_FOLLOWLOCATION, // follow redirects 21 | 'fail_on_error' => CURLOPT_FAILONERROR, // throw exception if return code is not a success code 22 | 'verify_ssl' => CURLOPT_SSL_VERIFYPEER, // verify ssl 23 | 'verify_host' => CURLOPT_SSL_VERIFYHOST, // verify host domain 24 | 'dns_cache' => CURLOPT_DNS_USE_GLOBAL_CACHE, // Use DNS Cache 25 | 'dns_lifetime' => CURLOPT_DNS_CACHE_TIMEOUT, // DNS lifetime in seconds 26 | ]; 27 | 28 | /** 29 | * Lush options. 30 | * 31 | * @var array 32 | */ 33 | public static $lushOptions = [ 34 | 'auto_format', // automatic format response 35 | 'username', // username for authentication 36 | 'password', // password for authentication 37 | 38 | 'return_status', // (internal) used for testing return status 39 | 'return_content_type', // (internal) used for testing content types 40 | 'body_format', // (internal) used for body formatting 41 | ]; 42 | 43 | /** 44 | * Curl Defaults (internal). 45 | * 46 | * @var array 47 | */ 48 | public static $defaultCurlOptions = [ 49 | CURLOPT_RETURNTRANSFER => true, // return web page 50 | CURLOPT_HEADER => false, // return headers 51 | CURLOPT_FOLLOWLOCATION => true, // follow redirects 52 | CURLOPT_ENCODING => '', // handle compressed 53 | CURLOPT_CONNECTTIMEOUT => 60, // time-out on connect 54 | CURLOPT_TIMEOUT => 300, // time-out on response 55 | CURLOPT_AUTOREFERER => true, 56 | CURLOPT_FAILONERROR => true, 57 | CURLOPT_DNS_CACHE_TIMEOUT => 120, // DNS lifetime in seconds 58 | CURLOPT_USERAGENT => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Lush Http Client', 59 | //CURLOPT_COOKIEJAR => storage_path('app/lushcookie.txt'), 60 | //CURLOPT_COOKIEFILE => storage_path('app/lushcookie.txt'), 61 | ]; 62 | 63 | /** 64 | * @param string $option 65 | * 66 | * @return mixed 67 | */ 68 | public static function resolve($option) 69 | { 70 | if (isset(self::$curlOptions[$option])) { 71 | return [ 72 | 'type' => 'curl_option', 73 | 'option' => self::$curlOptions[$option], 74 | ]; 75 | } elseif (in_array($option, self::$lushOptions)) { 76 | return [ 77 | 'type' => 'lush_option', 78 | 'option' => $option, 79 | ]; 80 | } 81 | 82 | throw new LushException(sprintf("Invalid option '%s'", $option)); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Response/LushResponse.php: -------------------------------------------------------------------------------- 1 | request = $request; 36 | $this->headers = $response['headers']; 37 | $this->content = $response['content']; 38 | 39 | if (isset($this->request->options['auto_format'])) { 40 | $this->autoFormat = $this->request->options['auto_format']; 41 | } 42 | 43 | if ($this->autoFormat) { 44 | $this->object = $this->formatContent($this->content); 45 | } 46 | 47 | if (function_exists('event')) { 48 | event(new ResponseEvent($this)); 49 | } 50 | } 51 | 52 | /** 53 | * Check if content is json. 54 | * 55 | * @return null 56 | */ 57 | public function isJson() 58 | { 59 | if (isset($this->isJson)) { 60 | return $this->isJson; 61 | } 62 | 63 | // check based on content header 64 | if (strpos($this->getHeader('content_type'), 'application/json') !== false) { 65 | $this->isJson = true; 66 | } else { 67 | // check based on content 68 | json_decode($this->content); 69 | $this->isJson = (json_last_error() == JSON_ERROR_NONE); 70 | } 71 | 72 | return $this->isJson; 73 | } 74 | 75 | /** 76 | * @return bool 77 | */ 78 | public function isXml() 79 | { 80 | if (isset($this->isXml)) { 81 | return $this->isXml; 82 | } 83 | 84 | if (strpos($this->getHeader('content_type'), 'text/xml') !== false) { 85 | $this->isXml = true; 86 | } else { 87 | $this->isXml = false; 88 | } 89 | 90 | return $this->isXml; 91 | } 92 | 93 | /** 94 | * format content. 95 | * 96 | * @param $content 97 | * 98 | * @return mixed 99 | */ 100 | protected function formatContent($content) 101 | { 102 | if ($this->request->method == 'HEAD') { 103 | return (object) $this->headers; 104 | } 105 | 106 | if ($this->isXml()) { 107 | return json_decode($this->parseXml($content)); 108 | } 109 | 110 | if ($this->isJson()) { 111 | return json_decode($content); 112 | } 113 | } 114 | 115 | /** 116 | * Parse xml to array. 117 | * 118 | * @param $xml 119 | * 120 | * @return mixed 121 | */ 122 | protected function parseXml($xml) 123 | { 124 | return json_encode( 125 | simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA) 126 | ); 127 | } 128 | 129 | /** 130 | * Magic getter for content properties. 131 | * 132 | * @param $property 133 | * 134 | * @return mixed 135 | */ 136 | public function &__get($property) 137 | { 138 | $return = null; 139 | 140 | // check if the property is present in the content object 141 | if (isset($this->object->{ $property })) { 142 | $return = $this->object->{ $property }; 143 | } 144 | 145 | return $return; 146 | } 147 | 148 | /** 149 | * Proxy function calls to the collection. 150 | * 151 | * @param $method 152 | * @param array $arguments 153 | * 154 | * @return mixed 155 | */ 156 | public function __call($method, $arguments) 157 | { 158 | return call_user_func_array([$this->getCollection(), $method], $arguments); 159 | } 160 | 161 | /** 162 | * @return array 163 | */ 164 | public function jsonSerialize() 165 | { 166 | return [ 167 | 'request' => $this->getRequest(), 168 | 'content' => $this->getContent(), 169 | 'object' => $this->getObject(), 170 | 'headers' => $this->getHeaders(), 171 | 'is_json' => $this->isJson(), 172 | 'is_xml' => $this->isXml(), 173 | ]; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/Response/ResponseGetters.php: -------------------------------------------------------------------------------- 1 | autoFormat && ! empty($this->object)) { 17 | return $this->object; 18 | } 19 | 20 | return $this->content; 21 | } 22 | 23 | /** 24 | * Get the content of the result. 25 | * 26 | * @return mixed 27 | */ 28 | public function getContent() 29 | { 30 | return $this->content; 31 | } 32 | 33 | /** 34 | * Content as object. 35 | * 36 | * @return mixed 37 | */ 38 | public function getObject() 39 | { 40 | return $this->object; 41 | } 42 | 43 | /** 44 | * Content as Collection. 45 | * 46 | * @return Collection 47 | */ 48 | public function getCollection() 49 | { 50 | return new Collection($this->object); 51 | } 52 | 53 | /** 54 | * Get the headers. 55 | * 56 | * @return mixed 57 | */ 58 | public function getHeaders() 59 | { 60 | return $this->headers; 61 | } 62 | 63 | /** 64 | * Get a specific header. 65 | * 66 | * @param $header 67 | * 68 | * @return mixed 69 | */ 70 | public function getHeader($header) 71 | { 72 | return isset($this->headers[$header]) ? $this->headers[$header] : null; 73 | } 74 | 75 | /** 76 | * Get the status code. 77 | * 78 | * @return string 79 | */ 80 | public function getStatusCode() 81 | { 82 | return $this->getHeader('http_code'); 83 | } 84 | 85 | /** 86 | * Get the content type. 87 | * 88 | * @return string 89 | */ 90 | public function getContentType() 91 | { 92 | return $this->getHeader('content_type'); 93 | } 94 | 95 | /** 96 | * Get the original request. 97 | * 98 | * @return \Appstract\LushHttp\Request\LushRequest 99 | */ 100 | public function getRequest() 101 | { 102 | return $this->request; 103 | } 104 | } 105 | --------------------------------------------------------------------------------