allow vendord
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 16s
Build, Push and Deploy / deploy-staging (push) Successful in 32s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 1s
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 16s
Build, Push and Deploy / deploy-staging (push) Successful in 32s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 1s
This commit is contained in:
98
vendor/rize/uri-template/src/Rize/UriTemplate.php
vendored
Normal file
98
vendor/rize/uri-template/src/Rize/UriTemplate.php
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Rize;
|
||||
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
/**
|
||||
* URI Template.
|
||||
*/
|
||||
class UriTemplate
|
||||
{
|
||||
protected Parser $parser;
|
||||
protected array $parsed = [];
|
||||
|
||||
public function __construct(protected string $base_uri = '', protected array $params = [], ?Parser $parser = null)
|
||||
{
|
||||
$this->parser = $parser ?: $this->createNodeParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands URI Template.
|
||||
*
|
||||
* @param mixed $params
|
||||
*/
|
||||
public function expand(string $uri, $params = []): string
|
||||
{
|
||||
$params += $this->params;
|
||||
$uri = $this->base_uri . $uri;
|
||||
$result = [];
|
||||
|
||||
// quick check
|
||||
if (!str_contains($uri, '{')) {
|
||||
return $uri;
|
||||
}
|
||||
|
||||
$parser = $this->parser;
|
||||
$nodes = $parser->parse($uri);
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
$result[] = $node->expand($parser, $params);
|
||||
}
|
||||
|
||||
return implode('', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts variables from URI.
|
||||
*
|
||||
* @return null|array params or null if not match and $strict is true
|
||||
*/
|
||||
public function extract(string $template, string $uri, bool $strict = false): ?array
|
||||
{
|
||||
$params = [];
|
||||
$nodes = $this->parser->parse($template);
|
||||
|
||||
// PHP 8.1.0RC4-dev still throws deprecation warning for `strlen`.
|
||||
// $uri = (string) $uri;
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
// if strict is given, and there's no remaining uri just return null
|
||||
if ($strict && (string) $uri === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// URI will be truncated from the start when a match is found
|
||||
$match = $node->match($this->parser, $uri, $params, $strict);
|
||||
|
||||
if ($match === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
[$uri, $params] = $match;
|
||||
}
|
||||
|
||||
// if there's remaining $uri, matching is failed
|
||||
if ($strict && (string) $uri !== '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
public function getParser(): Parser
|
||||
{
|
||||
return $this->parser;
|
||||
}
|
||||
|
||||
protected function createNodeParser(): Parser
|
||||
{
|
||||
static $parser;
|
||||
|
||||
if ($parser) {
|
||||
return $parser;
|
||||
}
|
||||
|
||||
return $parser = new Parser();
|
||||
}
|
||||
}
|
||||
50
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Abstraction.php
vendored
Normal file
50
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Abstraction.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Node;
|
||||
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
/**
|
||||
* Base class for all Nodes.
|
||||
*/
|
||||
abstract class Abstraction
|
||||
{
|
||||
public function __construct(private readonly string $token) {}
|
||||
|
||||
/**
|
||||
* Expands URI template
|
||||
*
|
||||
* @param array<string, mixed> $params
|
||||
*/
|
||||
public function expand(Parser $parser, array $params = []): ?string
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches given URI against current node.
|
||||
*
|
||||
* @param array<string, mixed> $params
|
||||
*
|
||||
* @return null|array{0: string, 1: array<string, mixed>} `uri and params` or `null` if not match and $strict is true
|
||||
*/
|
||||
public function match(Parser $parser, string $uri, array $params = [], bool $strict = false): ?array
|
||||
{
|
||||
// match literal string from start to end
|
||||
if (str_starts_with($uri, $this->token)) {
|
||||
$uri = substr($uri, strlen($this->token));
|
||||
}
|
||||
|
||||
// when there's no match, just return null if strict mode is given
|
||||
elseif ($strict) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [$uri, $params];
|
||||
}
|
||||
|
||||
public function getToken(): string
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
}
|
||||
124
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Expression.php
vendored
Normal file
124
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Expression.php
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Node;
|
||||
|
||||
use Rize\UriTemplate\Operator;
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
class Expression extends Abstraction
|
||||
{
|
||||
/**
|
||||
* @param string $forwardLookupSeparator
|
||||
*/
|
||||
public function __construct(string $token, private readonly Operator\Abstraction $operator, private readonly ?array $variables = null, /**
|
||||
* Whether to do a forward lookup for a given separator.
|
||||
*/
|
||||
private $forwardLookupSeparator = null)
|
||||
{
|
||||
parent::__construct($token);
|
||||
}
|
||||
|
||||
public function getOperator(): Operator\Abstraction
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
|
||||
public function getVariables(): ?array
|
||||
{
|
||||
return $this->variables;
|
||||
}
|
||||
|
||||
public function getForwardLookupSeparator(): string
|
||||
{
|
||||
return $this->forwardLookupSeparator;
|
||||
}
|
||||
|
||||
public function setForwardLookupSeparator(string $forwardLookupSeparator): void
|
||||
{
|
||||
$this->forwardLookupSeparator = $forwardLookupSeparator;
|
||||
}
|
||||
|
||||
public function expand(Parser $parser, array $params = []): ?string
|
||||
{
|
||||
$data = [];
|
||||
$op = $this->operator;
|
||||
|
||||
if ($this->variables === null) {
|
||||
return $op->first;
|
||||
}
|
||||
|
||||
// check for variable modifiers
|
||||
foreach ($this->variables as $var) {
|
||||
$val = $op->expand($parser, $var, $params);
|
||||
|
||||
// skip null value
|
||||
if (!is_null($val)) {
|
||||
$data[] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $data ? $op->first . implode($op->sep, $data) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches given URI against current node.
|
||||
*
|
||||
* @return null|array `uri and params` or `null` if not match and $strict is true
|
||||
*/
|
||||
public function match(Parser $parser, string $uri, array $params = [], bool $strict = false): ?array
|
||||
{
|
||||
$op = $this->operator;
|
||||
|
||||
// check expression operator first
|
||||
if ($op->id && isset($uri[0]) && $uri[0] !== $op->id) {
|
||||
return [$uri, $params];
|
||||
}
|
||||
|
||||
// remove operator from input
|
||||
if ($op->id) {
|
||||
$uri = substr($uri, 1);
|
||||
}
|
||||
|
||||
foreach ($this->sortVariables($this->variables) as $var) {
|
||||
$regex = '#' . $op->toRegex($parser, $var) . '#';
|
||||
$val = null;
|
||||
|
||||
// do a forward lookup and get just the relevant part
|
||||
$remainingUri = '';
|
||||
$preparedUri = $uri;
|
||||
if ($this->forwardLookupSeparator) {
|
||||
$lastOccurrenceOfSeparator = stripos($uri, $this->forwardLookupSeparator);
|
||||
$preparedUri = substr($uri, 0, $lastOccurrenceOfSeparator);
|
||||
$remainingUri = substr($uri, $lastOccurrenceOfSeparator);
|
||||
}
|
||||
|
||||
if (preg_match($regex, $preparedUri, $match)) {
|
||||
// remove matched part from input
|
||||
$preparedUri = preg_replace($regex, '', $preparedUri, 1);
|
||||
$val = $op->extract($parser, $var, $match[0]);
|
||||
}
|
||||
|
||||
// if strict is given, we quit immediately when there's no match
|
||||
elseif ($strict) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$uri = $preparedUri . $remainingUri;
|
||||
|
||||
$params[$var->getToken()] = $val;
|
||||
}
|
||||
|
||||
return [$uri, $params];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort variables before extracting data from uri.
|
||||
* We have to sort vars by non-explode to explode.
|
||||
*/
|
||||
protected function sortVariables(array $vars): array
|
||||
{
|
||||
usort($vars, static fn($a, $b) => $a->options['modifier'] <=> $b->options['modifier']);
|
||||
|
||||
return $vars;
|
||||
}
|
||||
}
|
||||
5
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Literal.php
vendored
Normal file
5
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Literal.php
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Node;
|
||||
|
||||
class Literal extends Abstraction {}
|
||||
27
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Variable.php
vendored
Normal file
27
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Variable.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Node;
|
||||
|
||||
class Variable extends Abstraction
|
||||
{
|
||||
/**
|
||||
* Variable name without modifier
|
||||
* e.g. 'term:1' becomes 'term'.
|
||||
*/
|
||||
public string $name;
|
||||
public array $options = ['modifier' => null, 'value' => null];
|
||||
|
||||
public function __construct(string $token, array $options = [])
|
||||
{
|
||||
parent::__construct($token);
|
||||
$this->options = $options + $this->options;
|
||||
|
||||
// normalize var name e.g. from 'term:1' becomes 'term'
|
||||
$name = $token;
|
||||
if ($options['modifier'] === ':') {
|
||||
$name = strstr($name, $options['modifier'], true);
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
373
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/Abstraction.php
vendored
Normal file
373
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/Abstraction.php
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Operator;
|
||||
|
||||
use Rize\UriTemplate\Node;
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
/**
|
||||
* .------------------------------------------------------------------.
|
||||
* | NUL + . / ; ? & # |
|
||||
* |------------------------------------------------------------------|
|
||||
* | first | "" "" "." "/" ";" "?" "&" "#" |
|
||||
* | sep | "," "," "." "/" ";" "&" "&" "," |
|
||||
* | named | false false false false true true true false |
|
||||
* | ifemp | "" "" "" "" "" "=" "=" "" |
|
||||
* | allow | U U+R U U U U U U+R |
|
||||
* `------------------------------------------------------------------'.
|
||||
*
|
||||
* named = false
|
||||
* | 1 | {/list} /red,green,blue | {$value}*(?:,{$value}+)*
|
||||
* | 2 | {/list*} /red/green/blue | {$value}+(?:{$sep}{$value}+)*
|
||||
* | 3 | {/keys} /semi,%3B,dot,.,comma,%2C | /(\w+,?)+
|
||||
* | 4 | {/keys*} /semi=%3B/dot=./comma=%2C | /(?:\w+=\w+/?)*
|
||||
* named = true
|
||||
* | 1 | {?list} ?list=red,green,blue | {name}=(?:\w+(?:,\w+?)*)*
|
||||
* | 2 | {?list*} ?list=red&list=green&list=blue | {name}+=(?:{$value}+(?:{sep}{name}+={$value}*))*
|
||||
* | 3 | {?keys} ?keys=semi,%3B,dot,.,comma,%2C | (same as 1)
|
||||
* | 4 | {?keys*} ?semi=%3B&dot=.&comma=%2C | (same as 2)
|
||||
*
|
||||
* UNRESERVED
|
||||
* ----------
|
||||
* RFC 1738 ALPHA | DIGIT | "-" | "." | "_" | | "$" | "+" | "!" | "*" | "'" | "(" | ")" | ","
|
||||
* RFC 3986 ALPHA | DIGIT | "-" | "." | "_" | "~"
|
||||
* RFC 6570 ALPHA | DIGIT | "-" | "." | "_" | "~"
|
||||
*
|
||||
* RESERVED
|
||||
* --------
|
||||
* RFC 1738 ":" | "/" | "?" | | "@" | "!" | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "=" | "-" | "_" | "." |
|
||||
* RFC 3986 ":" | "/" | "?" | "#" | "[" | "]" | "@" | "!" | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "="
|
||||
* RFC 6570 ":" | "/" | "?" | "#" | "[" | "]" | "@" | "!" | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "="
|
||||
*
|
||||
* PHP_QUERY_RFC3986 was added in PHP 5.4.0
|
||||
*/
|
||||
abstract class Abstraction
|
||||
{
|
||||
/**
|
||||
* start - Variable offset position, level-2 operators start at 1
|
||||
* (exclude operator itself, e.g. {?query})
|
||||
* first - If variables found, prepend this value to it
|
||||
* named - Whether the expansion includes the variable or key name
|
||||
* reserved - union of (unreserved / reserved / pct-encoded).
|
||||
*/
|
||||
public $id;
|
||||
public $named;
|
||||
public $sep;
|
||||
public $empty;
|
||||
public $reserved;
|
||||
public $start;
|
||||
public $first;
|
||||
|
||||
/**
|
||||
* gen-delims | sub-delims.
|
||||
*/
|
||||
public static $reserved_chars = [
|
||||
'%3A' => ':',
|
||||
'%2F' => '/',
|
||||
'%3F' => '?',
|
||||
'%23' => '#',
|
||||
'%5B' => '[',
|
||||
'%5D' => ']',
|
||||
'%40' => '@',
|
||||
'%21' => '!',
|
||||
'%24' => '$',
|
||||
'%26' => '&',
|
||||
'%27' => "'",
|
||||
'%28' => '(',
|
||||
'%29' => ')',
|
||||
'%2A' => '*',
|
||||
'%2B' => '+',
|
||||
'%2C' => ',',
|
||||
'%3B' => ';',
|
||||
'%3D' => '=',
|
||||
];
|
||||
|
||||
protected static $types = [
|
||||
'' => [
|
||||
'sep' => ',',
|
||||
'named' => false,
|
||||
'empty' => '',
|
||||
'reserved' => false,
|
||||
'start' => 0,
|
||||
'first' => null,
|
||||
],
|
||||
'+' => [
|
||||
'sep' => ',',
|
||||
'named' => false,
|
||||
'empty' => '',
|
||||
'reserved' => true,
|
||||
'start' => 1,
|
||||
'first' => null,
|
||||
],
|
||||
'.' => [
|
||||
'sep' => '.',
|
||||
'named' => false,
|
||||
'empty' => '',
|
||||
'reserved' => false,
|
||||
'start' => 1,
|
||||
'first' => '.',
|
||||
],
|
||||
'/' => [
|
||||
'sep' => '/',
|
||||
'named' => false,
|
||||
'empty' => '',
|
||||
'reserved' => false,
|
||||
'start' => 1,
|
||||
'first' => '/',
|
||||
],
|
||||
';' => [
|
||||
'sep' => ';',
|
||||
'named' => true,
|
||||
'empty' => '',
|
||||
'reserved' => false,
|
||||
'start' => 1,
|
||||
'first' => ';',
|
||||
],
|
||||
'?' => [
|
||||
'sep' => '&',
|
||||
'named' => true,
|
||||
'empty' => '=',
|
||||
'reserved' => false,
|
||||
'start' => 1,
|
||||
'first' => '?',
|
||||
],
|
||||
'&' => [
|
||||
'sep' => '&',
|
||||
'named' => true,
|
||||
'empty' => '=',
|
||||
'reserved' => false,
|
||||
'start' => 1,
|
||||
'first' => '&',
|
||||
],
|
||||
'#' => [
|
||||
'sep' => ',',
|
||||
'named' => false,
|
||||
'empty' => '',
|
||||
'reserved' => true,
|
||||
'start' => 1,
|
||||
'first' => '#',
|
||||
],
|
||||
];
|
||||
|
||||
protected static $loaded = [];
|
||||
|
||||
/**
|
||||
* RFC 3986 Allowed path characters regex except the path delimiter '/'.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $pathRegex = '(?:[a-zA-Z0-9\-\._~!\$&\'\(\)\*\+,;=%:@]+|%(?![A-Fa-f0-9]{2}))';
|
||||
|
||||
/**
|
||||
* RFC 3986 Allowed query characters regex except the query parameter delimiter '&'.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $queryRegex = '(?:[a-zA-Z0-9\-\._~!\$\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))';
|
||||
|
||||
public function __construct($id, $named, $sep, $empty, $reserved, $start, $first)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->named = $named;
|
||||
$this->sep = $sep;
|
||||
$this->empty = $empty;
|
||||
$this->start = $start;
|
||||
$this->first = $first;
|
||||
$this->reserved = $reserved;
|
||||
}
|
||||
|
||||
abstract public function toRegex(Parser $parser, Node\Variable $var): string;
|
||||
|
||||
public function expand(Parser $parser, Node\Variable $var, array $params = [])
|
||||
{
|
||||
$options = $var->options;
|
||||
$name = $var->name;
|
||||
$is_explode = in_array($options['modifier'], ['*', '%']);
|
||||
|
||||
// skip null
|
||||
if (!isset($params[$name])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$val = $params[$name];
|
||||
|
||||
// This algorithm is based on RFC6570 http://tools.ietf.org/html/rfc6570
|
||||
// non-array, e.g. string
|
||||
if (!is_array($val)) {
|
||||
return $this->expandString($parser, $var, $val);
|
||||
}
|
||||
|
||||
// non-explode ':'
|
||||
if (!$is_explode) {
|
||||
return $this->expandNonExplode($parser, $var, $val);
|
||||
}
|
||||
|
||||
// explode '*', '%'
|
||||
|
||||
return $this->expandExplode($parser, $var, $val);
|
||||
}
|
||||
|
||||
public function expandString(Parser $parser, Node\Variable $var, $val)
|
||||
{
|
||||
$val = (string) $val;
|
||||
$options = $var->options;
|
||||
$result = null;
|
||||
|
||||
if ($options['modifier'] === ':') {
|
||||
$val = substr($val, 0, (int) $options['value']);
|
||||
}
|
||||
|
||||
return $result . $this->encode($parser, $var, $val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Non explode modifier ':'.
|
||||
*/
|
||||
public function expandNonExplode(Parser $parser, Node\Variable $var, array $val): ?string
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->encode($parser, $var, $val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode modifier '*', '%'.
|
||||
*/
|
||||
public function expandExplode(Parser $parser, Node\Variable $var, array $val): ?string
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->encode($parser, $var, $val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes variable according to spec (reserved or unreserved).
|
||||
*
|
||||
* @return string encoded string
|
||||
*/
|
||||
public function encode(Parser $parser, Node\Variable $var, mixed $values)
|
||||
{
|
||||
$values = (array) $values;
|
||||
$list = isset($values[0]);
|
||||
$reserved = $this->reserved;
|
||||
$maps = static::$reserved_chars;
|
||||
$sep = $this->sep;
|
||||
$assoc_sep = '=';
|
||||
|
||||
// non-explode modifier always use ',' as a separator
|
||||
if ($var->options['modifier'] !== '*') {
|
||||
$assoc_sep = $sep = ',';
|
||||
}
|
||||
|
||||
array_walk($values, function (&$v, $k) use ($assoc_sep, $reserved, $list, $maps): void {
|
||||
$encoded = rawurlencode($v);
|
||||
|
||||
// assoc? encode key too
|
||||
if (!$list) {
|
||||
$encoded = rawurlencode($k) . $assoc_sep . $encoded;
|
||||
}
|
||||
|
||||
// rawurlencode is compliant with 'unreserved' set
|
||||
if (!$reserved) {
|
||||
$v = $encoded;
|
||||
}
|
||||
|
||||
// decode chars in reserved set
|
||||
else {
|
||||
$v = str_replace(
|
||||
array_keys($maps),
|
||||
$maps,
|
||||
$encoded,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return implode($sep, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes variable.
|
||||
*
|
||||
* @return string decoded string
|
||||
*/
|
||||
public function decode(Parser $parser, Node\Variable $var, mixed $values)
|
||||
{
|
||||
$single = !is_array($values);
|
||||
$values = (array) $values;
|
||||
|
||||
array_walk($values, function (&$v, $k): void {
|
||||
$v = rawurldecode($v);
|
||||
});
|
||||
|
||||
return $single ? reset($values) : $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts value from variable.
|
||||
*/
|
||||
public function extract(Parser $parser, Node\Variable $var, string $data): array|string
|
||||
{
|
||||
$value = $data;
|
||||
$vals = array_filter(explode($this->sep, $data));
|
||||
$options = $var->options;
|
||||
|
||||
switch ($options['modifier']) {
|
||||
case '*':
|
||||
$value = [];
|
||||
foreach ($vals as $val) {
|
||||
if (str_contains($val, '=')) {
|
||||
[$k, $v] = explode('=', $val);
|
||||
$value[$k] = $v;
|
||||
} else {
|
||||
$value[] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ':':
|
||||
break;
|
||||
|
||||
default:
|
||||
$value = str_contains($value, (string) $this->sep) ? $vals : $value;
|
||||
}
|
||||
|
||||
return $this->decode($parser, $var, $value);
|
||||
}
|
||||
|
||||
public static function createById($id)
|
||||
{
|
||||
if (!isset(static::$types[$id])) {
|
||||
throw new \InvalidArgumentException("Invalid operator [{$id}]");
|
||||
}
|
||||
|
||||
if (isset(static::$loaded[$id])) {
|
||||
return static::$loaded[$id];
|
||||
}
|
||||
|
||||
$op = static::$types[$id];
|
||||
$class = __NAMESPACE__ . '\\' . ($op['named'] ? 'Named' : 'UnNamed');
|
||||
|
||||
return static::$loaded[$id] = new $class($id, $op['named'], $op['sep'], $op['empty'], $op['reserved'], $op['start'], $op['first']);
|
||||
}
|
||||
|
||||
public static function isValid($id): bool
|
||||
{
|
||||
return isset(static::$types[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the correct regex given the variable location in the URI.
|
||||
*/
|
||||
protected function getRegex(): string
|
||||
{
|
||||
return match ($this->id) {
|
||||
'?', '&', '#' => self::$queryRegex,
|
||||
default => self::$pathRegex,
|
||||
};
|
||||
}
|
||||
}
|
||||
202
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/Named.php
vendored
Normal file
202
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/Named.php
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Operator;
|
||||
|
||||
use Rize\UriTemplate\Node;
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
/**
|
||||
* | 1 | {?list} ?list=red,green,blue | {name}=(?:\w+(?:,\w+?)*)*
|
||||
* | 2 | {?list*} ?list=red&list=green&list=blue | {name}+=(?:{$value}+(?:{sep}{name}+={$value}*))*
|
||||
* | 3 | {?keys} ?keys=semi,%3B,dot,.,comma,%2C | (same as 1)
|
||||
* | 4 | {?keys*} ?semi=%3B&dot=.&comma=%2C | (same as 2)
|
||||
* | 5 | {?list*} ?list[]=red&list[]=green&list[]=blue | {name[]}+=(?:{$value}+(?:{sep}{name[]}+={$value}*))*.
|
||||
*/
|
||||
class Named extends Abstraction
|
||||
{
|
||||
public function toRegex(Parser $parser, Node\Variable $var): string
|
||||
{
|
||||
$name = $var->name;
|
||||
$value = $this->getRegex();
|
||||
$options = $var->options;
|
||||
|
||||
if ($options['modifier']) {
|
||||
switch ($options['modifier']) {
|
||||
case '*':
|
||||
// 2 | 4
|
||||
$regex = "{$name}+=(?:{$value}+(?:{$this->sep}{$name}+={$value}*)*)"
|
||||
. "|{$value}+=(?:{$value}+(?:{$this->sep}{$value}+={$value}*)*)";
|
||||
|
||||
break;
|
||||
|
||||
case ':':
|
||||
$regex = "{$value}\\{0,{$options['value']}\\}";
|
||||
|
||||
break;
|
||||
|
||||
case '%':
|
||||
// 5
|
||||
$name .= '+(?:%5B|\[)[^=]*=';
|
||||
$regex = "{$name}(?:{$value}+(?:{$this->sep}{$name}{$value}*)*)";
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException("Unknown modifier `{$options['modifier']}`");
|
||||
}
|
||||
} else {
|
||||
// 1, 3
|
||||
$regex = "{$name}=(?:{$value}+(?:,{$value}+)*)*";
|
||||
}
|
||||
|
||||
return '(?:&)?' . $regex;
|
||||
}
|
||||
|
||||
public function expandString(Parser $parser, Node\Variable $var, $val): string
|
||||
{
|
||||
$val = (string) $val;
|
||||
$options = $var->options;
|
||||
$result = $this->encode($parser, $var, $var->name);
|
||||
|
||||
// handle empty value
|
||||
if ($val === '') {
|
||||
return $result . $this->empty;
|
||||
}
|
||||
|
||||
$result .= '=';
|
||||
|
||||
if ($options['modifier'] === ':') {
|
||||
$val = mb_substr($val, 0, (int) $options['value']);
|
||||
}
|
||||
|
||||
return $result . $this->encode($parser, $var, $val);
|
||||
}
|
||||
|
||||
public function expandNonExplode(Parser $parser, Node\Variable $var, array $val): ?string
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = $this->encode($parser, $var, $var->name);
|
||||
|
||||
$result .= '=';
|
||||
|
||||
return $result . $this->encode($parser, $var, $val);
|
||||
}
|
||||
|
||||
public function expandExplode(Parser $parser, Node\Variable $var, array $val): ?string
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$list = isset($val[0]);
|
||||
$data = [];
|
||||
foreach ($val as $k => $v) {
|
||||
// if value is a list, use `varname` as keyname, otherwise use `key` name
|
||||
$key = $list ? $var->name : $k;
|
||||
if ($list) {
|
||||
$data[$key][] = $v;
|
||||
} else {
|
||||
$data[$key] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's array modifier, we have to use variable name as index
|
||||
// e.g. if variable name is 'query' and value is ['limit' => 1]
|
||||
// then we convert it to ['query' => ['limit' => 1]]
|
||||
if (!$list && $var->options['modifier'] === '%') {
|
||||
$data = [$var->name => $data];
|
||||
}
|
||||
|
||||
return $this->encodeExplodeVars($var, $data);
|
||||
}
|
||||
|
||||
public function extract(Parser $parser, Node\Variable $var, $data): array|string
|
||||
{
|
||||
// get rid of optional `&` at the beginning
|
||||
if ($data[0] === '&') {
|
||||
$data = substr($data, 1);
|
||||
}
|
||||
|
||||
$value = $data;
|
||||
$vals = explode($this->sep, $data);
|
||||
$options = $var->options;
|
||||
|
||||
switch ($options['modifier']) {
|
||||
case '%':
|
||||
parse_str($value, $query);
|
||||
|
||||
return $query[$var->name];
|
||||
|
||||
case '*':
|
||||
$value = [];
|
||||
|
||||
foreach ($vals as $val) {
|
||||
[$k, $v] = explode('=', $val);
|
||||
|
||||
// 2
|
||||
if ($k === $var->getToken()) {
|
||||
$value[] = $v;
|
||||
}
|
||||
|
||||
// 4
|
||||
else {
|
||||
$value[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ':':
|
||||
break;
|
||||
|
||||
default:
|
||||
// 1, 3
|
||||
// remove key from value e.g. 'lang=en,th' becomes 'en,th'
|
||||
$value = str_replace($var->getToken() . '=', '', $value);
|
||||
$value = explode(',', $value);
|
||||
|
||||
if (count($value) === 1) {
|
||||
$value = current($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->decode($parser, $var, $value);
|
||||
}
|
||||
|
||||
public function encodeExplodeVars(Node\Variable $var, $data): null|array|string
|
||||
{
|
||||
// http_build_query uses PHP_QUERY_RFC1738 encoding by default
|
||||
// i.e. spaces are encoded as '+' (plus signs) we need to convert
|
||||
// it to %20 RFC3986
|
||||
$query = http_build_query($data, '', $this->sep);
|
||||
$query = str_replace('+', '%20', $query);
|
||||
|
||||
// `%` array modifier
|
||||
if ($var->options['modifier'] === '%') {
|
||||
|
||||
// it also uses numeric based-index by default e.g. list[] becomes list[0]
|
||||
$query = preg_replace('#%5B\d+%5D#', '%5B%5D', $query);
|
||||
}
|
||||
|
||||
// `:`, `*` modifiers
|
||||
else {
|
||||
// by default, http_build_query will convert array values to `a[]=1&a[]=2`
|
||||
// which is different from the spec. It should be `a=1&a=2`
|
||||
$query = preg_replace('#%5B\d+%5D#', '', $query);
|
||||
}
|
||||
|
||||
// handle reserved charset
|
||||
if ($this->reserved) {
|
||||
$query = str_replace(
|
||||
array_keys(static::$reserved_chars),
|
||||
static::$reserved_chars,
|
||||
$query,
|
||||
);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
47
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/UnNamed.php
vendored
Normal file
47
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/UnNamed.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Operator;
|
||||
|
||||
use Rize\UriTemplate\Node;
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
/**
|
||||
* | 1 | {/list} /red,green,blue | {$value}*(?:,{$value}+)*
|
||||
* | 2 | {/list*} /red/green/blue | {$value}+(?:{$sep}{$value}+)*
|
||||
* | 3 | {/keys} /semi,%3B,dot,.,comma,%2C | /(\w+,?)+
|
||||
* | 4 | {/keys*} /semi=%3B/dot=./comma=%2C | /(?:\w+=\w+/?)*.
|
||||
*/
|
||||
class UnNamed extends Abstraction
|
||||
{
|
||||
public function toRegex(Parser $parser, Node\Variable $var): string
|
||||
{
|
||||
$value = $this->getRegex();
|
||||
$options = $var->options;
|
||||
|
||||
if ($options['modifier']) {
|
||||
switch ($options['modifier']) {
|
||||
case '*':
|
||||
// 2 | 4
|
||||
$regex = "{$value}+(?:{$this->sep}{$value}+)*";
|
||||
|
||||
break;
|
||||
|
||||
case ':':
|
||||
$regex = $value . '{0,' . $options['value'] . '}';
|
||||
|
||||
break;
|
||||
|
||||
case '%':
|
||||
throw new \InvalidArgumentException('% (array) modifier only works with Named type operators e.g. ;,?,&');
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException("Unknown modifier `{$options['modifier']}`");
|
||||
}
|
||||
} else {
|
||||
// 1, 3
|
||||
$regex = "{$value}*(?:,{$value}+)*";
|
||||
}
|
||||
|
||||
return $regex;
|
||||
}
|
||||
}
|
||||
149
vendor/rize/uri-template/src/Rize/UriTemplate/Parser.php
vendored
Normal file
149
vendor/rize/uri-template/src/Rize/UriTemplate/Parser.php
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate;
|
||||
|
||||
use Rize\UriTemplate\Node\Abstraction;
|
||||
use Rize\UriTemplate\Node\Expression;
|
||||
use Rize\UriTemplate\Node\Variable;
|
||||
use Rize\UriTemplate\Operator\UnNamed;
|
||||
|
||||
class Parser
|
||||
{
|
||||
private const REGEX_VARNAME = '[A-z0-9.]|%[0-9a-fA-F]{2}';
|
||||
|
||||
/**
|
||||
* Parses URI Template and returns nodes.
|
||||
*
|
||||
* @return Node\Abstraction[]
|
||||
*/
|
||||
public function parse(string $template): array
|
||||
{
|
||||
$parts = preg_split('#(\{[^}]+})#', $template, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
$nodes = [];
|
||||
|
||||
foreach ($parts as $part) {
|
||||
$node = $this->createNode($part);
|
||||
|
||||
// if current node has dot separator that requires a forward lookup
|
||||
// for the previous node iff previous node's operator is UnNamed
|
||||
if ($node instanceof Expression && $node->getOperator()->id === '.') {
|
||||
if (count($nodes) > 0) {
|
||||
$previousNode = $nodes[count($nodes) - 1];
|
||||
if ($previousNode instanceof Expression && $previousNode->getOperator() instanceof UnNamed) {
|
||||
$previousNode->setForwardLookupSeparator($node->getOperator()->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$nodes[] = $node;
|
||||
}
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
protected function createNode(string $token): Abstraction
|
||||
{
|
||||
// literal string
|
||||
if ($token[0] !== '{') {
|
||||
$node = $this->createLiteralNode($token);
|
||||
} else {
|
||||
// remove `{}` from expression and parse it
|
||||
$node = $this->parseExpression(substr($token, 1, -1));
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
protected function parseExpression(string $expression): Expression
|
||||
{
|
||||
$token = $expression;
|
||||
$prefix = $token[0];
|
||||
|
||||
// not a valid operator?
|
||||
if (!Operator\Abstraction::isValid($prefix)) {
|
||||
// not valid chars?
|
||||
if (!preg_match('#' . self::REGEX_VARNAME . '#', $token)) {
|
||||
throw new \InvalidArgumentException("Invalid operator [{$prefix}] found at {$token}");
|
||||
}
|
||||
|
||||
// default operator
|
||||
//
|
||||
// PHP 8.5: using null as array offset is deprecated and we no longer rely on auto-casting null to ''.
|
||||
$prefix = '';
|
||||
}
|
||||
|
||||
// remove operator prefix if exists e.g. '?'
|
||||
if ($prefix) {
|
||||
$token = substr($token, 1);
|
||||
}
|
||||
|
||||
// parse variables
|
||||
$vars = [];
|
||||
foreach (explode(',', $token) as $var) {
|
||||
$vars[] = $this->parseVariable($var);
|
||||
}
|
||||
|
||||
return $this->createExpressionNode(
|
||||
$token,
|
||||
$this->createOperatorNode($prefix),
|
||||
$vars,
|
||||
);
|
||||
}
|
||||
|
||||
protected function parseVariable(string $var): Variable
|
||||
{
|
||||
$var = trim($var);
|
||||
$val = null;
|
||||
$modifier = null;
|
||||
|
||||
// check for prefix (:) / explode (*) / array (%) modifier
|
||||
if (str_contains($var, ':')) {
|
||||
$modifier = ':';
|
||||
[$varname, $val] = explode(':', $var);
|
||||
|
||||
// error checking
|
||||
if (!is_numeric($val)) {
|
||||
throw new \InvalidArgumentException("Value for `:` modifier must be numeric value [{$varname}:{$val}]");
|
||||
}
|
||||
}
|
||||
|
||||
switch ($last = substr($var, -1)) {
|
||||
case '*':
|
||||
case '%':
|
||||
// there can be only 1 modifier per var
|
||||
if ($modifier) {
|
||||
throw new \InvalidArgumentException("Multiple modifiers per variable are not allowed [{$var}]");
|
||||
}
|
||||
|
||||
$modifier = $last;
|
||||
$var = substr($var, 0, -1);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return $this->createVariableNode(
|
||||
$var,
|
||||
['modifier' => $modifier, 'value' => $val],
|
||||
);
|
||||
}
|
||||
|
||||
protected function createVariableNode($token, $options = []): Variable
|
||||
{
|
||||
return new Variable($token, $options);
|
||||
}
|
||||
|
||||
protected function createExpressionNode($token, ?Operator\Abstraction $operator = null, array $vars = []): Expression
|
||||
{
|
||||
return new Expression($token, $operator, $vars);
|
||||
}
|
||||
|
||||
protected function createLiteralNode(string $token): Node\Literal
|
||||
{
|
||||
return new Node\Literal($token);
|
||||
}
|
||||
|
||||
protected function createOperatorNode($token): Operator\Abstraction
|
||||
{
|
||||
return Operator\Abstraction::createById($token);
|
||||
}
|
||||
}
|
||||
10
vendor/rize/uri-template/src/Rize/UriTemplate/UriTemplate.php
vendored
Normal file
10
vendor/rize/uri-template/src/Rize/UriTemplate/UriTemplate.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate;
|
||||
|
||||
use Rize\UriTemplate as Template;
|
||||
|
||||
/**
|
||||
* Future compatibility.
|
||||
*/
|
||||
class UriTemplate extends Template {}
|
||||
Reference in New Issue
Block a user