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. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
Client.php
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