File Manager Lite
Dir:
/home/codewavebd/public_html/vendor/guzzlehttp/uri-template/src
Upload
[..]
UriTemplate.php (10.58 KB)
Edit
Rename
Del
Edit: UriTemplate.php
<?php declare(strict_types=1); namespace GuzzleHttp\UriTemplate; /** * Expands URI templates. Userland implementation of PECL uri_template. * * @see https://datatracker.ietf.org/doc/html/rfc6570 */ final class UriTemplate { /** * @var array<string, array{prefix:string, joiner:string, query:bool}> Hash for quick operator lookups */ private static $operatorHash = [ '' => ['prefix' => '', 'joiner' => ',', 'query' => false], '+' => ['prefix' => '', 'joiner' => ',', 'query' => false], '#' => ['prefix' => '#', 'joiner' => ',', 'query' => false], '.' => ['prefix' => '.', 'joiner' => '.', 'query' => false], '/' => ['prefix' => '/', 'joiner' => '/', 'query' => false], ';' => ['prefix' => ';', 'joiner' => ';', 'query' => true], '?' => ['prefix' => '?', 'joiner' => '&', 'query' => true], '&' => ['prefix' => '&', 'joiner' => '&', 'query' => true], ]; /** * @param array<string,mixed> $variables Variables to use in the template expansion * * @throws \RuntimeException */ public static function expand(string $template, array $variables): string { if (false === \strpos($template, '{')) { return $template; } /** @var string|null */ $result = \preg_replace_callback( '/\{([^\}]+)\}/', self::expandMatchCallback($variables), $template ); if (null === $result) { throw new \RuntimeException(\sprintf('Unable to process template: %s', \preg_last_error_msg())); } return $result; } /** * @param array<string,mixed> $variables Variables to use in the template expansion * * @return callable(string[]): string */ private static function expandMatchCallback(array $variables): callable { return static function (array $matches) use ($variables): string { return self::expandMatch($matches, $variables); }; } /** * Process an expansion * * @param array<string,mixed> $variables Variables to use in the template expansion * @param string[] $matches Matches met in the preg_replace_callback * * @return string Returns the replacement string */ private static function expandMatch(array $matches, array $variables): string { $replacements = []; $parsed = self::parseExpression($matches[1]); $prefix = self::$operatorHash[$parsed['operator']]['prefix']; $joiner = self::$operatorHash[$parsed['operator']]['joiner']; $useQuery = self::$operatorHash[$parsed['operator']]['query']; $allowReserved = $parsed['operator'] === '+' || $parsed['operator'] === '#'; $hasDefinedVariable = false; foreach ($parsed['values'] as $value) { if (!isset($variables[$value['value']])) { continue; } $variable = $variables[$value['value']]; $actuallyUseQuery = $useQuery; $expanded = ''; if (\is_array($variable)) { $isAssoc = self::isAssoc($variable); $kvp = []; /** @var mixed $var */ foreach ($variable as $key => $var) { if ($isAssoc) { $rawKey = (string) $key; $key = \rawurlencode($rawKey); $isNestedArray = \is_array($var); } else { $isNestedArray = false; } if (!$isNestedArray) { $var = self::encodeValue(self::stringifyValue($var), $allowReserved); } if ($value['modifier'] === '*') { if ($isAssoc) { if ($isNestedArray) { // Nested arrays must allow for deeply nested structures. $var = \http_build_query([$rawKey => self::stringifyNonFiniteFloats($var)], '', '&', \PHP_QUERY_RFC3986); if ($var === '') { continue; } } else { $var = \sprintf('%s=%s', (string) $key, (string) $var); } } elseif ($key > 0 && $actuallyUseQuery) { $var = \sprintf('%s=%s', $value['value'], (string) $var); } } /** @var string $var */ $kvp[$key] = $var; } if ($kvp === []) { continue; } elseif ($value['modifier'] === '*') { $expanded = \implode($joiner, $kvp); if ($isAssoc) { // Don't prepend the value name when using the explode // modifier with an associative array. $actuallyUseQuery = false; } } else { if ($isAssoc) { // When an associative array is encountered and the // explode modifier is not set, then the result must be // a comma separated list of keys followed by their // respective values. foreach ($kvp as $k => &$v) { $v = \sprintf('%s,%s', $k, $v); } } $expanded = \implode(',', $kvp); } } else { $variable = self::stringifyValue($variable); if ($value['modifier'] === ':' && isset($value['position'])) { $variable = \substr($variable, 0, $value['position']); } $expanded = self::encodeValue($variable, $allowReserved); } if ($actuallyUseQuery) { if ($expanded === '' && $joiner !== '&') { $expanded = $value['value']; } else { $expanded = \sprintf('%s=%s', $value['value'], $expanded); } } $hasDefinedVariable = true; $replacements[] = $expanded; } $ret = \implode($joiner, $replacements); // Spec section 3.2.1 and appendix A: the operator's first string is // appended once any variable in the expression is defined, even when // every defined value expands to an empty string. if ('' !== $prefix && $hasDefinedVariable) { return \sprintf('%s%s', $prefix, $ret); } return $ret; } /** * Parse an expression into parts * * @param string $expression Expression to parse * * @return array{operator:string, values:array<array{value:string, modifier:(''|'*'|':'), position?:int}>} */ private static function parseExpression(string $expression): array { $result = []; if (isset(self::$operatorHash[$expression[0]])) { $result['operator'] = $expression[0]; /** @var string */ $expression = \substr($expression, 1); } else { $result['operator'] = ''; } $result['values'] = []; foreach (\explode(',', $expression) as $value) { $value = \trim($value); $varspec = []; if ($colonPos = \strpos($value, ':')) { $varspec['value'] = (string) \substr($value, 0, $colonPos); $varspec['modifier'] = ':'; $varspec['position'] = (int) \substr($value, $colonPos + 1); } elseif (\substr($value, -1) === '*') { $varspec['modifier'] = '*'; $varspec['value'] = (string) \substr($value, 0, -1); } else { $varspec['value'] = $value; $varspec['modifier'] = ''; } $result['values'][] = $varspec; } return $result; } /** * Determines if an array is associative. * * This makes the assumption that input arrays are sequences or hashes. * This assumption is a tradeoff for accuracy in favor of speed, but it * should work in almost every case where input is supplied for a URI * template. */ private static function isAssoc(array $array): bool { return $array && \array_keys($array)[0] !== 0; } /** * Cast a variable value to its expansion string. * * Non-finite floats are converted explicitly because coercing them to * string triggers a warning on PHP 8.5. * * @param mixed $value */ private static function stringifyValue($value): string { if (\is_float($value) && !\is_finite($value)) { return \is_nan($value) ? 'NAN' : ($value > 0 ? 'INF' : '-INF'); } return (string) $value; } /** * Stringify non-finite float members of a nested array so that * http_build_query does not trigger coercion warnings on PHP 8.5. * * @param array<array-key,mixed> $value * * @return array<array-key,mixed> */ private static function stringifyNonFiniteFloats(array $value): array { /** @var mixed $member */ foreach ($value as $key => $member) { if (\is_float($member) && !\is_finite($member)) { $value[$key] = self::stringifyValue($member); } elseif (\is_array($member)) { $value[$key] = self::stringifyNonFiniteFloats($member); } } return $value; } private static function encodeValue(string $value, bool $allowReserved): string { if ($value === '') { return ''; } $matches = []; if (\preg_match_all('/%[0-9A-Fa-f]{2}|./s', $value, $matches) === false) { throw new \RuntimeException('Unable to encode URI template value.'); } $encoded = ''; foreach ($matches[0] as $token) { if ($allowReserved && \preg_match('/\A%[0-9A-Fa-f]{2}\z/', $token) === 1) { $encoded .= $token; continue; } if (\preg_match('/\A[A-Za-z0-9._~-]\z/', $token) === 1) { $encoded .= $token; continue; } if ($allowReserved && \strlen($token) === 1 && \strpos(":/?#[]@!$&'()*+,;=", $token) !== false) { $encoded .= $token; continue; } $encoded .= \rawurlencode($token); } return $encoded; } }
Simpan