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:
341
vendor/Aws3/JmesPath/FnDispatcher.php
vendored
Normal file
341
vendor/Aws3/JmesPath/FnDispatcher.php
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Aws3\JmesPath;
|
||||
|
||||
/**
|
||||
* Dispatches to named JMESPath functions using a single function that has the
|
||||
* following signature:
|
||||
*
|
||||
* mixed $result = fn(string $function_name, array $args)
|
||||
*/
|
||||
class FnDispatcher
|
||||
{
|
||||
/**
|
||||
* Gets a cached instance of the default function implementations.
|
||||
*
|
||||
* @return FnDispatcher
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
static $instance = null;
|
||||
if (!$instance) {
|
||||
$instance = new self();
|
||||
}
|
||||
return $instance;
|
||||
}
|
||||
/**
|
||||
* @param string $fn Function name.
|
||||
* @param array $args Function arguments.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __invoke($fn, array $args)
|
||||
{
|
||||
return $this->{'fn_' . $fn}($args);
|
||||
}
|
||||
private function fn_abs(array $args)
|
||||
{
|
||||
$this->validate('abs', $args, [['number']]);
|
||||
return \abs($args[0]);
|
||||
}
|
||||
private function fn_avg(array $args)
|
||||
{
|
||||
$this->validate('avg', $args, [['array']]);
|
||||
$sum = $this->reduce('avg:0', $args[0], ['number'], function ($a, $b) {
|
||||
return Utils::add($a, $b);
|
||||
});
|
||||
return $args[0] ? $sum / \count($args[0]) : null;
|
||||
}
|
||||
private function fn_ceil(array $args)
|
||||
{
|
||||
$this->validate('ceil', $args, [['number']]);
|
||||
return \ceil($args[0]);
|
||||
}
|
||||
private function fn_contains(array $args)
|
||||
{
|
||||
$this->validate('contains', $args, [['string', 'array'], ['any']]);
|
||||
if (\is_array($args[0])) {
|
||||
return \in_array($args[1], $args[0]);
|
||||
} elseif (\is_string($args[1])) {
|
||||
return \mb_strpos($args[0], $args[1], 0, 'UTF-8') !== \false;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private function fn_ends_with(array $args)
|
||||
{
|
||||
$this->validate('ends_with', $args, [['string'], ['string']]);
|
||||
list($search, $suffix) = $args;
|
||||
return $suffix === '' || \mb_substr($search, -\mb_strlen($suffix, 'UTF-8'), null, 'UTF-8') === $suffix;
|
||||
}
|
||||
private function fn_floor(array $args)
|
||||
{
|
||||
$this->validate('floor', $args, [['number']]);
|
||||
return \floor($args[0]);
|
||||
}
|
||||
private function fn_not_null(array $args)
|
||||
{
|
||||
if (!$args) {
|
||||
throw new \RuntimeException("not_null() expects 1 or more arguments, 0 were provided");
|
||||
}
|
||||
return \array_reduce($args, function ($carry, $item) {
|
||||
return $carry !== null ? $carry : $item;
|
||||
});
|
||||
}
|
||||
private function fn_join(array $args)
|
||||
{
|
||||
$this->validate('join', $args, [['string'], ['array']]);
|
||||
$fn = function ($a, $b, $i) use($args) {
|
||||
return $i ? $a . $args[0] . $b : $b;
|
||||
};
|
||||
return $this->reduce('join:0', $args[1], ['string'], $fn);
|
||||
}
|
||||
private function fn_keys(array $args)
|
||||
{
|
||||
$this->validate('keys', $args, [['object']]);
|
||||
return \array_keys((array) $args[0]);
|
||||
}
|
||||
private function fn_length(array $args)
|
||||
{
|
||||
$this->validate('length', $args, [['string', 'array', 'object']]);
|
||||
return \is_string($args[0]) ? \mb_strlen($args[0], 'UTF-8') : \count((array) $args[0]);
|
||||
}
|
||||
private function fn_max(array $args)
|
||||
{
|
||||
$this->validate('max', $args, [['array']]);
|
||||
$fn = function ($a, $b) {
|
||||
return $a >= $b ? $a : $b;
|
||||
};
|
||||
return $this->reduce('max:0', $args[0], ['number', 'string'], $fn);
|
||||
}
|
||||
private function fn_max_by(array $args)
|
||||
{
|
||||
$this->validate('max_by', $args, [['array'], ['expression']]);
|
||||
$expr = $this->wrapExpression('max_by:1', $args[1], ['number', 'string']);
|
||||
$fn = function ($carry, $item, $index) use($expr) {
|
||||
return $index ? $expr($carry) >= $expr($item) ? $carry : $item : $item;
|
||||
};
|
||||
return $this->reduce('max_by:1', $args[0], ['any'], $fn);
|
||||
}
|
||||
private function fn_min(array $args)
|
||||
{
|
||||
$this->validate('min', $args, [['array']]);
|
||||
$fn = function ($a, $b, $i) {
|
||||
return $i && $a <= $b ? $a : $b;
|
||||
};
|
||||
return $this->reduce('min:0', $args[0], ['number', 'string'], $fn);
|
||||
}
|
||||
private function fn_min_by(array $args)
|
||||
{
|
||||
$this->validate('min_by', $args, [['array'], ['expression']]);
|
||||
$expr = $this->wrapExpression('min_by:1', $args[1], ['number', 'string']);
|
||||
$i = -1;
|
||||
$fn = function ($a, $b) use($expr, &$i) {
|
||||
return ++$i ? $expr($a) <= $expr($b) ? $a : $b : $b;
|
||||
};
|
||||
return $this->reduce('min_by:1', $args[0], ['any'], $fn);
|
||||
}
|
||||
private function fn_reverse(array $args)
|
||||
{
|
||||
$this->validate('reverse', $args, [['array', 'string']]);
|
||||
if (\is_array($args[0])) {
|
||||
return \array_reverse($args[0]);
|
||||
} elseif (\is_string($args[0])) {
|
||||
return \strrev($args[0]);
|
||||
} else {
|
||||
throw new \RuntimeException('Cannot reverse provided argument');
|
||||
}
|
||||
}
|
||||
private function fn_sum(array $args)
|
||||
{
|
||||
$this->validate('sum', $args, [['array']]);
|
||||
$fn = function ($a, $b) {
|
||||
return Utils::add($a, $b);
|
||||
};
|
||||
return $this->reduce('sum:0', $args[0], ['number'], $fn);
|
||||
}
|
||||
private function fn_sort(array $args)
|
||||
{
|
||||
$this->validate('sort', $args, [['array']]);
|
||||
$valid = ['string', 'number'];
|
||||
return Utils::stableSort($args[0], function ($a, $b) use($valid) {
|
||||
$this->validateSeq('sort:0', $valid, $a, $b);
|
||||
return \strnatcmp($a, $b);
|
||||
});
|
||||
}
|
||||
private function fn_sort_by(array $args)
|
||||
{
|
||||
$this->validate('sort_by', $args, [['array'], ['expression']]);
|
||||
$expr = $args[1];
|
||||
$valid = ['string', 'number'];
|
||||
return Utils::stableSort($args[0], function ($a, $b) use($expr, $valid) {
|
||||
$va = $expr($a);
|
||||
$vb = $expr($b);
|
||||
$this->validateSeq('sort_by:0', $valid, $va, $vb);
|
||||
return \strnatcmp($va, $vb);
|
||||
});
|
||||
}
|
||||
private function fn_starts_with(array $args)
|
||||
{
|
||||
$this->validate('starts_with', $args, [['string'], ['string']]);
|
||||
list($search, $prefix) = $args;
|
||||
return $prefix === '' || \mb_strpos($search, $prefix, 0, 'UTF-8') === 0;
|
||||
}
|
||||
private function fn_type(array $args)
|
||||
{
|
||||
$this->validateArity('type', \count($args), 1);
|
||||
return Utils::type($args[0]);
|
||||
}
|
||||
private function fn_to_string(array $args)
|
||||
{
|
||||
$this->validateArity('to_string', \count($args), 1);
|
||||
$v = $args[0];
|
||||
if (\is_string($v)) {
|
||||
return $v;
|
||||
} elseif (\is_object($v) && !$v instanceof \JsonSerializable && \method_exists($v, '__toString')) {
|
||||
return (string) $v;
|
||||
}
|
||||
return \json_encode($v);
|
||||
}
|
||||
private function fn_to_number(array $args)
|
||||
{
|
||||
$this->validateArity('to_number', \count($args), 1);
|
||||
$value = $args[0];
|
||||
$type = Utils::type($value);
|
||||
if ($type == 'number') {
|
||||
return $value;
|
||||
} elseif ($type == 'string' && \is_numeric($value)) {
|
||||
return \mb_strpos($value, '.', 0, 'UTF-8') ? (float) $value : (int) $value;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private function fn_values(array $args)
|
||||
{
|
||||
$this->validate('values', $args, [['array', 'object']]);
|
||||
return \array_values((array) $args[0]);
|
||||
}
|
||||
private function fn_merge(array $args)
|
||||
{
|
||||
if (!$args) {
|
||||
throw new \RuntimeException("merge() expects 1 or more arguments, 0 were provided");
|
||||
}
|
||||
return \call_user_func_array('array_replace', $args);
|
||||
}
|
||||
private function fn_to_array(array $args)
|
||||
{
|
||||
$this->validate('to_array', $args, [['any']]);
|
||||
return Utils::isArray($args[0]) ? $args[0] : [$args[0]];
|
||||
}
|
||||
private function fn_map(array $args)
|
||||
{
|
||||
$this->validate('map', $args, [['expression'], ['any']]);
|
||||
$result = [];
|
||||
foreach ($args[1] as $a) {
|
||||
$result[] = $args[0]($a);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
private function typeError($from, $msg)
|
||||
{
|
||||
if (\mb_strpos($from, ':', 0, 'UTF-8')) {
|
||||
list($fn, $pos) = \explode(':', $from);
|
||||
throw new \RuntimeException(\sprintf('Argument %d of %s %s', $pos, $fn, $msg));
|
||||
} else {
|
||||
throw new \RuntimeException(\sprintf('Type error: %s %s', $from, $msg));
|
||||
}
|
||||
}
|
||||
private function validateArity($from, $given, $expected)
|
||||
{
|
||||
if ($given != $expected) {
|
||||
$err = "%s() expects {$expected} arguments, {$given} were provided";
|
||||
throw new \RuntimeException(\sprintf($err, $from));
|
||||
}
|
||||
}
|
||||
private function validate($from, $args, $types = [])
|
||||
{
|
||||
$this->validateArity($from, \count($args), \count($types));
|
||||
foreach ($args as $index => $value) {
|
||||
if (!isset($types[$index]) || !$types[$index]) {
|
||||
continue;
|
||||
}
|
||||
$this->validateType("{$from}:{$index}", $value, $types[$index]);
|
||||
}
|
||||
}
|
||||
private function validateType($from, $value, array $types)
|
||||
{
|
||||
if ($types[0] == 'any' || \in_array(Utils::type($value), $types) || $value === [] && \in_array('object', $types)) {
|
||||
return;
|
||||
}
|
||||
$msg = 'must be one of the following types: ' . \implode(', ', $types) . '. ' . Utils::type($value) . ' found';
|
||||
$this->typeError($from, $msg);
|
||||
}
|
||||
/**
|
||||
* Validates value A and B, ensures they both are correctly typed, and of
|
||||
* the same type.
|
||||
*
|
||||
* @param string $from String of function:argument_position
|
||||
* @param array $types Array of valid value types.
|
||||
* @param mixed $a Value A
|
||||
* @param mixed $b Value B
|
||||
*/
|
||||
private function validateSeq($from, array $types, $a, $b)
|
||||
{
|
||||
$ta = Utils::type($a);
|
||||
$tb = Utils::type($b);
|
||||
if ($ta !== $tb) {
|
||||
$msg = "encountered a type mismatch in sequence: {$ta}, {$tb}";
|
||||
$this->typeError($from, $msg);
|
||||
}
|
||||
$typeMatch = $types && $types[0] == 'any' || \in_array($ta, $types);
|
||||
if (!$typeMatch) {
|
||||
$msg = 'encountered a type error in sequence. The argument must be ' . 'an array of ' . \implode('|', $types) . ' types. ' . "Found {$ta}, {$tb}.";
|
||||
$this->typeError($from, $msg);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reduces and validates an array of values to a single value using a fn.
|
||||
*
|
||||
* @param string $from String of function:argument_position
|
||||
* @param array $values Values to reduce.
|
||||
* @param array $types Array of valid value types.
|
||||
* @param callable $reduce Reduce function that accepts ($carry, $item).
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function reduce($from, array $values, array $types, callable $reduce)
|
||||
{
|
||||
$i = -1;
|
||||
return \array_reduce($values, function ($carry, $item) use($from, $types, $reduce, &$i) {
|
||||
if (++$i > 0) {
|
||||
$this->validateSeq($from, $types, $carry, $item);
|
||||
}
|
||||
return $reduce($carry, $item, $i);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Validates the return values of expressions as they are applied.
|
||||
*
|
||||
* @param string $from Function name : position
|
||||
* @param callable $expr Expression function to validate.
|
||||
* @param array $types Array of acceptable return type values.
|
||||
*
|
||||
* @return callable Returns a wrapped function
|
||||
*/
|
||||
private function wrapExpression($from, callable $expr, array $types)
|
||||
{
|
||||
list($fn, $pos) = \explode(':', $from);
|
||||
$from = "The expression return value of argument {$pos} of {$fn}";
|
||||
return function ($value) use($from, $expr, $types) {
|
||||
$value = $expr($value);
|
||||
$this->validateType($from, $value, $types);
|
||||
return $value;
|
||||
};
|
||||
}
|
||||
/** @internal Pass function name validation off to runtime */
|
||||
public function __call($name, $args)
|
||||
{
|
||||
$name = \str_replace('fn_', '', $name);
|
||||
throw new \RuntimeException("Call to undefined function {$name}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user