PluginProbe
Depicter — Popup & Slider Builder / 1.5.2
Depicter — Popup & Slider Builder v1.5.2
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / modules / GuzzleHttp / Client.php

Client.php in Depicter — Popup & Slider Builder 1.5.2, at modules/GuzzleHttp/Client.php

478 lines 18.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Depicter\GuzzleHttp;
4
5 use Depicter\GuzzleHttp\Cookie\CookieJar;
6 use Depicter\GuzzleHttp\Exception\GuzzleException;
7 use Depicter\GuzzleHttp\Exception\InvalidArgumentException;
8 use Depicter\GuzzleHttp\Promise as P;
9 use Depicter\GuzzleHttp\Promise\PromiseInterface;
10 use Depicter\Psr\Http\Message\RequestInterface;
11 use Depicter\Psr\Http\Message\ResponseInterface;
12 use Depicter\Psr\Http\Message\UriInterface;
13
14 /**
15 * @final
16 */
17 class Client implements ClientInterface, \Depicter\Psr\Http\Client\ClientInterface
18 {
19 use ClientTrait;
20
21 /**
22 * @var array Default request options
23 */
24 private $config;
25
26 /**
27 * Clients accept an array of constructor parameters.
28 *
29 * Here's an example of creating a client using a base_uri and an array of
30 * default request options to apply to each request:
31 *
32 * $client = new Client([
33 * 'base_uri' => 'http://www.foo.com/1.0/',
34 * 'timeout' => 0,
35 * 'allow_redirects' => false,
36 * 'proxy' => '192.168.16.1:10'
37 * ]);
38 *
39 * Client configuration settings include the following options:
40 *
41 * - handler: (callable) Function that transfers HTTP requests over the
42 * wire. The function is called with a Psr7\Http\Message\RequestInterface
43 * and array of transfer options, and must return a
44 * Depicter\GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
45 * Psr7\Http\Message\ResponseInterface on success.
46 * If no handler is provided, a default handler will be created
47 * that enables all of the request options below by attaching all of the
48 * default middleware to the handler.
49 * - base_uri: (string|UriInterface) Base URI of the client that is merged
50 * into relative URIs. Can be a string or instance of UriInterface.
51 * - **: any request option
52 *
53 * @param array $config Client configuration settings.
54 *
55 * @see \Depicter\GuzzleHttp\RequestOptions for a list of available request options.
56 */
57 public function __construct(array $config = [])
58 {
59 if (!isset($config['handler'])) {
60 $config['handler'] = HandlerStack::create();
61 } elseif (!\is_callable($config['handler'])) {
62 throw new InvalidArgumentException('handler must be a callable');
63 }
64
65 // Convert the base_uri to a UriInterface
66 if (isset($config['base_uri'])) {
67 $config['base_uri'] = Psr7\Utils::uriFor($config['base_uri']);
68 }
69
70 $this->configureDefaults($config);
71 }
72
73 /**
74 * @param string $method
75 * @param array $args
76 *
77 * @return PromiseInterface|ResponseInterface
78 *
79 * @deprecated Client::__call will be removed in guzzlehttp/guzzle:8.0.
80 */
81 public function __call($method, $args)
82 {
83 if (\count($args) < 1) {
84 throw new InvalidArgumentException('Magic request methods require a URI and optional options array');
85 }
86
87 $uri = $args[0];
88 $opts = $args[1] ?? [];
89
90 return \substr($method, -5) === 'Async'
91 ? $this->requestAsync(\substr($method, 0, -5), $uri, $opts)
92 : $this->request($method, $uri, $opts);
93 }
94
95 /**
96 * Asynchronously send an HTTP request.
97 *
98 * @param array $options Request options to apply to the given
99 * request and to the transfer. See \Depicter\GuzzleHttp\RequestOptions.
100 */
101 public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface
102 {
103 // Merge the base URI into the request URI if needed.
104 $options = $this->prepareDefaults($options);
105
106 return $this->transfer(
107 $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
108 $options
109 );
110 }
111
112 /**
113 * Send an HTTP request.
114 *
115 * @param array $options Request options to apply to the given
116 * request and to the transfer. See \Depicter\GuzzleHttp\RequestOptions.
117 *
118 * @throws GuzzleException
119 */
120 public function send(RequestInterface $request, array $options = []): ResponseInterface
121 {
122 $options[RequestOptions::SYNCHRONOUS] = true;
123 return $this->sendAsync($request, $options)->wait();
124 }
125
126 /**
127 * The HttpClient PSR (PSR-18) specify this method.
128 *
129 * @inheritDoc
130 */
131 public function sendRequest(RequestInterface $request): ResponseInterface
132 {
133 $options[RequestOptions::SYNCHRONOUS] = true;
134 $options[RequestOptions::ALLOW_REDIRECTS] = false;
135 $options[RequestOptions::HTTP_ERRORS] = false;
136
137 return $this->sendAsync($request, $options)->wait();
138 }
139
140 /**
141 * Create and send an asynchronous HTTP request.
142 *
143 * Use an absolute path to override the base path of the client, or a
144 * relative path to append to the base path of the client. The URL can
145 * contain the query string as well. Use an array to provide a URL
146 * template and additional variables to use in the URL template expansion.
147 *
148 * @param string $method HTTP method
149 * @param string|UriInterface $uri URI object or string.
150 * @param array $options Request options to apply. See \Depicter\GuzzleHttp\RequestOptions.
151 */
152 public function requestAsync(string $method, $uri = '', array $options = []): PromiseInterface
153 {
154 $options = $this->prepareDefaults($options);
155 // Remove request modifying parameter because it can be done up-front.
156 $headers = $options['headers'] ?? [];
157 $body = $options['body'] ?? null;
158 $version = $options['version'] ?? '1.1';
159 // Merge the URI into the base URI.
160 $uri = $this->buildUri(Psr7\Utils::uriFor($uri), $options);
161 if (\is_array($body)) {
162 throw $this->invalidBody();
163 }
164 $request = new Psr7\Request($method, $uri, $headers, $body, $version);
165 // Remove the option so that they are not doubly-applied.
166 unset($options['headers'], $options['body'], $options['version']);
167
168 return $this->transfer($request, $options);
169 }
170
171 /**
172 * Create and send an HTTP request.
173 *
174 * Use an absolute path to override the base path of the client, or a
175 * relative path to append to the base path of the client. The URL can
176 * contain the query string as well.
177 *
178 * @param string $method HTTP method.
179 * @param string|UriInterface $uri URI object or string.
180 * @param array $options Request options to apply. See \Depicter\GuzzleHttp\RequestOptions.
181 *
182 * @throws GuzzleException
183 */
184 public function request(string $method, $uri = '', array $options = []): ResponseInterface
185 {
186 $options[RequestOptions::SYNCHRONOUS] = true;
187 return $this->requestAsync($method, $uri, $options)->wait();
188 }
189
190 /**
191 * Get a client configuration option.
192 *
193 * These options include default request options of the client, a "handler"
194 * (if utilized by the concrete client), and a "base_uri" if utilized by
195 * the concrete client.
196 *
197 * @param string|null $option The config option to retrieve.
198 *
199 * @return mixed
200 *
201 * @deprecated Client::getConfig will be removed in guzzlehttp/guzzle:8.0.
202 */
203 public function getConfig(?string $option = null)
204 {
205 return $option === null
206 ? $this->config
207 : ($this->config[$option] ?? null);
208 }
209
210 private function buildUri(UriInterface $uri, array $config): UriInterface
211 {
212 if (isset($config['base_uri'])) {
213 $uri = Psr7\UriResolver::resolve(Psr7\Utils::uriFor($config['base_uri']), $uri);
214 }
215
216 if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
217 $idnOptions = ($config['idn_conversion'] === true) ? \IDNA_DEFAULT : $config['idn_conversion'];
218 $uri = Utils::idnUriConvert($uri, $idnOptions);
219 }
220
221 return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
222 }
223
224 /**
225 * Configures the default options for a client.
226 */
227 private function configureDefaults(array $config): void
228 {
229 $defaults = [
230 'allow_redirects' => RedirectMiddleware::$defaultSettings,
231 'http_errors' => true,
232 'decode_content' => true,
233 'verify' => true,
234 'cookies' => false,
235 'idn_conversion' => false,
236 ];
237
238 // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
239
240 // We can only trust the HTTP_PROXY environment variable in a CLI
241 // process due to the fact that PHP has no reliable mechanism to
242 // get environment variables that start with "HTTP_".
243 if (\PHP_SAPI === 'cli' && ($proxy = Utils::getenv('HTTP_PROXY'))) {
244 $defaults['proxy']['http'] = $proxy;
245 }
246
247 if ($proxy = Utils::getenv('HTTPS_PROXY')) {
248 $defaults['proxy']['https'] = $proxy;
249 }
250
251 if ($noProxy = Utils::getenv('NO_PROXY')) {
252 $cleanedNoProxy = \str_replace(' ', '', $noProxy);
253 $defaults['proxy']['no'] = \explode(',', $cleanedNoProxy);
254 }
255
256 $this->config = $config + $defaults;
257
258 if (!empty($config['cookies']) && $config['cookies'] === true) {
259 $this->config['cookies'] = new CookieJar();
260 }
261
262 // Add the default user-agent header.
263 if (!isset($this->config['headers'])) {
264 $this->config['headers'] = ['User-Agent' => Utils::defaultUserAgent()];
265 } else {
266 // Add the User-Agent header if one was not already set.
267 foreach (\array_keys($this->config['headers']) as $name) {
268 if (\strtolower($name) === 'user-agent') {
269 return;
270 }
271 }
272 $this->config['headers']['User-Agent'] = Utils::defaultUserAgent();
273 }
274 }
275
276 /**
277 * Merges default options into the array.
278 *
279 * @param array $options Options to modify by reference
280 */
281 private function prepareDefaults(array $options): array
282 {
283 $defaults = $this->config;
284
285 if (!empty($defaults['headers'])) {
286 // Default headers are only added if they are not present.
287 $defaults['_conditional'] = $defaults['headers'];
288 unset($defaults['headers']);
289 }
290
291 // Special handling for headers is required as they are added as
292 // conditional headers and as headers passed to a request ctor.
293 if (\array_key_exists('headers', $options)) {
294 // Allows default headers to be unset.
295 if ($options['headers'] === null) {
296 $defaults['_conditional'] = [];
297 unset($options['headers']);
298 } elseif (!\is_array($options['headers'])) {
299 throw new InvalidArgumentException('headers must be an array');
300 }
301 }
302
303 // Shallow merge defaults underneath options.
304 $result = $options + $defaults;
305
306 // Remove null values.
307 foreach ($result as $k => $v) {
308 if ($v === null) {
309 unset($result[$k]);
310 }
311 }
312
313 return $result;
314 }
315
316 /**
317 * Transfers the given request and applies request options.
318 *
319 * The URI of the request is not modified and the request options are used
320 * as-is without merging in default options.
321 *
322 * @param array $options See \Depicter\GuzzleHttp\RequestOptions.
323 */
324 private function transfer(RequestInterface $request, array $options): PromiseInterface
325 {
326 $request = $this->applyOptions($request, $options);
327 /** @var HandlerStack $handler */
328 $handler = $options['handler'];
329
330 try {
331 return P\Create::promiseFor($handler($request, $options));
332 } catch (\Exception $e) {
333 return P\Create::rejectionFor($e);
334 }
335 }
336
337 /**
338 * Applies the array of request options to a request.
339 */
340 private function applyOptions(RequestInterface $request, array &$options): RequestInterface
341 {
342 $modify = [
343 'set_headers' => [],
344 ];
345
346 if (isset($options['headers'])) {
347 if (array_keys($options['headers']) === range(0, count($options['headers']) - 1)) {
348 throw new InvalidArgumentException('The headers array must have header name as keys.');
349 }
350 $modify['set_headers'] = $options['headers'];
351 unset($options['headers']);
352 }
353
354 if (isset($options['form_params'])) {
355 if (isset($options['multipart'])) {
356 throw new InvalidArgumentException('You cannot use '
357 . 'form_params and multipart at the same time. Use the '
358 . 'form_params option if you want to send application/'
359 . 'x-www-form-urlencoded requests, and the multipart '
360 . 'option to send multipart/form-data requests.');
361 }
362 $options['body'] = \http_build_query($options['form_params'], '', '&');
363 unset($options['form_params']);
364 // Ensure that we don't have the header in different case and set the new value.
365 $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
366 $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
367 }
368
369 if (isset($options['multipart'])) {
370 $options['body'] = new Psr7\MultipartStream($options['multipart']);
371 unset($options['multipart']);
372 }
373
374 if (isset($options['json'])) {
375 $options['body'] = Utils::jsonEncode($options['json']);
376 unset($options['json']);
377 // Ensure that we don't have the header in different case and set the new value.
378 $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
379 $options['_conditional']['Content-Type'] = 'application/json';
380 }
381
382 if (!empty($options['decode_content'])
383 && $options['decode_content'] !== true
384 ) {
385 // Ensure that we don't have the header in different case and set the new value.
386 $options['_conditional'] = Psr7\Utils::caselessRemove(['Accept-Encoding'], $options['_conditional']);
387 $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
388 }
389
390 if (isset($options['body'])) {
391 if (\is_array($options['body'])) {
392 throw $this->invalidBody();
393 }
394 $modify['body'] = Psr7\Utils::streamFor($options['body']);
395 unset($options['body']);
396 }
397
398 if (!empty($options['auth']) && \is_array($options['auth'])) {
399 $value = $options['auth'];
400 $type = isset($value[2]) ? \strtolower($value[2]) : 'basic';
401 switch ($type) {
402 case 'basic':
403 // Ensure that we don't have the header in different case and set the new value.
404 $modify['set_headers'] = Psr7\Utils::caselessRemove(['Authorization'], $modify['set_headers']);
405 $modify['set_headers']['Authorization'] = 'Basic '
406 . \base64_encode("$value[0]:$value[1]");
407 break;
408 case 'digest':
409 // @todo: Do not rely on curl
410 $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_DIGEST;
411 $options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
412 break;
413 case 'ntlm':
414 $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_NTLM;
415 $options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
416 break;
417 }
418 }
419
420 if (isset($options['query'])) {
421 $value = $options['query'];
422 if (\is_array($value)) {
423 $value = \http_build_query($value, '', '&', \PHP_QUERY_RFC3986);
424 }
425 if (!\is_string($value)) {
426 throw new InvalidArgumentException('query must be a string or array');
427 }
428 $modify['query'] = $value;
429 unset($options['query']);
430 }
431
432 // Ensure that sink is not an invalid value.
433 if (isset($options['sink'])) {
434 // TODO: Add more sink validation?
435 if (\is_bool($options['sink'])) {
436 throw new InvalidArgumentException('sink must not be a boolean');
437 }
438 }
439
440 $request = Psr7\Utils::modifyRequest($request, $modify);
441 if ($request->getBody() instanceof Psr7\MultipartStream) {
442 // Use a multipart/form-data POST if a Content-Type is not set.
443 // Ensure that we don't have the header in different case and set the new value.
444 $options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
445 $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
446 . $request->getBody()->getBoundary();
447 }
448
449 // Merge in conditional headers if they are not present.
450 if (isset($options['_conditional'])) {
451 // Build up the changes so it's in a single clone of the message.
452 $modify = [];
453 foreach ($options['_conditional'] as $k => $v) {
454 if (!$request->hasHeader($k)) {
455 $modify['set_headers'][$k] = $v;
456 }
457 }
458 $request = Psr7\Utils::modifyRequest($request, $modify);
459 // Don't pass this internal value along to middleware/handlers.
460 unset($options['_conditional']);
461 }
462
463 return $request;
464 }
465
466 /**
467 * Return an InvalidArgumentException with pre-set message.
468 */
469 private function invalidBody(): InvalidArgumentException
470 {
471 return new InvalidArgumentException('Passing in the "body" request '
472 . 'option as an array to send a request is not supported. '
473 . 'Please use the "form_params" request option to send a '
474 . 'application/x-www-form-urlencoded request, or the "multipart" '
475 . 'request option to send a multipart/form-data request.');
476 }
477 }
478