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:
30
vendor/Aws3/Aws/Api/Serializer/Ec2ParamBuilder.php
vendored
Normal file
30
vendor/Aws3/Aws/Api/Serializer/Ec2ParamBuilder.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Serializer;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Shape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\ListShape;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class Ec2ParamBuilder extends QueryParamBuilder
|
||||
{
|
||||
protected function queryName(Shape $shape, $default = null)
|
||||
{
|
||||
return ($shape['queryName'] ?: \ucfirst(@$shape['locationName'] ?: "")) ?: $default;
|
||||
}
|
||||
protected function isFlat(Shape $shape)
|
||||
{
|
||||
return \false;
|
||||
}
|
||||
protected function format_list(ListShape $shape, array $value, $prefix, &$query)
|
||||
{
|
||||
// Handle empty list serialization
|
||||
if (!empty($value)) {
|
||||
$items = $shape->getMember();
|
||||
foreach ($value as $k => $v) {
|
||||
$this->format($items, $v, $prefix . '.' . ($k + 1), $query);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
94
vendor/Aws3/Aws/Api/Serializer/JsonBody.php
vendored
Normal file
94
vendor/Aws3/Aws/Api/Serializer/JsonBody.php
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Serializer;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Service;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Shape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\TimestampShape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Exception\InvalidJsonException;
|
||||
/**
|
||||
* Formats the JSON body of a JSON-REST or JSON-RPC operation.
|
||||
* @internal
|
||||
*/
|
||||
class JsonBody
|
||||
{
|
||||
private $api;
|
||||
public function __construct(Service $api)
|
||||
{
|
||||
$this->api = $api;
|
||||
}
|
||||
/**
|
||||
* Gets the JSON Content-Type header for a service API
|
||||
*
|
||||
* @param Service $service
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getContentType(Service $service)
|
||||
{
|
||||
if ($service->getMetadata('protocol') === 'rest-json') {
|
||||
return 'application/json';
|
||||
}
|
||||
$jsonVersion = $service->getMetadata('jsonVersion');
|
||||
if (empty($jsonVersion)) {
|
||||
throw new \InvalidArgumentException('invalid json');
|
||||
} else {
|
||||
return 'application/x-amz-json-' . @\number_format($service->getMetadata('jsonVersion'), 1);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Builds the JSON body based on an array of arguments.
|
||||
*
|
||||
* @param Shape $shape Operation being constructed
|
||||
* @param array $args Associative array of arguments
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function build(Shape $shape, array $args)
|
||||
{
|
||||
$result = \json_encode($this->format($shape, $args));
|
||||
return $result == '[]' ? '{}' : $result;
|
||||
}
|
||||
private function format(Shape $shape, $value)
|
||||
{
|
||||
switch ($shape['type']) {
|
||||
case 'structure':
|
||||
$data = [];
|
||||
if (isset($shape['document']) && $shape['document']) {
|
||||
return $value;
|
||||
}
|
||||
foreach ($value as $k => $v) {
|
||||
if ($v !== null && $shape->hasMember($k)) {
|
||||
$valueShape = $shape->getMember($k);
|
||||
$data[$valueShape['locationName'] ?: $k] = $this->format($valueShape, $v);
|
||||
}
|
||||
}
|
||||
if (empty($data)) {
|
||||
return new \stdClass();
|
||||
}
|
||||
return $data;
|
||||
case 'list':
|
||||
$items = $shape->getMember();
|
||||
foreach ($value as $k => $v) {
|
||||
$value[$k] = $this->format($items, $v);
|
||||
}
|
||||
return $value;
|
||||
case 'map':
|
||||
if (empty($value)) {
|
||||
return new \stdClass();
|
||||
}
|
||||
$values = $shape->getValue();
|
||||
foreach ($value as $k => $v) {
|
||||
$value[$k] = $this->format($values, $v);
|
||||
}
|
||||
return $value;
|
||||
case 'blob':
|
||||
return \base64_encode($value);
|
||||
case 'timestamp':
|
||||
$timestampFormat = !empty($shape['timestampFormat']) ? $shape['timestampFormat'] : 'unixTimestamp';
|
||||
return TimestampShape::format($value, $timestampFormat);
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
vendor/Aws3/Aws/Api/Serializer/JsonRpcSerializer.php
vendored
Normal file
59
vendor/Aws3/Aws/Api/Serializer/JsonRpcSerializer.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Serializer;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Service;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\CommandInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\EndpointV2\EndpointV2SerializerTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\EndpointV2\Ruleset\RulesetEndpoint;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\GuzzleHttp\Psr7\Request;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Psr\Http\Message\RequestInterface;
|
||||
/**
|
||||
* Prepares a JSON-RPC request for transfer.
|
||||
* @internal
|
||||
*/
|
||||
class JsonRpcSerializer
|
||||
{
|
||||
use EndpointV2SerializerTrait;
|
||||
/** @var JsonBody */
|
||||
private $jsonFormatter;
|
||||
/** @var string */
|
||||
private $endpoint;
|
||||
/** @var Service */
|
||||
private $api;
|
||||
/** @var string */
|
||||
private $contentType;
|
||||
/**
|
||||
* @param Service $api Service description
|
||||
* @param string $endpoint Endpoint to connect to
|
||||
* @param JsonBody $jsonFormatter Optional JSON formatter to use
|
||||
*/
|
||||
public function __construct(Service $api, $endpoint, JsonBody $jsonFormatter = null)
|
||||
{
|
||||
$this->endpoint = $endpoint;
|
||||
$this->api = $api;
|
||||
$this->jsonFormatter = $jsonFormatter ?: new JsonBody($this->api);
|
||||
$this->contentType = JsonBody::getContentType($api);
|
||||
}
|
||||
/**
|
||||
* When invoked with an AWS command, returns a serialization array
|
||||
* containing "method", "uri", "headers", and "body" key value pairs.
|
||||
*
|
||||
* @param CommandInterface $command Command to serialize into a request.
|
||||
* @param $endpointProvider Provider used for dynamic endpoint resolution.
|
||||
* @param $clientArgs Client arguments used for dynamic endpoint resolution.
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function __invoke(CommandInterface $command, $endpoint = null)
|
||||
{
|
||||
$operationName = $command->getName();
|
||||
$operation = $this->api->getOperation($operationName);
|
||||
$commandArgs = $command->toArray();
|
||||
$headers = ['X-Amz-Target' => $this->api->getMetadata('targetPrefix') . '.' . $operationName, 'Content-Type' => $this->contentType];
|
||||
if ($endpoint instanceof RulesetEndpoint) {
|
||||
$this->setEndpointV2RequestOptions($endpoint, $headers);
|
||||
}
|
||||
return new Request($operation['http']['method'], $this->endpoint, $headers, $this->jsonFormatter->build($operation->getInput(), $commandArgs));
|
||||
}
|
||||
}
|
||||
112
vendor/Aws3/Aws/Api/Serializer/QueryParamBuilder.php
vendored
Normal file
112
vendor/Aws3/Aws/Api/Serializer/QueryParamBuilder.php
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Serializer;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\StructureShape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\ListShape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\MapShape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Shape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\TimestampShape;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class QueryParamBuilder
|
||||
{
|
||||
private $methods;
|
||||
protected function queryName(Shape $shape, $default = null)
|
||||
{
|
||||
if (null !== $shape['queryName']) {
|
||||
return $shape['queryName'];
|
||||
}
|
||||
if (null !== $shape['locationName']) {
|
||||
return $shape['locationName'];
|
||||
}
|
||||
if ($this->isFlat($shape) && !empty($shape['member']['locationName'])) {
|
||||
return $shape['member']['locationName'];
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
protected function isFlat(Shape $shape)
|
||||
{
|
||||
return $shape['flattened'] === \true;
|
||||
}
|
||||
public function __invoke(StructureShape $shape, array $params)
|
||||
{
|
||||
if (!$this->methods) {
|
||||
$this->methods = \array_fill_keys(\get_class_methods($this), \true);
|
||||
}
|
||||
$query = [];
|
||||
$this->format_structure($shape, $params, '', $query);
|
||||
return $query;
|
||||
}
|
||||
protected function format(Shape $shape, $value, $prefix, array &$query)
|
||||
{
|
||||
$type = 'format_' . $shape['type'];
|
||||
if (isset($this->methods[$type])) {
|
||||
$this->{$type}($shape, $value, $prefix, $query);
|
||||
} else {
|
||||
$query[$prefix] = (string) $value;
|
||||
}
|
||||
}
|
||||
protected function format_structure(StructureShape $shape, array $value, $prefix, &$query)
|
||||
{
|
||||
if ($prefix) {
|
||||
$prefix .= '.';
|
||||
}
|
||||
foreach ($value as $k => $v) {
|
||||
if ($shape->hasMember($k)) {
|
||||
$member = $shape->getMember($k);
|
||||
$this->format($member, $v, $prefix . $this->queryName($member, $k), $query);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected function format_list(ListShape $shape, array $value, $prefix, &$query)
|
||||
{
|
||||
// Handle empty list serialization
|
||||
if (!$value) {
|
||||
$query[$prefix] = '';
|
||||
return;
|
||||
}
|
||||
$items = $shape->getMember();
|
||||
if (!$this->isFlat($shape)) {
|
||||
$locationName = $shape->getMember()['locationName'] ?: 'member';
|
||||
$prefix .= ".{$locationName}";
|
||||
} elseif ($name = $this->queryName($items)) {
|
||||
$parts = \explode('.', $prefix);
|
||||
$parts[\count($parts) - 1] = $name;
|
||||
$prefix = \implode('.', $parts);
|
||||
}
|
||||
foreach ($value as $k => $v) {
|
||||
$this->format($items, $v, $prefix . '.' . ($k + 1), $query);
|
||||
}
|
||||
}
|
||||
protected function format_map(MapShape $shape, array $value, $prefix, array &$query)
|
||||
{
|
||||
$vals = $shape->getValue();
|
||||
$keys = $shape->getKey();
|
||||
if (!$this->isFlat($shape)) {
|
||||
$prefix .= '.entry';
|
||||
}
|
||||
$i = 0;
|
||||
$keyName = '%s.%d.' . $this->queryName($keys, 'key');
|
||||
$valueName = '%s.%s.' . $this->queryName($vals, 'value');
|
||||
foreach ($value as $k => $v) {
|
||||
$i++;
|
||||
$this->format($keys, $k, \sprintf($keyName, $prefix, $i), $query);
|
||||
$this->format($vals, $v, \sprintf($valueName, $prefix, $i), $query);
|
||||
}
|
||||
}
|
||||
protected function format_blob(Shape $shape, $value, $prefix, array &$query)
|
||||
{
|
||||
$query[$prefix] = \base64_encode($value);
|
||||
}
|
||||
protected function format_timestamp(TimestampShape $shape, $value, $prefix, array &$query)
|
||||
{
|
||||
$timestampFormat = !empty($shape['timestampFormat']) ? $shape['timestampFormat'] : 'iso8601';
|
||||
$query[$prefix] = TimestampShape::format($value, $timestampFormat);
|
||||
}
|
||||
protected function format_boolean(Shape $shape, $value, $prefix, array &$query)
|
||||
{
|
||||
$query[$prefix] = $value ? 'true' : 'false';
|
||||
}
|
||||
}
|
||||
54
vendor/Aws3/Aws/Api/Serializer/QuerySerializer.php
vendored
Normal file
54
vendor/Aws3/Aws/Api/Serializer/QuerySerializer.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Serializer;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Service;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\CommandInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\EndpointV2\EndpointProviderV2;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\EndpointV2\EndpointV2SerializerTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\EndpointV2\Ruleset\RulesetEndpoint;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\GuzzleHttp\Psr7\Request;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Psr\Http\Message\RequestInterface;
|
||||
/**
|
||||
* Serializes a query protocol request.
|
||||
* @internal
|
||||
*/
|
||||
class QuerySerializer
|
||||
{
|
||||
use EndpointV2SerializerTrait;
|
||||
private $endpoint;
|
||||
private $api;
|
||||
private $paramBuilder;
|
||||
public function __construct(Service $api, $endpoint, callable $paramBuilder = null)
|
||||
{
|
||||
$this->api = $api;
|
||||
$this->endpoint = $endpoint;
|
||||
$this->paramBuilder = $paramBuilder ?: new QueryParamBuilder();
|
||||
}
|
||||
/**
|
||||
* When invoked with an AWS command, returns a serialization array
|
||||
* containing "method", "uri", "headers", and "body" key value pairs.
|
||||
*
|
||||
* @param CommandInterface $command Command to serialize into a request.
|
||||
* @param $endpointProvider Provider used for dynamic endpoint resolution.
|
||||
* @param $clientArgs Client arguments used for dynamic endpoint resolution.
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function __invoke(CommandInterface $command, $endpoint = null)
|
||||
{
|
||||
$operation = $this->api->getOperation($command->getName());
|
||||
$body = ['Action' => $command->getName(), 'Version' => $this->api->getMetadata('apiVersion')];
|
||||
$commandArgs = $command->toArray();
|
||||
// Only build up the parameters when there are parameters to build
|
||||
if ($commandArgs) {
|
||||
$body += \call_user_func($this->paramBuilder, $operation->getInput(), $commandArgs);
|
||||
}
|
||||
$body = \http_build_query($body, '', '&', \PHP_QUERY_RFC3986);
|
||||
$headers = ['Content-Length' => \strlen($body), 'Content-Type' => 'application/x-www-form-urlencoded'];
|
||||
if ($endpoint instanceof RulesetEndpoint) {
|
||||
$this->setEndpointV2RequestOptions($endpoint, $headers);
|
||||
}
|
||||
return new Request('POST', $this->endpoint, $headers, $body);
|
||||
}
|
||||
}
|
||||
34
vendor/Aws3/Aws/Api/Serializer/RestJsonSerializer.php
vendored
Normal file
34
vendor/Aws3/Aws/Api/Serializer/RestJsonSerializer.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Serializer;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Service;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\StructureShape;
|
||||
/**
|
||||
* Serializes requests for the REST-JSON protocol.
|
||||
* @internal
|
||||
*/
|
||||
class RestJsonSerializer extends RestSerializer
|
||||
{
|
||||
/** @var JsonBody */
|
||||
private $jsonFormatter;
|
||||
/** @var string */
|
||||
private $contentType;
|
||||
/**
|
||||
* @param Service $api Service API description
|
||||
* @param string $endpoint Endpoint to connect to
|
||||
* @param JsonBody $jsonFormatter Optional JSON formatter to use
|
||||
*/
|
||||
public function __construct(Service $api, $endpoint, JsonBody $jsonFormatter = null)
|
||||
{
|
||||
parent::__construct($api, $endpoint);
|
||||
$this->contentType = JsonBody::getContentType($api);
|
||||
$this->jsonFormatter = $jsonFormatter ?: new JsonBody($api);
|
||||
}
|
||||
protected function payload(StructureShape $member, array $value, array &$opts)
|
||||
{
|
||||
$body = isset($value) ? (string) $this->jsonFormatter->build($member, $value) : "{}";
|
||||
$opts['headers']['Content-Type'] = $this->contentType;
|
||||
$opts['body'] = $body;
|
||||
}
|
||||
}
|
||||
239
vendor/Aws3/Aws/Api/Serializer/RestSerializer.php
vendored
Normal file
239
vendor/Aws3/Aws/Api/Serializer/RestSerializer.php
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Serializer;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\MapShape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Service;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Operation;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Shape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\StructureShape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\TimestampShape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\CommandInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\EndpointV2\EndpointProviderV2;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\EndpointV2\EndpointV2SerializerTrait;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\EndpointV2\Ruleset\RulesetEndpoint;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\GuzzleHttp\Psr7;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\GuzzleHttp\Psr7\Request;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\GuzzleHttp\Psr7\Uri;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\GuzzleHttp\Psr7\UriResolver;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Psr\Http\Message\RequestInterface;
|
||||
/**
|
||||
* Serializes HTTP locations like header, uri, payload, etc...
|
||||
* @internal
|
||||
*/
|
||||
abstract class RestSerializer
|
||||
{
|
||||
use EndpointV2SerializerTrait;
|
||||
/** @var Service */
|
||||
private $api;
|
||||
/** @var Uri */
|
||||
private $endpoint;
|
||||
/**
|
||||
* @param Service $api Service API description
|
||||
* @param string $endpoint Endpoint to connect to
|
||||
*/
|
||||
public function __construct(Service $api, $endpoint)
|
||||
{
|
||||
$this->api = $api;
|
||||
$this->endpoint = Psr7\Utils::uriFor($endpoint);
|
||||
}
|
||||
/**
|
||||
* @param CommandInterface $command Command to serialize into a request.
|
||||
* @param $endpointProvider Provider used for dynamic endpoint resolution.
|
||||
* @param $clientArgs Client arguments used for dynamic endpoint resolution.
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function __invoke(CommandInterface $command, $endpoint = null)
|
||||
{
|
||||
$operation = $this->api->getOperation($command->getName());
|
||||
$commandArgs = $command->toArray();
|
||||
$opts = $this->serialize($operation, $commandArgs);
|
||||
$headers = isset($opts['headers']) ? $opts['headers'] : [];
|
||||
if ($endpoint instanceof RulesetEndpoint) {
|
||||
$this->setEndpointV2RequestOptions($endpoint, $headers);
|
||||
}
|
||||
$uri = $this->buildEndpoint($operation, $commandArgs, $opts);
|
||||
return new Request($operation['http']['method'], $uri, $headers, isset($opts['body']) ? $opts['body'] : null);
|
||||
}
|
||||
/**
|
||||
* Modifies a hash of request options for a payload body.
|
||||
*
|
||||
* @param StructureShape $member Member to serialize
|
||||
* @param array $value Value to serialize
|
||||
* @param array $opts Request options to modify.
|
||||
*/
|
||||
protected abstract function payload(StructureShape $member, array $value, array &$opts);
|
||||
private function serialize(Operation $operation, array $args)
|
||||
{
|
||||
$opts = [];
|
||||
$input = $operation->getInput();
|
||||
// Apply the payload trait if present
|
||||
if ($payload = $input['payload']) {
|
||||
$this->applyPayload($input, $payload, $args, $opts);
|
||||
}
|
||||
foreach ($args as $name => $value) {
|
||||
if ($input->hasMember($name)) {
|
||||
$member = $input->getMember($name);
|
||||
$location = $member['location'];
|
||||
if (!$payload && !$location) {
|
||||
$bodyMembers[$name] = $value;
|
||||
} elseif ($location == 'header') {
|
||||
$this->applyHeader($name, $member, $value, $opts);
|
||||
} elseif ($location == 'querystring') {
|
||||
$this->applyQuery($name, $member, $value, $opts);
|
||||
} elseif ($location == 'headers') {
|
||||
$this->applyHeaderMap($name, $member, $value, $opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($bodyMembers)) {
|
||||
$this->payload($operation->getInput(), $bodyMembers, $opts);
|
||||
} else {
|
||||
if (!isset($opts['body']) && $this->hasPayloadParam($input, $payload)) {
|
||||
$this->payload($operation->getInput(), [], $opts);
|
||||
}
|
||||
}
|
||||
return $opts;
|
||||
}
|
||||
private function applyPayload(StructureShape $input, $name, array $args, array &$opts)
|
||||
{
|
||||
if (!isset($args[$name])) {
|
||||
return;
|
||||
}
|
||||
$m = $input->getMember($name);
|
||||
if ($m['streaming'] || ($m['type'] == 'string' || $m['type'] == 'blob')) {
|
||||
// Streaming bodies or payloads that are strings are
|
||||
// always just a stream of data.
|
||||
$opts['body'] = Psr7\Utils::streamFor($args[$name]);
|
||||
return;
|
||||
}
|
||||
$this->payload($m, $args[$name], $opts);
|
||||
}
|
||||
private function applyHeader($name, Shape $member, $value, array &$opts)
|
||||
{
|
||||
if ($member->getType() === 'timestamp') {
|
||||
$timestampFormat = !empty($member['timestampFormat']) ? $member['timestampFormat'] : 'rfc822';
|
||||
$value = TimestampShape::format($value, $timestampFormat);
|
||||
} elseif ($member->getType() === 'boolean') {
|
||||
$value = $value ? 'true' : 'false';
|
||||
}
|
||||
if ($member['jsonvalue']) {
|
||||
$value = \json_encode($value);
|
||||
if (empty($value) && \JSON_ERROR_NONE !== \json_last_error()) {
|
||||
throw new \InvalidArgumentException('Unable to encode the provided value' . ' with \'json_encode\'. ' . \json_last_error_msg());
|
||||
}
|
||||
$value = \base64_encode($value);
|
||||
}
|
||||
$opts['headers'][$member['locationName'] ?: $name] = $value;
|
||||
}
|
||||
/**
|
||||
* Note: This is currently only present in the Amazon S3 model.
|
||||
*/
|
||||
private function applyHeaderMap($name, Shape $member, array $value, array &$opts)
|
||||
{
|
||||
$prefix = $member['locationName'];
|
||||
foreach ($value as $k => $v) {
|
||||
$opts['headers'][$prefix . $k] = $v;
|
||||
}
|
||||
}
|
||||
private function applyQuery($name, Shape $member, $value, array &$opts)
|
||||
{
|
||||
if ($member instanceof MapShape) {
|
||||
$opts['query'] = isset($opts['query']) && \is_array($opts['query']) ? $opts['query'] + $value : $value;
|
||||
} elseif ($value !== null) {
|
||||
$type = $member->getType();
|
||||
if ($type === 'boolean') {
|
||||
$value = $value ? 'true' : 'false';
|
||||
} elseif ($type === 'timestamp') {
|
||||
$timestampFormat = !empty($member['timestampFormat']) ? $member['timestampFormat'] : 'iso8601';
|
||||
$value = TimestampShape::format($value, $timestampFormat);
|
||||
}
|
||||
$opts['query'][$member['locationName'] ?: $name] = $value;
|
||||
}
|
||||
}
|
||||
private function buildEndpoint(Operation $operation, array $args, array $opts)
|
||||
{
|
||||
// Create an associative array of variable definitions used in expansions
|
||||
$varDefinitions = $this->getVarDefinitions($operation, $args);
|
||||
$relative = \preg_replace_callback('/\\{([^\\}]+)\\}/', function (array $matches) use($varDefinitions) {
|
||||
$isGreedy = \substr($matches[1], -1, 1) == '+';
|
||||
$k = $isGreedy ? \substr($matches[1], 0, -1) : $matches[1];
|
||||
if (!isset($varDefinitions[$k])) {
|
||||
return '';
|
||||
}
|
||||
if ($isGreedy) {
|
||||
return \str_replace('%2F', '/', \rawurlencode($varDefinitions[$k]));
|
||||
}
|
||||
return \rawurlencode($varDefinitions[$k]);
|
||||
}, $operation['http']['requestUri']);
|
||||
// Add the query string variables or appending to one if needed.
|
||||
if (!empty($opts['query'])) {
|
||||
$relative = $this->appendQuery($opts['query'], $relative);
|
||||
}
|
||||
$path = $this->endpoint->getPath();
|
||||
//Accounts for trailing '/' in path when custom endpoint
|
||||
//is provided to endpointProviderV2
|
||||
if ($this->api->isModifiedModel() && $this->api->getServiceName() === 's3') {
|
||||
if (\substr($path, -1) === '/' && $relative[0] === '/') {
|
||||
$path = \rtrim($path, '/');
|
||||
}
|
||||
$relative = $path . $relative;
|
||||
if (\strpos($relative, '../') !== \false || \substr($relative, -2) === '..') {
|
||||
if ($relative[0] !== '/') {
|
||||
$relative = '/' . $relative;
|
||||
}
|
||||
return new Uri($this->endpoint->withPath('') . $relative);
|
||||
}
|
||||
}
|
||||
// If endpoint has path, remove leading '/' to preserve URI resolution.
|
||||
if ($path && $relative[0] === '/') {
|
||||
$relative = \substr($relative, 1);
|
||||
}
|
||||
//Append path to endpoint when leading '//...'
|
||||
// present as uri cannot be properly resolved
|
||||
if ($this->api->isModifiedModel() && \strpos($relative, '//') === 0) {
|
||||
return new Uri($this->endpoint . $relative);
|
||||
}
|
||||
// Expand path place holders using Amazon's slightly different URI
|
||||
// template syntax.
|
||||
return UriResolver::resolve($this->endpoint, new Uri($relative));
|
||||
}
|
||||
/**
|
||||
* @param StructureShape $input
|
||||
*/
|
||||
private function hasPayloadParam(StructureShape $input, $payload)
|
||||
{
|
||||
if ($payload) {
|
||||
$potentiallyEmptyTypes = ['blob', 'string'];
|
||||
if ($this->api->getMetadata('protocol') == 'rest-xml') {
|
||||
$potentiallyEmptyTypes[] = 'structure';
|
||||
}
|
||||
$payloadMember = $input->getMember($payload);
|
||||
if (\in_array($payloadMember['type'], $potentiallyEmptyTypes)) {
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
foreach ($input->getMembers() as $member) {
|
||||
if (!isset($member['location'])) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
private function appendQuery($query, $endpoint)
|
||||
{
|
||||
$append = Psr7\Query::build($query);
|
||||
return $endpoint .= \strpos($endpoint, '?') !== \false ? "&{$append}" : "?{$append}";
|
||||
}
|
||||
private function getVarDefinitions($command, $args)
|
||||
{
|
||||
$varDefinitions = [];
|
||||
foreach ($command->getInput()->getMembers() as $name => $member) {
|
||||
if ($member['location'] == 'uri') {
|
||||
$varDefinitions[$member['locationName'] ?: $name] = isset($args[$name]) ? $args[$name] : null;
|
||||
}
|
||||
}
|
||||
return $varDefinitions;
|
||||
}
|
||||
}
|
||||
42
vendor/Aws3/Aws/Api/Serializer/RestXmlSerializer.php
vendored
Normal file
42
vendor/Aws3/Aws/Api/Serializer/RestXmlSerializer.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Serializer;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\StructureShape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Service;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class RestXmlSerializer extends RestSerializer
|
||||
{
|
||||
/** @var XmlBody */
|
||||
private $xmlBody;
|
||||
/**
|
||||
* @param Service $api Service API description
|
||||
* @param string $endpoint Endpoint to connect to
|
||||
* @param XmlBody $xmlBody Optional XML formatter to use
|
||||
*/
|
||||
public function __construct(Service $api, $endpoint, XmlBody $xmlBody = null)
|
||||
{
|
||||
parent::__construct($api, $endpoint);
|
||||
$this->xmlBody = $xmlBody ?: new XmlBody($api);
|
||||
}
|
||||
protected function payload(StructureShape $member, array $value, array &$opts)
|
||||
{
|
||||
$opts['headers']['Content-Type'] = 'application/xml';
|
||||
$opts['body'] = $this->getXmlBody($member, $value);
|
||||
}
|
||||
/**
|
||||
* @param StructureShape $member
|
||||
* @param array $value
|
||||
* @return string
|
||||
*/
|
||||
private function getXmlBody(StructureShape $member, array $value)
|
||||
{
|
||||
$xmlBody = (string) $this->xmlBody->build($member, $value);
|
||||
$xmlBody = \str_replace("'", "'", $xmlBody);
|
||||
$xmlBody = \str_replace('\\r', " ", $xmlBody);
|
||||
$xmlBody = \str_replace('\\n', " ", $xmlBody);
|
||||
return $xmlBody;
|
||||
}
|
||||
}
|
||||
148
vendor/Aws3/Aws/Api/Serializer/XmlBody.php
vendored
Normal file
148
vendor/Aws3/Aws/Api/Serializer/XmlBody.php
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Serializer;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\MapShape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Service;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Shape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\StructureShape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\ListShape;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\TimestampShape;
|
||||
use XMLWriter;
|
||||
/**
|
||||
* @internal Formats the XML body of a REST-XML services.
|
||||
*/
|
||||
class XmlBody
|
||||
{
|
||||
/** @var \Aws\Api\Service */
|
||||
private $api;
|
||||
/**
|
||||
* @param Service $api API being used to create the XML body.
|
||||
*/
|
||||
public function __construct(Service $api)
|
||||
{
|
||||
$this->api = $api;
|
||||
}
|
||||
/**
|
||||
* Builds the XML body based on an array of arguments.
|
||||
*
|
||||
* @param Shape $shape Operation being constructed
|
||||
* @param array $args Associative array of arguments
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function build(Shape $shape, array $args)
|
||||
{
|
||||
$xml = new XMLWriter();
|
||||
$xml->openMemory();
|
||||
$xml->startDocument('1.0', 'UTF-8');
|
||||
$this->format($shape, $shape['locationName'] ?: $shape['name'], $args, $xml);
|
||||
$xml->endDocument();
|
||||
return $xml->outputMemory();
|
||||
}
|
||||
private function startElement(Shape $shape, $name, XMLWriter $xml)
|
||||
{
|
||||
$xml->startElement($name);
|
||||
if ($ns = $shape['xmlNamespace']) {
|
||||
$xml->writeAttribute(isset($ns['prefix']) ? "xmlns:{$ns['prefix']}" : 'xmlns', $shape['xmlNamespace']['uri']);
|
||||
}
|
||||
}
|
||||
private function format(Shape $shape, $name, $value, XMLWriter $xml)
|
||||
{
|
||||
// Any method mentioned here has a custom serialization handler.
|
||||
static $methods = ['add_structure' => \true, 'add_list' => \true, 'add_blob' => \true, 'add_timestamp' => \true, 'add_boolean' => \true, 'add_map' => \true, 'add_string' => \true];
|
||||
$type = 'add_' . $shape['type'];
|
||||
if (isset($methods[$type])) {
|
||||
$this->{$type}($shape, $name, $value, $xml);
|
||||
} else {
|
||||
$this->defaultShape($shape, $name, $value, $xml);
|
||||
}
|
||||
}
|
||||
private function defaultShape(Shape $shape, $name, $value, XMLWriter $xml)
|
||||
{
|
||||
$this->startElement($shape, $name, $xml);
|
||||
$xml->text($value);
|
||||
$xml->endElement();
|
||||
}
|
||||
private function add_structure(StructureShape $shape, $name, array $value, \XMLWriter $xml)
|
||||
{
|
||||
$this->startElement($shape, $name, $xml);
|
||||
foreach ($this->getStructureMembers($shape, $value) as $k => $definition) {
|
||||
$this->format($definition['member'], $definition['member']['locationName'] ?: $k, $definition['value'], $xml);
|
||||
}
|
||||
$xml->endElement();
|
||||
}
|
||||
private function getStructureMembers(StructureShape $shape, array $value)
|
||||
{
|
||||
$members = [];
|
||||
foreach ($value as $k => $v) {
|
||||
if ($v !== null && $shape->hasMember($k)) {
|
||||
$definition = ['member' => $shape->getMember($k), 'value' => $v];
|
||||
if ($definition['member']['xmlAttribute']) {
|
||||
// array_unshift_associative
|
||||
$members = [$k => $definition] + $members;
|
||||
} else {
|
||||
$members[$k] = $definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $members;
|
||||
}
|
||||
private function add_list(ListShape $shape, $name, array $value, XMLWriter $xml)
|
||||
{
|
||||
$items = $shape->getMember();
|
||||
if ($shape['flattened']) {
|
||||
$elementName = $name;
|
||||
} else {
|
||||
$this->startElement($shape, $name, $xml);
|
||||
$elementName = $items['locationName'] ?: 'member';
|
||||
}
|
||||
foreach ($value as $v) {
|
||||
$this->format($items, $elementName, $v, $xml);
|
||||
}
|
||||
if (!$shape['flattened']) {
|
||||
$xml->endElement();
|
||||
}
|
||||
}
|
||||
private function add_map(MapShape $shape, $name, array $value, XMLWriter $xml)
|
||||
{
|
||||
$xmlEntry = $shape['flattened'] ? $shape['locationName'] : 'entry';
|
||||
$xmlKey = $shape->getKey()['locationName'] ?: 'key';
|
||||
$xmlValue = $shape->getValue()['locationName'] ?: 'value';
|
||||
$this->startElement($shape, $name, $xml);
|
||||
foreach ($value as $key => $v) {
|
||||
$this->startElement($shape, $xmlEntry, $xml);
|
||||
$this->format($shape->getKey(), $xmlKey, $key, $xml);
|
||||
$this->format($shape->getValue(), $xmlValue, $v, $xml);
|
||||
$xml->endElement();
|
||||
}
|
||||
$xml->endElement();
|
||||
}
|
||||
private function add_blob(Shape $shape, $name, $value, XMLWriter $xml)
|
||||
{
|
||||
$this->startElement($shape, $name, $xml);
|
||||
$xml->writeRaw(\base64_encode($value));
|
||||
$xml->endElement();
|
||||
}
|
||||
private function add_timestamp(TimestampShape $shape, $name, $value, XMLWriter $xml)
|
||||
{
|
||||
$this->startElement($shape, $name, $xml);
|
||||
$timestampFormat = !empty($shape['timestampFormat']) ? $shape['timestampFormat'] : 'iso8601';
|
||||
$xml->writeRaw(TimestampShape::format($value, $timestampFormat));
|
||||
$xml->endElement();
|
||||
}
|
||||
private function add_boolean(Shape $shape, $name, $value, XMLWriter $xml)
|
||||
{
|
||||
$this->startElement($shape, $name, $xml);
|
||||
$xml->writeRaw($value ? 'true' : 'false');
|
||||
$xml->endElement();
|
||||
}
|
||||
private function add_string(Shape $shape, $name, $value, XMLWriter $xml)
|
||||
{
|
||||
if ($shape['xmlAttribute']) {
|
||||
$xml->writeAttribute($shape['locationName'] ?: $name, $value);
|
||||
} else {
|
||||
$this->defaultShape($shape, $name, $value, $xml);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user