feat: add S3-compatible storage provider (MinIO, Ceph, R2, etc.)
Adds a new 'S3-Compatible Storage' provider that works with any
S3-API-compatible object storage service, including MinIO, Ceph,
Cloudflare R2, Backblaze B2, and others.
Changes:
- New provider class: classes/providers/storage/s3-compatible-provider.php
- Provider key: s3compatible
- Reads user-configured endpoint URL from settings
- Uses path-style URL access (required by most S3-compatible services)
- Supports credentials via AS3CF_S3COMPAT_ACCESS_KEY_ID /
AS3CF_S3COMPAT_SECRET_ACCESS_KEY wp-config.php constants
- Disables AWS-specific features (Block Public Access, Object Ownership)
- New provider SVG icons (s3compatible.svg, -link.svg, -round.svg)
- Registered provider in main plugin class with endpoint setting support
- Updated StorageProviderSubPage to show endpoint URL input for S3-compatible
- Built pro settings bundle with rollup (Svelte 4.2.19)
- Added package.json and updated rollup.config.mjs for pro-only builds
This commit is contained in:
21
vendor/Gcp/rize/uri-template/LICENSE
vendored
Normal file
21
vendor/Gcp/rize/uri-template/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) [2014] [Marut Khumtong]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
85
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate.php
vendored
Normal file
85
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate.php
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Rize;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Parser;
|
||||
/**
|
||||
* URI Template
|
||||
*/
|
||||
class UriTemplate
|
||||
{
|
||||
/**
|
||||
* @var Parser
|
||||
*/
|
||||
protected $parser, $parsed = array(), $base_uri, $params = array();
|
||||
public function __construct($base_uri = '', $params = array(), Parser $parser = null)
|
||||
{
|
||||
$this->base_uri = $base_uri;
|
||||
$this->params = $params;
|
||||
$this->parser = $parser ?: $this->createNodeParser();
|
||||
}
|
||||
/**
|
||||
* Expands URI Template
|
||||
*
|
||||
* @param string $uri URI Template
|
||||
* @param array $params URI Template's parameters
|
||||
* @return string
|
||||
*/
|
||||
public function expand($uri, $params = array())
|
||||
{
|
||||
$params += $this->params;
|
||||
$uri = $this->base_uri . $uri;
|
||||
$result = array();
|
||||
// quick check
|
||||
if (($start = \strpos($uri, '{')) === \false) {
|
||||
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
|
||||
*
|
||||
* @param string $template
|
||||
* @param string $uri
|
||||
* @param bool $strict This will perform a full match
|
||||
* @return null|array params or null if not match and $strict is true
|
||||
*/
|
||||
public function extract($template, $uri, $strict = \false)
|
||||
{
|
||||
$params = array();
|
||||
$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 && !\strlen((string) $uri)) {
|
||||
return null;
|
||||
}
|
||||
// uri'll be truncated from the start when a match is found
|
||||
$match = $node->match($this->parser, $uri, $params, $strict);
|
||||
list($uri, $params) = $match;
|
||||
}
|
||||
// if there's remaining $uri, matching is failed
|
||||
if ($strict && \strlen((string) $uri)) {
|
||||
return null;
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
public function getParser()
|
||||
{
|
||||
return $this->parser;
|
||||
}
|
||||
protected function createNodeParser()
|
||||
{
|
||||
static $parser;
|
||||
if ($parser) {
|
||||
return $parser;
|
||||
}
|
||||
return $parser = new Parser();
|
||||
}
|
||||
}
|
||||
59
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Node/Abstraction.php
vendored
Normal file
59
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Node/Abstraction.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Node;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Parser;
|
||||
/**
|
||||
* Base class for all Nodes
|
||||
*/
|
||||
abstract class Abstraction
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $token;
|
||||
public function __construct($token)
|
||||
{
|
||||
$this->token = $token;
|
||||
}
|
||||
/**
|
||||
* Expands URI template
|
||||
*
|
||||
* @param Parser $parser
|
||||
* @param array $params
|
||||
* @return null|string
|
||||
*/
|
||||
public function expand(Parser $parser, array $params = array())
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
/**
|
||||
* Matches given URI against current node
|
||||
*
|
||||
* @param Parser $parser
|
||||
* @param string $uri
|
||||
* @param array $params
|
||||
* @param bool $strict
|
||||
* @return null|array `uri and params` or `null` if not match and $strict is true
|
||||
*/
|
||||
public function match(Parser $parser, $uri, $params = array(), $strict = \false)
|
||||
{
|
||||
// match literal string from start to end
|
||||
$length = \strlen($this->token);
|
||||
if (\substr($uri, 0, $length) === $this->token) {
|
||||
$uri = \substr($uri, $length);
|
||||
} else {
|
||||
if ($strict) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return array($uri, $params);
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
}
|
||||
139
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Node/Expression.php
vendored
Normal file
139
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Node/Expression.php
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Node;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Parser;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Operator;
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
class Expression extends Abstraction
|
||||
{
|
||||
/**
|
||||
* @var Operator\Abstraction
|
||||
*/
|
||||
private $operator;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $variables = array();
|
||||
/**
|
||||
* Whether to do a forward lookup for a given separator
|
||||
* @var string
|
||||
*/
|
||||
private $forwardLookupSeparator;
|
||||
public function __construct($token, Operator\Abstraction $operator, array $variables = null, $forwardLookupSeparator = null)
|
||||
{
|
||||
parent::__construct($token);
|
||||
$this->operator = $operator;
|
||||
$this->variables = $variables;
|
||||
$this->forwardLookupSeparator = $forwardLookupSeparator;
|
||||
}
|
||||
/**
|
||||
* @return Operator\Abstraction
|
||||
*/
|
||||
public function getOperator()
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getVariables()
|
||||
{
|
||||
return $this->variables;
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getForwardLookupSeparator()
|
||||
{
|
||||
return $this->forwardLookupSeparator;
|
||||
}
|
||||
/**
|
||||
* @param string $forwardLookupSeparator
|
||||
*/
|
||||
public function setForwardLookupSeparator($forwardLookupSeparator)
|
||||
{
|
||||
$this->forwardLookupSeparator = $forwardLookupSeparator;
|
||||
}
|
||||
/**
|
||||
* @param Parser $parser
|
||||
* @param array $params
|
||||
* @return null|string
|
||||
*/
|
||||
public function expand(Parser $parser, array $params = array())
|
||||
{
|
||||
$data = array();
|
||||
$op = $this->operator;
|
||||
// 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
|
||||
*
|
||||
* @param Parser $parser
|
||||
* @param string $uri
|
||||
* @param array $params
|
||||
* @param bool $strict
|
||||
* @return null|array `uri and params` or `null` if not match and $strict is true
|
||||
*/
|
||||
public function match(Parser $parser, $uri, $params = array(), $strict = \false)
|
||||
{
|
||||
$op = $this->operator;
|
||||
// check expression operator first
|
||||
if ($op->id && isset($uri[0]) && $uri[0] !== $op->id) {
|
||||
return array($uri, $params);
|
||||
}
|
||||
// remove operator from input
|
||||
if ($op->id) {
|
||||
$uri = \substr($uri, 1);
|
||||
}
|
||||
foreach ($this->sortVariables($this->variables) as $var) {
|
||||
/** @var \Rize\UriTemplate\Node\Variable $regex */
|
||||
$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, $limit = 1);
|
||||
$val = $op->extract($parser, $var, $match[0]);
|
||||
} else {
|
||||
if ($strict) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$uri = $preparedUri . $remainingUri;
|
||||
$params[$var->getToken()] = $val;
|
||||
}
|
||||
return array($uri, $params);
|
||||
}
|
||||
/**
|
||||
* Sort variables before extracting data from uri.
|
||||
* We have to sort vars by non-explode to explode.
|
||||
*
|
||||
* @param array $vars
|
||||
* @return array
|
||||
*/
|
||||
protected function sortVariables(array $vars)
|
||||
{
|
||||
\usort($vars, function ($a, $b) {
|
||||
return $a->options['modifier'] >= $b->options['modifier'] ? 1 : -1;
|
||||
});
|
||||
return $vars;
|
||||
}
|
||||
}
|
||||
10
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Node/Literal.php
vendored
Normal file
10
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Node/Literal.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Node;
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
class Literal extends Abstraction
|
||||
{
|
||||
}
|
||||
26
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Node/Variable.php
vendored
Normal file
26
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Node/Variable.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Node;
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
class Variable extends Abstraction
|
||||
{
|
||||
/**
|
||||
* Variable name without modifier
|
||||
* e.g. 'term:1' becomes 'term'
|
||||
*/
|
||||
public $name, $options = array('modifier' => null, 'value' => null);
|
||||
public function __construct($token, array $options = array())
|
||||
{
|
||||
parent::__construct($token);
|
||||
$this->options = $options + $this->options;
|
||||
// normalize var name e.g. from 'term:1' becomes 'term'
|
||||
$name = $token;
|
||||
if ($options['modifier'] === ':') {
|
||||
$name = \substr($name, 0, \strpos($name, $options['modifier']));
|
||||
}
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
262
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Operator/Abstraction.php
vendored
Normal file
262
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Operator/Abstraction.php
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Operator;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Node;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\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 or not the expansion includes the variable or key name
|
||||
* reserved - union of (unreserved / reserved / pct-encoded)
|
||||
*/
|
||||
public $id, $named, $sep, $empty, $reserved, $start, $first;
|
||||
protected static $types = array('' => array('sep' => ',', 'named' => \false, 'empty' => '', 'reserved' => \false, 'start' => 0, 'first' => null), '+' => array('sep' => ',', 'named' => \false, 'empty' => '', 'reserved' => \true, 'start' => 1, 'first' => null), '.' => array('sep' => '.', 'named' => \false, 'empty' => '', 'reserved' => \false, 'start' => 1, 'first' => '.'), '/' => array('sep' => '/', 'named' => \false, 'empty' => '', 'reserved' => \false, 'start' => 1, 'first' => '/'), ';' => array('sep' => ';', 'named' => \true, 'empty' => '', 'reserved' => \false, 'start' => 1, 'first' => ';'), '?' => array('sep' => '&', 'named' => \true, 'empty' => '=', 'reserved' => \false, 'start' => 1, 'first' => '?'), '&' => array('sep' => '&', 'named' => \true, 'empty' => '=', 'reserved' => \false, 'start' => 1, 'first' => '&'), '#' => array('sep' => ',', 'named' => \false, 'empty' => '', 'reserved' => \true, 'start' => 1, 'first' => '#')), $loaded = array();
|
||||
/**
|
||||
* gen-delims | sub-delims
|
||||
*/
|
||||
public static $reserved_chars = array('%3A' => ':', '%2F' => '/', '%3F' => '?', '%23' => '#', '%5B' => '[', '%5D' => ']', '%40' => '@', '%21' => '!', '%24' => '$', '%26' => '&', '%27' => "'", '%28' => '(', '%29' => ')', '%2A' => '*', '%2B' => '+', '%2C' => ',', '%3B' => ';', '%3D' => '=');
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
public abstract function toRegex(Parser $parser, Node\Variable $var);
|
||||
public function expand(Parser $parser, Node\Variable $var, array $params = array())
|
||||
{
|
||||
$options = $var->options;
|
||||
$name = $var->name;
|
||||
$is_explode = \in_array($options['modifier'], array('*', '%'));
|
||||
// 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);
|
||||
} else {
|
||||
if (!$is_explode) {
|
||||
return $this->expandNonExplode($parser, $var, $val);
|
||||
} else {
|
||||
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 ':'
|
||||
*
|
||||
* @param Parser $parser
|
||||
* @param Node\Variable $var
|
||||
* @param array $val
|
||||
* @return null|string
|
||||
*/
|
||||
public function expandNonExplode(Parser $parser, Node\Variable $var, array $val)
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
return $this->encode($parser, $var, $val);
|
||||
}
|
||||
/**
|
||||
* Explode modifier '*', '%'
|
||||
*
|
||||
* @param Parser $parser
|
||||
* @param Node\Variable $var
|
||||
* @param array $val
|
||||
* @return null|string
|
||||
*/
|
||||
public function expandExplode(Parser $parser, Node\Variable $var, array $val)
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
return $this->encode($parser, $var, $val);
|
||||
}
|
||||
/**
|
||||
* Encodes variable according to spec (reserved or unreserved)
|
||||
*
|
||||
* @param Parser $parser
|
||||
* @param Node\Variable $var
|
||||
* @param mixed $values
|
||||
*
|
||||
* @return string encoded string
|
||||
*/
|
||||
public function encode(Parser $parser, Node\Variable $var, $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) {
|
||||
$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;
|
||||
} else {
|
||||
$v = \str_replace(\array_keys($maps), $maps, $encoded);
|
||||
}
|
||||
});
|
||||
return \implode($sep, $values);
|
||||
}
|
||||
/**
|
||||
* Decodes variable
|
||||
*
|
||||
* @param Parser $parser
|
||||
* @param Node\Variable $var
|
||||
* @param mixed $values
|
||||
*
|
||||
* @return string decoded string
|
||||
*/
|
||||
public function decode(Parser $parser, Node\Variable $var, $values)
|
||||
{
|
||||
$single = !\is_array($values);
|
||||
$values = (array) $values;
|
||||
\array_walk($values, function (&$v, $k) {
|
||||
$v = \rawurldecode($v);
|
||||
});
|
||||
return $single ? \reset($values) : $values;
|
||||
}
|
||||
/**
|
||||
* Extracts value from variable
|
||||
*
|
||||
* @param Parser $parser
|
||||
* @param Node\Variable $var
|
||||
* @param string $data
|
||||
* @return string
|
||||
*/
|
||||
public function extract(Parser $parser, Node\Variable $var, $data)
|
||||
{
|
||||
$value = $data;
|
||||
$vals = \array_filter(\explode($this->sep, $data));
|
||||
$options = $var->options;
|
||||
switch ($options['modifier']) {
|
||||
case '*':
|
||||
$data = array();
|
||||
foreach ($vals as $val) {
|
||||
if (\strpos($val, '=') !== \false) {
|
||||
list($k, $v) = \explode('=', $val);
|
||||
$data[$k] = $v;
|
||||
} else {
|
||||
$data[] = $val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
break;
|
||||
default:
|
||||
$data = \strpos($data, $this->sep) !== \false ? $vals : $value;
|
||||
}
|
||||
return $this->decode($parser, $var, $data);
|
||||
}
|
||||
public static function createById($id)
|
||||
{
|
||||
if (!isset(static::$types[$id])) {
|
||||
throw new \Exception("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)
|
||||
{
|
||||
return isset(static::$types[$id]);
|
||||
}
|
||||
/**
|
||||
* Returns the correct regex given the variable location in the URI
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getRegex()
|
||||
{
|
||||
switch ($this->id) {
|
||||
case '?':
|
||||
case '&':
|
||||
case '#':
|
||||
return self::$queryRegex;
|
||||
case ';':
|
||||
default:
|
||||
return self::$pathRegex;
|
||||
}
|
||||
}
|
||||
}
|
||||
164
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Operator/Named.php
vendored
Normal file
164
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Operator/Named.php
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Operator;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Node;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\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)
|
||||
{
|
||||
$regex = null;
|
||||
$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 = $name . '+(?:%5B|\\[)[^=]*=';
|
||||
$regex = "{$name}(?:{$value}+(?:{$this->sep}{$name}{$value}*)*)";
|
||||
break;
|
||||
default:
|
||||
throw new \Exception("Unknown modifier `{$options['modifier']}`");
|
||||
}
|
||||
} else {
|
||||
// 1, 3
|
||||
$regex = "{$name}=(?:{$value}+(?:,{$value}+)*)*";
|
||||
}
|
||||
return '(?:&)?' . $regex;
|
||||
}
|
||||
public function expandString(Parser $parser, Node\Variable $var, $val)
|
||||
{
|
||||
$val = (string) $val;
|
||||
$options = $var->options;
|
||||
$result = $this->encode($parser, $var, $var->name);
|
||||
// handle empty value
|
||||
if ($val === '') {
|
||||
return $result . $this->empty;
|
||||
} else {
|
||||
$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)
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
$result = $this->encode($parser, $var, $var->name);
|
||||
if (empty($val)) {
|
||||
return $result . $this->empty;
|
||||
} else {
|
||||
$result .= '=';
|
||||
}
|
||||
return $result . $this->encode($parser, $var, $val);
|
||||
}
|
||||
public function expandExplode(Parser $parser, Node\Variable $var, array $val)
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
$result = $this->encode($parser, $var, $var->name);
|
||||
// RFC6570 doesn't specify how to handle empty list/assoc array
|
||||
// for explode modifier
|
||||
if (empty($val)) {
|
||||
return $result . $this->empty;
|
||||
}
|
||||
$list = isset($val[0]);
|
||||
$data = array();
|
||||
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 and $var->options['modifier'] === '%') {
|
||||
$data = array($var->name => $data);
|
||||
}
|
||||
return $this->encodeExplodeVars($parser, $var, $data);
|
||||
}
|
||||
public function extract(Parser $parser, Node\Variable $var, $data)
|
||||
{
|
||||
// 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($data, $query);
|
||||
return $query[$var->name];
|
||||
case '*':
|
||||
$data = array();
|
||||
foreach ($vals as $val) {
|
||||
list($k, $v) = \explode('=', $val);
|
||||
// 2
|
||||
if ($k === $var->getToken()) {
|
||||
$data[] = $v;
|
||||
} else {
|
||||
$data[$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);
|
||||
$data = \explode(',', $value);
|
||||
if (\sizeof($data) === 1) {
|
||||
$data = \current($data);
|
||||
}
|
||||
}
|
||||
return $this->decode($parser, $var, $data);
|
||||
}
|
||||
public function encodeExplodeVars(Parser $parser, Node\Variable $var, $data)
|
||||
{
|
||||
// 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);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
40
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Operator/UnNamed.php
vendored
Normal file
40
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Operator/UnNamed.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Operator;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Node;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\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)
|
||||
{
|
||||
$regex = null;
|
||||
$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 \Exception("% (array) modifier only works with Named type operators e.g. ;,?,&");
|
||||
default:
|
||||
throw new \Exception("Unknown modifier `{$options['modifier']}`");
|
||||
}
|
||||
} else {
|
||||
// 1, 3
|
||||
$regex = "{$value}*(?:,{$value}+)*";
|
||||
}
|
||||
return $regex;
|
||||
}
|
||||
}
|
||||
120
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Parser.php
vendored
Normal file
120
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/Parser.php
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Node;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Node\Expression;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Operator;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate\Operator\UnNamed;
|
||||
class Parser
|
||||
{
|
||||
const REGEX_VARNAME = '(?:[A-z0-9_\\.]|%[0-9a-fA-F]{2})';
|
||||
/**
|
||||
* Parses URI Template and returns nodes
|
||||
*
|
||||
* @param string $template
|
||||
* @return Node\Abstraction[]
|
||||
*/
|
||||
public function parse($template)
|
||||
{
|
||||
$parts = \preg_split('#(\\{[^\\}]+\\})#', $template, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
|
||||
$nodes = array();
|
||||
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 (\sizeof($nodes) > 0) {
|
||||
$previousNode = $nodes[\sizeof($nodes) - 1];
|
||||
if ($previousNode instanceof Expression && $previousNode->getOperator() instanceof UnNamed) {
|
||||
$previousNode->setForwardLookupSeparator($node->getOperator()->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
$nodes[] = $node;
|
||||
}
|
||||
return $nodes;
|
||||
}
|
||||
/**
|
||||
* @param string $token
|
||||
* @return Node\Abstraction
|
||||
*/
|
||||
protected function createNode($token)
|
||||
{
|
||||
// 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($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 \Exception("Invalid operator [{$prefix}] found at {$token}");
|
||||
}
|
||||
// default operator
|
||||
$prefix = null;
|
||||
}
|
||||
// remove operator prefix if exists e.g. '?'
|
||||
if ($prefix) {
|
||||
$token = \substr($token, 1);
|
||||
}
|
||||
// parse variables
|
||||
$vars = array();
|
||||
foreach (\explode(',', $token) as $var) {
|
||||
$vars[] = $this->parseVariable($var);
|
||||
}
|
||||
return $this->createExpressionNode($token, $this->createOperatorNode($prefix), $vars);
|
||||
}
|
||||
protected function parseVariable($var)
|
||||
{
|
||||
$var = \trim($var);
|
||||
$val = null;
|
||||
$modifier = null;
|
||||
// check for prefix (:) / explode (*) / array (%) modifier
|
||||
if (\strpos($var, ':') !== \false) {
|
||||
$modifier = ':';
|
||||
list($varname, $val) = \explode(':', $var);
|
||||
// error checking
|
||||
if (!\is_numeric($val)) {
|
||||
throw new \Exception("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 \Exception("Multiple modifiers per variable are not allowed [{$var}]");
|
||||
}
|
||||
$modifier = $last;
|
||||
$var = \substr($var, 0, -1);
|
||||
break;
|
||||
}
|
||||
return $this->createVariableNode($var, array('modifier' => $modifier, 'value' => $val));
|
||||
}
|
||||
protected function createVariableNode($token, $options = array())
|
||||
{
|
||||
return new Node\Variable($token, $options);
|
||||
}
|
||||
protected function createExpressionNode($token, Operator\Abstraction $operator = null, array $vars = array())
|
||||
{
|
||||
return new Node\Expression($token, $operator, $vars);
|
||||
}
|
||||
protected function createLiteralNode($token)
|
||||
{
|
||||
return new Node\Literal($token);
|
||||
}
|
||||
protected function createOperatorNode($token)
|
||||
{
|
||||
return Operator\Abstraction::createById($token);
|
||||
}
|
||||
}
|
||||
11
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/UriTemplate.php
vendored
Normal file
11
vendor/Gcp/rize/uri-template/src/Rize/UriTemplate/UriTemplate.php
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Rize\UriTemplate as Template;
|
||||
/**
|
||||
* Future compatibility
|
||||
*/
|
||||
class UriTemplate extends Template
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user