PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/guzzlehttp/guzzle/src/Client.php

https://gitlab.com/aleritty/yaitb
PHP | 397 lines | 251 code | 47 blank | 99 comment | 38 complexity | 216e1946f42d3ba7d3fe7f05db326690 MD5 | raw file
  1. <?php
  2. namespace GuzzleHttp;
  3. use GuzzleHttp\Cookie\CookieJar;
  4. use GuzzleHttp\Promise;
  5. use GuzzleHttp\Psr7;
  6. use Psr\Http\Message\UriInterface;
  7. use Psr\Http\Message\RequestInterface;
  8. use Psr\Http\Message\ResponseInterface;
  9. /**
  10. * @method ResponseInterface get($uri, array $options = [])
  11. * @method ResponseInterface head($uri, array $options = [])
  12. * @method ResponseInterface put($uri, array $options = [])
  13. * @method ResponseInterface post($uri, array $options = [])
  14. * @method ResponseInterface patch($uri, array $options = [])
  15. * @method ResponseInterface delete($uri, array $options = [])
  16. * @method Promise\PromiseInterface getAsync($uri, array $options = [])
  17. * @method Promise\PromiseInterface headAsync($uri, array $options = [])
  18. * @method Promise\PromiseInterface putAsync($uri, array $options = [])
  19. * @method Promise\PromiseInterface postAsync($uri, array $options = [])
  20. * @method Promise\PromiseInterface patchAsync($uri, array $options = [])
  21. * @method Promise\PromiseInterface deleteAsync($uri, array $options = [])
  22. */
  23. class Client implements ClientInterface
  24. {
  25. /** @var array Default request options */
  26. private $config;
  27. /**
  28. * Clients accept an array of constructor parameters.
  29. *
  30. * Here's an example of creating a client using a base_uri and an array of
  31. * default request options to apply to each request:
  32. *
  33. * $client = new Client([
  34. * 'base_uri' => 'http://www.foo.com/1.0/',
  35. * 'timeout' => 0,
  36. * 'allow_redirects' => false,
  37. * 'proxy' => '192.168.16.1:10'
  38. * ]);
  39. *
  40. * Client configuration settings include the following options:
  41. *
  42. * - handler: (callable) Function that transfers HTTP requests over the
  43. * wire. The function is called with a Psr7\Http\Message\RequestInterface
  44. * and array of transfer options, and must return a
  45. * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
  46. * Psr7\Http\Message\ResponseInterface on success. "handler" is a
  47. * constructor only option that cannot be overridden in per/request
  48. * options. If no handler is provided, a default handler will be created
  49. * that enables all of the request options below by attaching all of the
  50. * default middleware to the handler.
  51. * - base_uri: (string|UriInterface) Base URI of the client that is merged
  52. * into relative URIs. Can be a string or instance of UriInterface.
  53. * - **: any request option
  54. *
  55. * @param array $config Client configuration settings.
  56. *
  57. * @see \GuzzleHttp\RequestOptions for a list of available request options.
  58. */
  59. public function __construct(array $config = [])
  60. {
  61. if (!isset($config['handler'])) {
  62. $config['handler'] = HandlerStack::create();
  63. }
  64. // Convert the base_uri to a UriInterface
  65. if (isset($config['base_uri'])) {
  66. $config['base_uri'] = Psr7\uri_for($config['base_uri']);
  67. }
  68. $this->configureDefaults($config);
  69. }
  70. public function __call($method, $args)
  71. {
  72. if (count($args) < 1) {
  73. throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
  74. }
  75. $uri = $args[0];
  76. $opts = isset($args[1]) ? $args[1] : [];
  77. return substr($method, -5) === 'Async'
  78. ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
  79. : $this->request($method, $uri, $opts);
  80. }
  81. public function sendAsync(RequestInterface $request, array $options = [])
  82. {
  83. // Merge the base URI into the request URI if needed.
  84. $options = $this->prepareDefaults($options);
  85. return $this->transfer(
  86. $request->withUri($this->buildUri($request->getUri(), $options)),
  87. $options
  88. );
  89. }
  90. public function send(RequestInterface $request, array $options = [])
  91. {
  92. $options[RequestOptions::SYNCHRONOUS] = true;
  93. return $this->sendAsync($request, $options)->wait();
  94. }
  95. public function requestAsync($method, $uri = null, array $options = [])
  96. {
  97. $options = $this->prepareDefaults($options);
  98. // Remove request modifying parameter because it can be done up-front.
  99. $headers = isset($options['headers']) ? $options['headers'] : [];
  100. $body = isset($options['body']) ? $options['body'] : null;
  101. $version = isset($options['version']) ? $options['version'] : '1.1';
  102. // Merge the URI into the base URI.
  103. $uri = $this->buildUri($uri, $options);
  104. if (is_array($body)) {
  105. $this->invalidBody();
  106. }
  107. $request = new Psr7\Request($method, $uri, $headers, $body, $version);
  108. // Remove the option so that they are not doubly-applied.
  109. unset($options['headers'], $options['body'], $options['version']);
  110. return $this->transfer($request, $options);
  111. }
  112. public function request($method, $uri = null, array $options = [])
  113. {
  114. $options[RequestOptions::SYNCHRONOUS] = true;
  115. return $this->requestAsync($method, $uri, $options)->wait();
  116. }
  117. public function getConfig($option = null)
  118. {
  119. return $option === null
  120. ? $this->config
  121. : (isset($this->config[$option]) ? $this->config[$option] : null);
  122. }
  123. private function buildUri($uri, array $config)
  124. {
  125. if (!isset($config['base_uri'])) {
  126. return $uri instanceof UriInterface ? $uri : new Psr7\Uri($uri);
  127. }
  128. return Psr7\Uri::resolve(Psr7\uri_for($config['base_uri']), $uri);
  129. }
  130. /**
  131. * Configures the default options for a client.
  132. *
  133. * @param array $config
  134. */
  135. private function configureDefaults(array $config)
  136. {
  137. $defaults = [
  138. 'allow_redirects' => RedirectMiddleware::$defaultSettings,
  139. 'http_errors' => true,
  140. 'decode_content' => true,
  141. 'verify' => true,
  142. 'cookies' => false
  143. ];
  144. // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set
  145. if ($proxy = getenv('HTTP_PROXY')) {
  146. $defaults['proxy']['http'] = $proxy;
  147. }
  148. if ($proxy = getenv('HTTPS_PROXY')) {
  149. $defaults['proxy']['https'] = $proxy;
  150. }
  151. if ($noProxy = getenv('NO_PROXY')) {
  152. $cleanedNoProxy = str_replace(' ', '', $noProxy);
  153. $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
  154. }
  155. $this->config = $config + $defaults;
  156. if (!empty($config['cookies']) && $config['cookies'] === true) {
  157. $this->config['cookies'] = new CookieJar();
  158. }
  159. // Add the default user-agent header.
  160. if (!isset($this->config['headers'])) {
  161. $this->config['headers'] = ['User-Agent' => default_user_agent()];
  162. } else {
  163. // Add the User-Agent header if one was not already set.
  164. foreach (array_keys($this->config['headers']) as $name) {
  165. if (strtolower($name) === 'user-agent') {
  166. return;
  167. }
  168. }
  169. $this->config['headers']['User-Agent'] = default_user_agent();
  170. }
  171. }
  172. /**
  173. * Merges default options into the array.
  174. *
  175. * @param array $options Options to modify by reference
  176. *
  177. * @return array
  178. */
  179. private function prepareDefaults($options)
  180. {
  181. $defaults = $this->config;
  182. if (!empty($defaults['headers'])) {
  183. // Default headers are only added if they are not present.
  184. $defaults['_conditional'] = $defaults['headers'];
  185. unset($defaults['headers']);
  186. }
  187. // Special handling for headers is required as they are added as
  188. // conditional headers and as headers passed to a request ctor.
  189. if (array_key_exists('headers', $options)) {
  190. // Allows default headers to be unset.
  191. if ($options['headers'] === null) {
  192. $defaults['_conditional'] = null;
  193. unset($options['headers']);
  194. } elseif (!is_array($options['headers'])) {
  195. throw new \InvalidArgumentException('headers must be an array');
  196. }
  197. }
  198. // Shallow merge defaults underneath options.
  199. $result = $options + $defaults;
  200. // Remove null values.
  201. foreach ($result as $k => $v) {
  202. if ($v === null) {
  203. unset($result[$k]);
  204. }
  205. }
  206. return $result;
  207. }
  208. /**
  209. * Transfers the given request and applies request options.
  210. *
  211. * The URI of the request is not modified and the request options are used
  212. * as-is without merging in default options.
  213. *
  214. * @param RequestInterface $request
  215. * @param array $options
  216. *
  217. * @return Promise\PromiseInterface
  218. */
  219. private function transfer(RequestInterface $request, array $options)
  220. {
  221. // save_to -> sink
  222. if (isset($options['save_to'])) {
  223. $options['sink'] = $options['save_to'];
  224. unset($options['save_to']);
  225. }
  226. // exceptions -> http_error
  227. if (isset($options['exceptions'])) {
  228. $options['http_errors'] = $options['exceptions'];
  229. unset($options['exceptions']);
  230. }
  231. $request = $this->applyOptions($request, $options);
  232. $handler = $options['handler'];
  233. try {
  234. return Promise\promise_for($handler($request, $options));
  235. } catch (\Exception $e) {
  236. return Promise\rejection_for($e);
  237. }
  238. }
  239. /**
  240. * Applies the array of request options to a request.
  241. *
  242. * @param RequestInterface $request
  243. * @param array $options
  244. *
  245. * @return RequestInterface
  246. */
  247. private function applyOptions(RequestInterface $request, array &$options)
  248. {
  249. $modify = [];
  250. if (isset($options['form_params'])) {
  251. if (isset($options['multipart'])) {
  252. throw new \InvalidArgumentException('You cannot use '
  253. . 'form_params and multipart at the same time. Use the '
  254. . 'form_params option if you want to send application/'
  255. . 'x-www-form-urlencoded requests, and the multipart '
  256. . 'option to send multipart/form-data requests.');
  257. }
  258. $options['body'] = http_build_query($options['form_params'], null, '&');
  259. unset($options['form_params']);
  260. $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
  261. }
  262. if (isset($options['multipart'])) {
  263. $elements = $options['multipart'];
  264. unset($options['multipart']);
  265. $options['body'] = new Psr7\MultipartStream($elements);
  266. }
  267. if (!empty($options['decode_content'])
  268. && $options['decode_content'] !== true
  269. ) {
  270. $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
  271. }
  272. if (isset($options['headers'])) {
  273. if (isset($modify['set_headers'])) {
  274. $modify['set_headers'] = $options['headers'] + $modify['set_headers'];
  275. } else {
  276. $modify['set_headers'] = $options['headers'];
  277. }
  278. unset($options['headers']);
  279. }
  280. if (isset($options['body'])) {
  281. if (is_array($options['body'])) {
  282. $this->invalidBody();
  283. }
  284. $modify['body'] = Psr7\stream_for($options['body']);
  285. unset($options['body']);
  286. }
  287. if (!empty($options['auth'])) {
  288. $value = $options['auth'];
  289. $type = is_array($value)
  290. ? (isset($value[2]) ? strtolower($value[2]) : 'basic')
  291. : $value;
  292. $config['auth'] = $value;
  293. switch (strtolower($type)) {
  294. case 'basic':
  295. $modify['set_headers']['Authorization'] = 'Basic '
  296. . base64_encode("$value[0]:$value[1]");
  297. break;
  298. case 'digest':
  299. // @todo: Do not rely on curl
  300. $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
  301. $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
  302. break;
  303. }
  304. }
  305. if (isset($options['query'])) {
  306. $value = $options['query'];
  307. if (is_array($value)) {
  308. $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
  309. }
  310. if (!is_string($value)) {
  311. throw new \InvalidArgumentException('query must be a string or array');
  312. }
  313. $modify['query'] = $value;
  314. unset($options['query']);
  315. }
  316. if (isset($options['json'])) {
  317. $modify['body'] = Psr7\stream_for(json_encode($options['json']));
  318. $options['_conditional']['Content-Type'] = 'application/json';
  319. unset($options['json']);
  320. }
  321. $request = Psr7\modify_request($request, $modify);
  322. if ($request->getBody() instanceof Psr7\MultipartStream) {
  323. // Use a multipart/form-data POST if a Content-Type is not set.
  324. $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
  325. . $request->getBody()->getBoundary();
  326. }
  327. // Merge in conditional headers if they are not present.
  328. if (isset($options['_conditional'])) {
  329. // Build up the changes so it's in a single clone of the message.
  330. $modify = [];
  331. foreach ($options['_conditional'] as $k => $v) {
  332. if (!$request->hasHeader($k)) {
  333. $modify['set_headers'][$k] = $v;
  334. }
  335. }
  336. $request = Psr7\modify_request($request, $modify);
  337. // Don't pass this internal value along to middleware/handlers.
  338. unset($options['_conditional']);
  339. }
  340. return $request;
  341. }
  342. private function invalidBody()
  343. {
  344. throw new \InvalidArgumentException('Passing in the "body" request '
  345. . 'option as an array to send a POST request has been deprecated. '
  346. . 'Please use the "form_params" request option to send a '
  347. . 'application/x-www-form-urlencoded request, or a the "multipart" '
  348. . 'request option to send a multipart/form-data request.');
  349. }
  350. }