PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / trunk
Tutor LMS – eLearning and online course solution vtrunk
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / ecommerce / PaymentGateways / Paypal / vendor / guzzlehttp / guzzle / src / Utils.php
tutor / ecommerce / PaymentGateways / Paypal / vendor / guzzlehttp / guzzle / src Last commit date
Cookie 2 months ago Exception 2 months ago Handler 2 months ago BodySummarizer.php 1 year ago BodySummarizerInterface.php 1 year ago Client.php 2 months ago ClientInterface.php 1 year ago ClientTrait.php 1 year ago HandlerStack.php 2 months ago MessageFormatter.php 1 year ago MessageFormatterInterface.php 1 year ago Middleware.php 2 months ago Pool.php 2 months ago PrepareBodyMiddleware.php 2 months ago RedirectMiddleware.php 2 months ago RequestOptions.php 2 months ago RetryMiddleware.php 2 months ago TransferStats.php 1 year ago TransportSharing.php 2 months ago Utils.php 2 months ago functions.php 2 months ago functions_include.php 1 year ago
Utils.php
629 lines
1 <?php
2
3 namespace GuzzleHttp;
4
5 use GuzzleHttp\Exception\InvalidArgumentException;
6 use GuzzleHttp\Handler\CurlHandler;
7 use GuzzleHttp\Handler\CurlMultiHandler;
8 use GuzzleHttp\Handler\CurlShareHandleState;
9 use GuzzleHttp\Handler\Proxy;
10 use GuzzleHttp\Handler\StreamHandler;
11 use Psr\Http\Message\RequestInterface;
12 use Psr\Http\Message\UriInterface;
13
14 final class Utils
15 {
16 /**
17 * Debug function used to describe the provided value type and class.
18 *
19 * @param mixed $input
20 *
21 * @return string Returns a string containing the type of the variable and
22 * if a class is provided, the class name.
23 */
24 public static function describeType($input): string
25 {
26 switch (\gettype($input)) {
27 case 'object':
28 return 'object('.\get_class($input).')';
29 case 'array':
30 return 'array('.\count($input).')';
31 default:
32 \ob_start();
33 \var_dump($input);
34 // normalize float vs double
35 /** @var string $varDumpContent */
36 $varDumpContent = \ob_get_clean();
37
38 return \str_replace('double(', 'float(', \rtrim($varDumpContent));
39 }
40 }
41
42 /**
43 * Parses an array of header lines into an associative array of headers.
44 *
45 * @param iterable $lines Header lines array of strings in the following
46 * format: "Name: Value"
47 */
48 public static function headersFromLines(iterable $lines): array
49 {
50 $headers = [];
51
52 foreach ($lines as $line) {
53 $parts = \explode(':', $line, 2);
54 $headers[\trim($parts[0])][] = isset($parts[1]) ? \trim($parts[1]) : null;
55 }
56
57 return $headers;
58 }
59
60 /**
61 * Returns a debug stream based on the provided variable.
62 *
63 * @param mixed $value Optional value
64 *
65 * @return resource
66 */
67 public static function debugResource($value = null)
68 {
69 if (\is_resource($value)) {
70 return $value;
71 }
72 if (\defined('STDOUT')) {
73 return \STDOUT;
74 }
75
76 return Psr7\Utils::tryFopen('php://output', 'w');
77 }
78
79 /**
80 * Chooses and creates a default handler to use based on the environment.
81 *
82 * The returned handler is not wrapped by any default middlewares.
83 *
84 * @param array{transport_sharing?: mixed} $handlerOptions Handler constructor options.
85 *
86 * @return callable(RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system.
87 *
88 * @throws \RuntimeException if no viable Handler is available.
89 */
90 public static function chooseHandler(array $handlerOptions = []): callable
91 {
92 $handler = null;
93 $sharingMode = CurlShareHandleState::normalizeMode($handlerOptions['transport_sharing'] ?? null, 'transport_sharing');
94 $sharingRequested = $sharingMode !== TransportSharing::NONE;
95 $sharingRequired = $sharingMode === TransportSharing::HANDLER_REQUIRE;
96 $curlHandlerOptions = [];
97 $curlSupported = \defined('CURLOPT_CUSTOMREQUEST')
98 && \function_exists('curl_version')
99 && version_compare(curl_version()['version'], '7.21.2') >= 0
100 && (\function_exists('curl_multi_exec') || \function_exists('curl_exec'));
101
102 if ($sharingRequired && !$curlSupported) {
103 throw new \RuntimeException('Required transport sharing requires the PHP cURL extension, curl_exec() or curl_multi_exec(), and libcurl 7.21.2 or higher.');
104 }
105
106 if ($curlSupported) {
107 if ($sharingRequested) {
108 $shareState = CurlShareHandleState::fromOption($sharingMode);
109 if ($shareState !== null) {
110 $curlHandlerOptions['transport_sharing'] = $shareState;
111 }
112 }
113
114 if (\function_exists('curl_multi_exec') && \function_exists('curl_exec')) {
115 $handler = Proxy::wrapSync(new CurlMultiHandler($curlHandlerOptions), new CurlHandler($curlHandlerOptions));
116 } elseif (\function_exists('curl_exec')) {
117 $handler = new CurlHandler($curlHandlerOptions);
118 } elseif (\function_exists('curl_multi_exec')) {
119 $handler = new CurlMultiHandler($curlHandlerOptions);
120 }
121 }
122
123 if (\ini_get('allow_url_fopen')) {
124 $streamHandler = new StreamHandler(['transport_sharing' => $sharingMode]);
125
126 $handler = $handler
127 ? Proxy::wrapStreaming($handler, $streamHandler)
128 : $streamHandler;
129 } elseif (!$handler) {
130 throw new \RuntimeException('GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler.');
131 }
132
133 return $handler;
134 }
135
136 /**
137 * Get the default User-Agent string to use with Guzzle.
138 */
139 public static function defaultUserAgent(): string
140 {
141 return sprintf('GuzzleHttp/%d', ClientInterface::MAJOR_VERSION);
142 }
143
144 /**
145 * Returns the default cacert bundle for the current system.
146 *
147 * First, the openssl.cafile and curl.cainfo php.ini settings are checked.
148 * If those settings are not configured, then the common locations for
149 * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
150 * and Windows are checked. If any of these file locations are found on
151 * disk, they will be utilized.
152 *
153 * Note: the result of this function is cached for subsequent calls.
154 *
155 * @throws \RuntimeException if no bundle can be found.
156 *
157 * @deprecated Utils::defaultCaBundle will be removed in guzzlehttp/guzzle:8.0. This method is not needed in PHP 5.6+.
158 */
159 public static function defaultCaBundle(): string
160 {
161 static $cached = null;
162 static $cafiles = [
163 // Red Hat, CentOS, Fedora (provided by the ca-certificates package)
164 '/etc/pki/tls/certs/ca-bundle.crt',
165 // Ubuntu, Debian (provided by the ca-certificates package)
166 '/etc/ssl/certs/ca-certificates.crt',
167 // FreeBSD (provided by the ca_root_nss package)
168 '/usr/local/share/certs/ca-root-nss.crt',
169 // SLES 12 (provided by the ca-certificates package)
170 '/var/lib/ca-certificates/ca-bundle.pem',
171 // OS X provided by homebrew (using the default path)
172 '/usr/local/etc/openssl/cert.pem',
173 // Google app engine
174 '/etc/ca-certificates.crt',
175 // Windows?
176 'C:\\windows\\system32\\curl-ca-bundle.crt',
177 'C:\\windows\\curl-ca-bundle.crt',
178 ];
179
180 if ($cached) {
181 return $cached;
182 }
183
184 if ($ca = \ini_get('openssl.cafile')) {
185 return $cached = $ca;
186 }
187
188 if ($ca = \ini_get('curl.cainfo')) {
189 return $cached = $ca;
190 }
191
192 foreach ($cafiles as $filename) {
193 if (\file_exists($filename)) {
194 return $cached = $filename;
195 }
196 }
197
198 throw new \RuntimeException(
199 <<< EOT
200 No system CA bundle could be found in any of the the common system locations.
201 PHP versions earlier than 5.6 are not properly configured to use the system's
202 CA bundle by default. In order to verify peer certificates, you will need to
203 supply the path on disk to a certificate bundle to the 'verify' request
204 option: https://github.com/guzzle/guzzle/blob/7.11/docs/request-options.md#verify. If
205 you do not need a specific certificate bundle, then Mozilla provides a commonly
206 used CA bundle which can be downloaded here (provided by the maintainer of
207 cURL): https://curl.haxx.se/ca/cacert.pem. Once you have a CA bundle available
208 on disk, you can set the 'openssl.cafile' PHP ini setting to point to the path
209 to the file, allowing you to omit the 'verify' request option. See
210 https://curl.haxx.se/docs/sslcerts.html for more information.
211 EOT
212 );
213 }
214
215 /**
216 * Creates an associative array of lowercase header names to the actual
217 * header casing.
218 */
219 public static function normalizeHeaderKeys(array $headers): array
220 {
221 $result = [];
222 foreach (\array_keys($headers) as $key) {
223 $result[\strtolower((string) $key)] = $key;
224 }
225
226 return $result;
227 }
228
229 /**
230 * @param mixed $protocols
231 *
232 * @return string[]
233 *
234 * @throws InvalidArgumentException
235 */
236 public static function normalizeProtocols($protocols): array
237 {
238 if (!\is_array($protocols) || $protocols === []) {
239 throw new InvalidArgumentException('protocols must be a non-empty array of "http" and/or "https"');
240 }
241
242 $normalized = [];
243
244 foreach ($protocols as $protocol) {
245 if (!\is_string($protocol)) {
246 throw new InvalidArgumentException('protocols must contain only strings');
247 }
248
249 if ($protocol !== 'http' && $protocol !== 'https') {
250 throw new InvalidArgumentException('protocols may only contain "http" and "https"');
251 }
252
253 $normalized[$protocol] = true;
254 }
255
256 return \array_keys($normalized);
257 }
258
259 /**
260 * Returns true if the provided host matches any of the no proxy areas.
261 *
262 * This method will strip a port from the host if it is present. Each pattern
263 * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
264 * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
265 * "baz.foo.com", but ".foo.com" != "foo.com").
266 *
267 * Areas are matched in the following cases:
268 * 1. "*" (without quotes) always matches any hosts.
269 * 2. An exact match.
270 * 3. The area starts with "." and the area is the last part of the host. e.g.
271 * '.mit.edu' will match any host that ends with '.mit.edu'.
272 *
273 * @param string $host Host to check against the patterns.
274 * @param string[] $noProxyArray An array of host patterns.
275 *
276 * @throws InvalidArgumentException
277 */
278 public static function isHostInNoProxy(string $host, array $noProxyArray): bool
279 {
280 if (\strlen($host) === 0) {
281 throw new InvalidArgumentException('Empty host provided');
282 }
283
284 $host = self::normalizeNoProxyHost($host, true);
285
286 foreach ($noProxyArray as $area) {
287 // Always match on wildcards.
288 if ($area === '*') {
289 return true;
290 }
291
292 if ($area === '') {
293 continue;
294 }
295
296 $area = self::normalizeNoProxyHost($area, false);
297
298 if ($area === $host) {
299 // Exact matches.
300 return true;
301 }
302 // Special match if the area when prefixed with ".". Remove any
303 // existing leading "." and add a new leading ".".
304 $area = '.'.\ltrim($area, '.');
305 if (
306 \strpos($host, ':') === false
307 && \strpos($area, ':') === false
308 && \substr($host, -\strlen($area)) === $area
309 ) {
310 return true;
311 }
312 }
313
314 return false;
315 }
316
317 /**
318 * Returns true if the provided URI matches any of the no proxy areas.
319 *
320 * @param mixed $noProxy No-proxy host patterns.
321 *
322 * @internal
323 */
324 public static function isUriInNoProxy(UriInterface $uri, $noProxy): bool
325 {
326 if (\is_string($noProxy)) {
327 $noProxy = \explode(',', $noProxy);
328 }
329
330 if (!\is_array($noProxy)) {
331 return false;
332 }
333
334 $host = $uri->getHost();
335 if ($host === '') {
336 return false;
337 }
338
339 $port = $uri->getPort();
340 if ($port === null) {
341 $port = self::getDefaultPort($uri->getScheme());
342 }
343
344 foreach ($noProxy as $area) {
345 if (!\is_string($area)) {
346 continue;
347 }
348
349 $area = \trim($area);
350
351 // Always match on wildcards.
352 if ($area === '*') {
353 return true;
354 }
355
356 if ($area === '') {
357 continue;
358 }
359
360 [$area, $areaPort] = self::splitNoProxyHostAndPort($area);
361 if ($areaPort !== null && $areaPort !== $port) {
362 continue;
363 }
364
365 if (self::isHostInNoProxy($host, [$area])) {
366 return true;
367 }
368 }
369
370 return false;
371 }
372
373 private static function normalizeNoProxyHost(string $host, bool $stripPort): string
374 {
375 if ($host !== '' && $host[0] === '[') {
376 $closingBracket = \strpos($host, ']');
377
378 if ($closingBracket !== false) {
379 $address = \substr($host, 1, $closingBracket - 1);
380 $tail = \substr($host, $closingBracket + 1);
381
382 if (
383 ($tail === '' || ($stripPort && \preg_match('/^:\d+$/', $tail)))
384 && \filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)
385 ) {
386 return \strtolower($address);
387 }
388 }
389 }
390
391 if (\filter_var($host, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
392 return \strtolower($host);
393 }
394
395 if ($stripPort) {
396 [$host] = \explode(':', $host, 2);
397 }
398
399 return $host;
400 }
401
402 /**
403 * @return array{0: string, 1: int|null}
404 */
405 private static function splitNoProxyHostAndPort(string $area): array
406 {
407 if ($area !== '' && $area[0] === '[') {
408 $closingBracket = \strpos($area, ']');
409
410 if ($closingBracket !== false) {
411 $tail = \substr($area, $closingBracket + 1);
412 if ($tail !== '' && $tail[0] === ':') {
413 $port = self::parseNoProxyPort(\substr($tail, 1));
414
415 if ($port !== null) {
416 return [\substr($area, 0, $closingBracket + 1), $port];
417 }
418 }
419 }
420
421 return [$area, null];
422 }
423
424 if (\filter_var($area, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
425 return [$area, null];
426 }
427
428 $colon = \strrpos($area, ':');
429 if ($colon === false) {
430 return [$area, null];
431 }
432
433 $port = self::parseNoProxyPort(\substr($area, $colon + 1));
434 if ($port === null) {
435 return [$area, null];
436 }
437
438 return [\substr($area, 0, $colon), $port];
439 }
440
441 private static function parseNoProxyPort(string $port): ?int
442 {
443 if ($port === '' || !\ctype_digit($port)) {
444 return null;
445 }
446
447 $port = (int) $port;
448
449 return $port <= 65535 ? $port : null;
450 }
451
452 private static function getDefaultPort(string $scheme): ?int
453 {
454 if ($scheme === 'http') {
455 return 80;
456 }
457
458 if ($scheme === 'https') {
459 return 443;
460 }
461
462 return null;
463 }
464
465 /**
466 * Wrapper for json_decode that throws when an error occurs.
467 *
468 * @param string $json JSON data to parse
469 * @param bool $assoc When true, returned objects will be converted
470 * into associative arrays.
471 * @param int $depth User specified recursion depth.
472 * @param int $options Bitmask of JSON decode options.
473 *
474 * @return object|array|string|int|float|bool|null
475 *
476 * @throws InvalidArgumentException if the JSON cannot be decoded.
477 *
478 * @see https://www.php.net/manual/en/function.json-decode.php
479 */
480 public static function jsonDecode(string $json, bool $assoc = false, int $depth = 512, int $options = 0)
481 {
482 if ($depth < 1) {
483 throw new InvalidArgumentException('json_decode error: Maximum stack depth exceeded');
484 }
485
486 $data = \json_decode($json, $assoc, $depth, $options);
487 if (\JSON_ERROR_NONE !== \json_last_error()) {
488 throw new InvalidArgumentException('json_decode error: '.\json_last_error_msg());
489 }
490
491 return $data;
492 }
493
494 /**
495 * Wrapper for JSON encoding that throws when an error occurs.
496 *
497 * @param mixed $value The value being encoded
498 * @param int $options JSON encode option bitmask
499 * @param int $depth Set the maximum depth. Must be greater than zero.
500 *
501 * @throws InvalidArgumentException if the JSON cannot be encoded.
502 *
503 * @see https://www.php.net/manual/en/function.json-encode.php
504 */
505 public static function jsonEncode($value, int $options = 0, int $depth = 512): string
506 {
507 $json = \json_encode($value, $options, $depth);
508 if (\JSON_ERROR_NONE !== \json_last_error()) {
509 throw new InvalidArgumentException('json_encode error: '.\json_last_error_msg());
510 }
511
512 /** @var string */
513 return $json;
514 }
515
516 /**
517 * Wrapper for the hrtime() or microtime() functions
518 * (depending on the PHP version, one of the two is used)
519 *
520 * @return float UNIX timestamp
521 *
522 * @internal
523 */
524 public static function currentTime(): float
525 {
526 return (float) \function_exists('hrtime') ? \hrtime(true) / 1e9 : \microtime(true);
527 }
528
529 /**
530 * @param mixed $value
531 *
532 * @internal
533 */
534 public static function normalizeIdnConversionOption($value): ?int
535 {
536 if ($value === null || $value === false) {
537 return null;
538 }
539
540 if ($value === true) {
541 return \IDNA_DEFAULT;
542 }
543
544 if (\is_int($value)) {
545 return $value;
546 }
547
548 if ((\is_string($value) && \is_numeric($value)) || (\is_float($value) && \is_finite($value))) {
549 \trigger_deprecation(
550 'guzzlehttp/guzzle',
551 '7.11',
552 'Passing %s as the "idn_conversion" request option is deprecated; guzzlehttp/guzzle 8.0 will reject values that are not true, false, null, or an integer IDNA_* bitmask.',
553 self::describeType($value)
554 );
555
556 return (int) $value;
557 }
558
559 throw new InvalidArgumentException('idn_conversion must be true, false, null, or an integer IDNA_* bitmask');
560 }
561
562 /**
563 * @throws InvalidArgumentException
564 *
565 * @internal
566 */
567 public static function idnUriConvert(UriInterface $uri, int $options = 0): UriInterface
568 {
569 if ($uri->getHost()) {
570 $asciiHost = self::idnToAsci($uri->getHost(), $options, $info);
571 if ($asciiHost === false) {
572 $errorBitSet = $info['errors'] ?? 0;
573
574 $errorConstants = array_filter(array_keys(get_defined_constants()), static function (string $name): bool {
575 return substr($name, 0, 11) === 'IDNA_ERROR_';
576 });
577
578 $errors = [];
579 foreach ($errorConstants as $errorConstant) {
580 if ($errorBitSet & constant($errorConstant)) {
581 $errors[] = $errorConstant;
582 }
583 }
584
585 $errorMessage = 'IDN conversion failed';
586 if ($errors) {
587 $errorMessage .= ' (errors: '.implode(', ', $errors).')';
588 }
589
590 throw new InvalidArgumentException($errorMessage);
591 }
592 if ($uri->getHost() !== $asciiHost) {
593 // Replace URI only if the ASCII version is different
594 $uri = $uri->withHost($asciiHost);
595 }
596 }
597
598 return $uri;
599 }
600
601 /**
602 * @internal
603 */
604 public static function getenv(string $name): ?string
605 {
606 if (isset($_SERVER[$name])) {
607 return (string) $_SERVER[$name];
608 }
609
610 if (\PHP_SAPI === 'cli' && ($value = \getenv($name)) !== false && $value !== null) {
611 return (string) $value;
612 }
613
614 return null;
615 }
616
617 /**
618 * @return string|false
619 */
620 private static function idnToAsci(string $domain, int $options, ?array &$info = [])
621 {
622 if (\function_exists('idn_to_ascii') && \defined('INTL_IDNA_VARIANT_UTS46')) {
623 return \idn_to_ascii($domain, $options, \INTL_IDNA_VARIANT_UTS46, $info);
624 }
625
626 throw new \Error('ext-idn or symfony/polyfill-intl-idn not loaded or too old');
627 }
628 }
629