Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Client.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 18.86 KiB


001  <?php
002  namespace GuzzleHttp;
003   
004  use GuzzleHttp\Cookie\CookieJar;
005  use GuzzleHttp\Exception\GuzzleException;
006  use GuzzleHttp\Promise;
007  use GuzzleHttp\Psr7;
008  use Psr\Http\Message\RequestInterface;
009  use Psr\Http\Message\ResponseInterface;
010  use Psr\Http\Message\UriInterface;
011   
012  /**
013   * @method ResponseInterface get(string|UriInterface $uri, array $options = [])
014   * @method ResponseInterface head(string|UriInterface $uri, array $options = [])
015   * @method ResponseInterface put(string|UriInterface $uri, array $options = [])
016   * @method ResponseInterface post(string|UriInterface $uri, array $options = [])
017   * @method ResponseInterface patch(string|UriInterface $uri, array $options = [])
018   * @method ResponseInterface delete(string|UriInterface $uri, array $options = [])
019   * @method Promise\PromiseInterface getAsync(string|UriInterface $uri, array $options = [])
020   * @method Promise\PromiseInterface headAsync(string|UriInterface $uri, array $options = [])
021   * @method Promise\PromiseInterface putAsync(string|UriInterface $uri, array $options = [])
022   * @method Promise\PromiseInterface postAsync(string|UriInterface $uri, array $options = [])
023   * @method Promise\PromiseInterface patchAsync(string|UriInterface $uri, array $options = [])
024   * @method Promise\PromiseInterface deleteAsync(string|UriInterface $uri, array $options = [])
025   */
026  class Client implements ClientInterface
027  {
028      /** @var array Default request options */
029      private $config;
030   
031      /**
032       * Clients accept an array of constructor parameters.
033       *
034       * Here's an example of creating a client using a base_uri and an array of
035       * default request options to apply to each request:
036       *
037       *     $client = new Client([
038       *         'base_uri'        => 'http://www.foo.com/1.0/',
039       *         'timeout'         => 0,
040       *         'allow_redirects' => false,
041       *         'proxy'           => '192.168.16.1:10'
042       *     ]);
043       *
044       * Client configuration settings include the following options:
045       *
046       * - handler: (callable) Function that transfers HTTP requests over the
047       *   wire. The function is called with a Psr7\Http\Message\RequestInterface
048       *   and array of transfer options, and must return a
049       *   GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
050       *   Psr7\Http\Message\ResponseInterface on success.
051       *   If no handler is provided, a default handler will be created
052       *   that enables all of the request options below by attaching all of the
053       *   default middleware to the handler.
054       * - base_uri: (string|UriInterface) Base URI of the client that is merged
055       *   into relative URIs. Can be a string or instance of UriInterface.
056       * - **: any request option
057       *
058       * @param array $config Client configuration settings.
059       *
060       * @see \GuzzleHttp\RequestOptions for a list of available request options.
061       */
062      public function __construct(array $config = [])
063      {
064          if (!isset($config['handler'])) {
065              $config['handler'] = HandlerStack::create();
066          } elseif (!is_callable($config['handler'])) {
067              throw new \InvalidArgumentException('handler must be a callable');
068          }
069   
070          // Convert the base_uri to a UriInterface
071          if (isset($config['base_uri'])) {
072              $config['base_uri'] = Psr7\uri_for($config['base_uri']);
073          }
074   
075          $this->configureDefaults($config);
076      }
077   
078      /**
079       * @param string $method
080       * @param array  $args
081       *
082       * @return Promise\PromiseInterface
083       */
084      public function __call($method, $args)
085      {
086          if (count($args) < 1) {
087              throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
088          }
089   
090          $uri = $args[0];
091          $opts = isset($args[1]) ? $args[1] : [];
092   
093          return substr($method, -5) === 'Async'
094              ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
095              : $this->request($method, $uri, $opts);
096      }
097   
098      /**
099       * Asynchronously send an HTTP request.
100       *
101       * @param array $options Request options to apply to the given
102       *                       request and to the transfer. See \GuzzleHttp\RequestOptions.
103       *
104       * @return Promise\PromiseInterface
105       */
106      public function sendAsync(RequestInterface $request, array $options = [])
107      {
108          // Merge the base URI into the request URI if needed.
109          $options = $this->prepareDefaults($options);
110   
111          return $this->transfer(
112              $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
113              $options
114          );
115      }
116   
117      /**
118       * Send an HTTP request.
119       *
120       * @param array $options Request options to apply to the given
121       *                       request and to the transfer. See \GuzzleHttp\RequestOptions.
122       *
123       * @return ResponseInterface
124       * @throws GuzzleException
125       */
126      public function send(RequestInterface $request, array $options = [])
127      {
128          $options[RequestOptions::SYNCHRONOUS] = true;
129          return $this->sendAsync($request, $options)->wait();
130      }
131   
132      /**
133       * Create and send an asynchronous HTTP request.
134       *
135       * Use an absolute path to override the base path of the client, or a
136       * relative path to append to the base path of the client. The URL can
137       * contain the query string as well. Use an array to provide a URL
138       * template and additional variables to use in the URL template expansion.
139       *
140       * @param string              $method  HTTP method
141       * @param string|UriInterface $uri     URI object or string.
142       * @param array               $options Request options to apply. See \GuzzleHttp\RequestOptions.
143       *
144       * @return Promise\PromiseInterface
145       */
146      public function requestAsync($method, $uri = '', array $options = [])
147      {
148          $options = $this->prepareDefaults($options);
149          // Remove request modifying parameter because it can be done up-front.
150          $headers = isset($options['headers']) ? $options['headers'] : [];
151          $body = isset($options['body']) ? $options['body'] : null;
152          $version = isset($options['version']) ? $options['version'] : '1.1';
153          // Merge the URI into the base URI.
154          $uri = $this->buildUri($uri, $options);
155          if (is_array($body)) {
156              $this->invalidBody();
157          }
158          $request = new Psr7\Request($method, $uri, $headers, $body, $version);
159          // Remove the option so that they are not doubly-applied.
160          unset($options['headers'], $options['body'], $options['version']);
161   
162          return $this->transfer($request, $options);
163      }
164   
165      /**
166       * Create and send an HTTP request.
167       *
168       * Use an absolute path to override the base path of the client, or a
169       * relative path to append to the base path of the client. The URL can
170       * contain the query string as well.
171       *
172       * @param string              $method  HTTP method.
173       * @param string|UriInterface $uri     URI object or string.
174       * @param array               $options Request options to apply. See \GuzzleHttp\RequestOptions.
175       *
176       * @return ResponseInterface
177       * @throws GuzzleException
178       */
179      public function request($method, $uri = '', array $options = [])
180      {
181          $options[RequestOptions::SYNCHRONOUS] = true;
182          return $this->requestAsync($method, $uri, $options)->wait();
183      }
184   
185      /**
186       * Get a client configuration option.
187       *
188       * These options include default request options of the client, a "handler"
189       * (if utilized by the concrete client), and a "base_uri" if utilized by
190       * the concrete client.
191       *
192       * @param string|null $option The config option to retrieve.
193       *
194       * @return mixed
195       */
196      public function getConfig($option = null)
197      {
198          return $option === null
199              ? $this->config
200              : (isset($this->config[$option]) ? $this->config[$option] : null);
201      }
202   
203      /**
204       * @param  string|null $uri
205       *
206       * @return UriInterface
207       */
208      private function buildUri($uri, array $config)
209      {
210          // for BC we accept null which would otherwise fail in uri_for
211          $uri = Psr7\uri_for($uri === null ? '' : $uri);
212   
213          if (isset($config['base_uri'])) {
214              $uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
215          }
216   
217          if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
218              $idnOptions = ($config['idn_conversion'] === true) ? IDNA_DEFAULT : $config['idn_conversion'];
219              $uri = Utils::idnUriConvert($uri, $idnOptions);
220          }
221   
222          return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
223      }
224   
225      /**
226       * Configures the default options for a client.
227       *
228       * @param array $config
229       * @return void
230       */
231      private function configureDefaults(array $config)
232      {
233          $defaults = [
234              'allow_redirects' => RedirectMiddleware::$defaultSettings,
235              'http_errors'     => true,
236              'decode_content'  => true,
237              'verify'          => true,
238              'cookies'         => false,
239              'idn_conversion'  => true,
240          ];
241   
242          // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
243   
244          // We can only trust the HTTP_PROXY environment variable in a CLI
245          // process due to the fact that PHP has no reliable mechanism to
246          // get environment variables that start with "HTTP_".
247          if (php_sapi_name() === 'cli' && getenv('HTTP_PROXY')) {
248              $defaults['proxy']['http'] = getenv('HTTP_PROXY');
249          }
250   
251          if ($proxy = getenv('HTTPS_PROXY')) {
252              $defaults['proxy']['https'] = $proxy;
253          }
254   
255          if ($noProxy = getenv('NO_PROXY')) {
256              $cleanedNoProxy = str_replace(' ', '', $noProxy);
257              $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
258          }
259   
260          $this->config = $config + $defaults;
261   
262          if (!empty($config['cookies']) && $config['cookies'] === true) {
263              $this->config['cookies'] = new CookieJar();
264          }
265   
266          // Add the default user-agent header.
267          if (!isset($this->config['headers'])) {
268              $this->config['headers'] = ['User-Agent' => default_user_agent()];
269          } else {
270              // Add the User-Agent header if one was not already set.
271              foreach (array_keys($this->config['headers']) as $name) {
272                  if (strtolower($name) === 'user-agent') {
273                      return;
274                  }
275              }
276              $this->config['headers']['User-Agent'] = default_user_agent();
277          }
278      }
279   
280      /**
281       * Merges default options into the array.
282       *
283       * @param array $options Options to modify by reference
284       *
285       * @return array
286       */
287      private function prepareDefaults(array $options)
288      {
289          $defaults = $this->config;
290   
291          if (!empty($defaults['headers'])) {
292              // Default headers are only added if they are not present.
293              $defaults['_conditional'] = $defaults['headers'];
294              unset($defaults['headers']);
295          }
296   
297          // Special handling for headers is required as they are added as
298          // conditional headers and as headers passed to a request ctor.
299          if (array_key_exists('headers', $options)) {
300              // Allows default headers to be unset.
301              if ($options['headers'] === null) {
302                  $defaults['_conditional'] = [];
303                  unset($options['headers']);
304              } elseif (!is_array($options['headers'])) {
305                  throw new \InvalidArgumentException('headers must be an array');
306              }
307          }
308   
309          // Shallow merge defaults underneath options.
310          $result = $options + $defaults;
311   
312          // Remove null values.
313          foreach ($result as $k => $v) {
314              if ($v === null) {
315                  unset($result[$k]);
316              }
317          }
318   
319          return $result;
320      }
321   
322      /**
323       * Transfers the given request and applies request options.
324       *
325       * The URI of the request is not modified and the request options are used
326       * as-is without merging in default options.
327       *
328       * @param array $options See \GuzzleHttp\RequestOptions.
329       *
330       * @return Promise\PromiseInterface
331       */
332      private function transfer(RequestInterface $request, array $options)
333      {
334          // save_to -> sink
335          if (isset($options['save_to'])) {
336              $options['sink'] = $options['save_to'];
337              unset($options['save_to']);
338          }
339   
340          // exceptions -> http_errors
341          if (isset($options['exceptions'])) {
342              $options['http_errors'] = $options['exceptions'];
343              unset($options['exceptions']);
344          }
345   
346          $request = $this->applyOptions($request, $options);
347          /** @var HandlerStack $handler */
348          $handler = $options['handler'];
349   
350          try {
351              return Promise\promise_for($handler($request, $options));
352          } catch (\Exception $e) {
353              return Promise\rejection_for($e);
354          }
355      }
356   
357      /**
358       * Applies the array of request options to a request.
359       *
360       * @param RequestInterface $request
361       * @param array            $options
362       *
363       * @return RequestInterface
364       */
365      private function applyOptions(RequestInterface $request, array &$options)
366      {
367          $modify = [
368              'set_headers' => [],
369          ];
370   
371          if (isset($options['headers'])) {
372              $modify['set_headers'] = $options['headers'];
373              unset($options['headers']);
374          }
375   
376          if (isset($options['form_params'])) {
377              if (isset($options['multipart'])) {
378                  throw new \InvalidArgumentException('You cannot use '
379                      . 'form_params and multipart at the same time. Use the '
380                      . 'form_params option if you want to send application/'
381                      . 'x-www-form-urlencoded requests, and the multipart '
382                      . 'option to send multipart/form-data requests.');
383              }
384              $options['body'] = http_build_query($options['form_params'], '', '&');
385              unset($options['form_params']);
386              // Ensure that we don't have the header in different case and set the new value.
387              $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
388              $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
389          }
390   
391          if (isset($options['multipart'])) {
392              $options['body'] = new Psr7\MultipartStream($options['multipart']);
393              unset($options['multipart']);
394          }
395   
396          if (isset($options['json'])) {
397              $options['body'] = \GuzzleHttp\json_encode($options['json']);
398              unset($options['json']);
399              // Ensure that we don't have the header in different case and set the new value.
400              $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
401              $options['_conditional']['Content-Type'] = 'application/json';
402          }
403   
404          if (!empty($options['decode_content'])
405              && $options['decode_content'] !== true
406          ) {
407              // Ensure that we don't have the header in different case and set the new value.
408              $options['_conditional'] = Psr7\_caseless_remove(['Accept-Encoding'], $options['_conditional']);
409              $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
410          }
411   
412          if (isset($options['body'])) {
413              if (is_array($options['body'])) {
414                  $this->invalidBody();
415              }
416              $modify['body'] = Psr7\stream_for($options['body']);
417              unset($options['body']);
418          }
419   
420          if (!empty($options['auth']) && is_array($options['auth'])) {
421              $value = $options['auth'];
422              $type = isset($value[2]) ? strtolower($value[2]) : 'basic';
423              switch ($type) {
424                  case 'basic':
425                      // Ensure that we don't have the header in different case and set the new value.
426                      $modify['set_headers'] = Psr7\_caseless_remove(['Authorization'], $modify['set_headers']);
427                      $modify['set_headers']['Authorization'] = 'Basic '
428                          . base64_encode("$value[0]:$value[1]");
429                      break;
430                  case 'digest':
431                      // @todo: Do not rely on curl
432                      $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
433                      $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
434                      break;
435                  case 'ntlm':
436                      $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_NTLM;
437                      $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
438                      break;
439              }
440          }
441   
442          if (isset($options['query'])) {
443              $value = $options['query'];
444              if (is_array($value)) {
445                  $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
446              }
447              if (!is_string($value)) {
448                  throw new \InvalidArgumentException('query must be a string or array');
449              }
450              $modify['query'] = $value;
451              unset($options['query']);
452          }
453   
454          // Ensure that sink is not an invalid value.
455          if (isset($options['sink'])) {
456              // TODO: Add more sink validation?
457              if (is_bool($options['sink'])) {
458                  throw new \InvalidArgumentException('sink must not be a boolean');
459              }
460          }
461   
462          $request = Psr7\modify_request($request, $modify);
463          if ($request->getBody() instanceof Psr7\MultipartStream) {
464              // Use a multipart/form-data POST if a Content-Type is not set.
465              // Ensure that we don't have the header in different case and set the new value.
466              $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
467              $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
468                  . $request->getBody()->getBoundary();
469          }
470   
471          // Merge in conditional headers if they are not present.
472          if (isset($options['_conditional'])) {
473              // Build up the changes so it's in a single clone of the message.
474              $modify = [];
475              foreach ($options['_conditional'] as $k => $v) {
476                  if (!$request->hasHeader($k)) {
477                      $modify['set_headers'][$k] = $v;
478                  }
479              }
480              $request = Psr7\modify_request($request, $modify);
481              // Don't pass this internal value along to middleware/handlers.
482              unset($options['_conditional']);
483          }
484   
485          return $request;
486      }
487   
488      /**
489       * Throw Exception with pre-set message.
490       * @return void
491       * @throws \InvalidArgumentException Invalid body.
492       */
493      private function invalidBody()
494      {
495          throw new \InvalidArgumentException('Passing in the "body" request '
496              . 'option as an array to send a POST request has been deprecated. '
497              . 'Please use the "form_params" request option to send a '
498              . 'application/x-www-form-urlencoded request, or the "multipart" '
499              . 'request option to send a multipart/form-data request.');
500      }
501  }
502