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:
200
classes/providers/delivery/aws-cloudfront.php
Normal file
200
classes/providers/delivery/aws-cloudfront.php
Normal file
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Delivery;
|
||||
|
||||
use AS3CF_Plugin_Base;
|
||||
|
||||
class AWS_CloudFront extends Delivery_Provider {
|
||||
|
||||
/**
|
||||
* Which storage providers does the delivery provider support, empty means all.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $supported_storage_providers = array(
|
||||
'aws',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = 'Amazon Web Services';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = 'AWS';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = 'aws';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = 'CloudFront';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = 'CloudFront';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = 'cloudfront';
|
||||
|
||||
/**
|
||||
* Optional override of "Provider Name" + "Service Name" for friendly name for service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name = 'Amazon CloudFront';
|
||||
|
||||
/**
|
||||
* The slug for the service's quick start guide doc.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_quick_start_slug = 'cloudfront-setup';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $default_domain = 'cloudfront.net';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url = 'https://console.aws.amazon.com/cloudfront/home';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $block_public_access_supported = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $object_ownership_supported = true;
|
||||
|
||||
/**
|
||||
* AWS_CloudFront constructor.
|
||||
*
|
||||
* @param AS3CF_Plugin_Base $as3cf
|
||||
*/
|
||||
public function __construct( AS3CF_Plugin_Base $as3cf ) {
|
||||
parent::__construct( $as3cf );
|
||||
|
||||
// Autoloader.
|
||||
require_once $as3cf->get_plugin_sdks_dir_path() . '/Aws3/aws-autoloader.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function signed_urls_support_desc() {
|
||||
global $as3cf;
|
||||
|
||||
return sprintf(
|
||||
__( 'Private Media Supported with <a href="%s" target="_blank">upgrade</a>', 'amazon-s3-and-cloudfront' ),
|
||||
$as3cf::dbrains_url( '/wp-offload-media/upgrade/', array(
|
||||
'utm_campaign' => 'WP+Offload+S3',
|
||||
) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Block All Public Access is enabled and Delivery Provider supports it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_block_public_access_enabled_supported_desc() {
|
||||
global $as3cf;
|
||||
|
||||
$mesg = __( 'Since you\'re using Amazon CloudFront for delivery we recommend you keep Block All Public Access enabled.', 'amazon-s3-and-cloudfront' );
|
||||
$mesg .= ' ';
|
||||
$mesg .= $as3cf::settings_more_info_link( 'bucket', '', 'change+bucket+access' );
|
||||
|
||||
return $mesg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Block All Public Access is disabled and Delivery Provider supports it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_block_public_access_disabled_supported_desc() {
|
||||
global $as3cf;
|
||||
|
||||
$mesg = __( 'Since you\'re using Amazon CloudFront for delivery we recommend you enable Block All Public Access once you have set up the required Origin Access Identity and bucket policy.', 'amazon-s3-and-cloudfront' );
|
||||
$mesg .= ' ';
|
||||
$mesg .= $as3cf::settings_more_info_link( 'bucket', '', 'change+bucket+access' );
|
||||
|
||||
return $mesg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt text to confirm that everything is in place to enable Block All Public Access.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_block_public_access_confirm_setup_prompt() {
|
||||
global $as3cf;
|
||||
|
||||
$bucket_settings_doc = $as3cf::dbrains_url(
|
||||
'/wp-offload-media/doc/settings/',
|
||||
array( 'utm_campaign' => 'support+docs', 'utm_content' => 'change+bucket+access' ),
|
||||
'bucket'
|
||||
);
|
||||
|
||||
return sprintf(
|
||||
__( 'I have set up the required <a href="%1$s">Origin Access Identity and bucket policy</a>', 'amazon-s3-and-cloudfront' ),
|
||||
$bucket_settings_doc
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Object Ownership is enforced and Delivery Provider supports it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_object_ownership_enforced_supported_desc(): string {
|
||||
global $as3cf;
|
||||
|
||||
$mesg = __( 'Since you\'re using Amazon CloudFront for delivery we recommend you keep Object Ownership enforced.', 'amazon-s3-and-cloudfront' );
|
||||
$mesg .= ' ';
|
||||
$mesg .= $as3cf::settings_more_info_link( 'bucket', '', 'change+bucket+access' );
|
||||
|
||||
return $mesg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Object Ownership is not enforced and Delivery Provider supports it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_object_ownership_not_enforced_supported_desc(): string {
|
||||
global $as3cf;
|
||||
|
||||
$mesg = __( 'Since you\'re using Amazon CloudFront for delivery we recommend you enforce Object Ownership once you have set up the required Origin Access Identity and bucket policy.', 'amazon-s3-and-cloudfront' );
|
||||
$mesg .= ' ';
|
||||
$mesg .= $as3cf::settings_more_info_link( 'bucket', '', 'change+bucket+access' );
|
||||
|
||||
return $mesg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Title to be shown for provider's console link.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_console_title(): string {
|
||||
return _x( 'CloudFront Distributions', 'Provider console link text', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
}
|
||||
76
classes/providers/delivery/cloudflare.php
Normal file
76
classes/providers/delivery/cloudflare.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Delivery;
|
||||
|
||||
class Cloudflare extends Delivery_Provider {
|
||||
|
||||
/**
|
||||
* Which storage providers does the delivery provider support, empty means all.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $supported_storage_providers = array(
|
||||
// TODO: Add 'do' after testing and documenting.
|
||||
'aws',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = 'Cloudflare';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = 'Cloudflare';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = 'cloudflare';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = 'CDN';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = 'CDN';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = 'cdn';
|
||||
|
||||
/**
|
||||
* Optional override of "Provider Name" + "Service Name" for friendly name for service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name = 'Cloudflare';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_quick_start_slug = 'cloudflare-setup';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url = 'https://dash.cloudflare.com';
|
||||
|
||||
/**
|
||||
* Title to be shown for provider's console link.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_console_title(): string {
|
||||
return _x( 'Cloudflare Dashboard', 'Provider console link text', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
}
|
||||
927
classes/providers/delivery/delivery-provider.php
Normal file
927
classes/providers/delivery/delivery-provider.php
Normal file
@@ -0,0 +1,927 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Delivery;
|
||||
|
||||
use AS3CF_Utils;
|
||||
use DeliciousBrains\WP_Offload_Media\Settings_Validator_Trait;
|
||||
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
||||
use DeliciousBrains\WP_Offload_Media\Providers\Provider;
|
||||
use DeliciousBrains\WP_Offload_Media\Settings\Delivery_Check;
|
||||
use DeliciousBrains\WP_Offload_Media\Settings\Domain_Check;
|
||||
use DeliciousBrains\WP_Offload_Media\Settings\Validator_Interface;
|
||||
use Exception;
|
||||
use WP_Error as AS3CF_Result;
|
||||
|
||||
abstract class Delivery_Provider extends Provider implements Validator_Interface {
|
||||
use Settings_Validator_Trait;
|
||||
|
||||
const VALIDATOR_KEY = 'delivery';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name_setting_name = 'delivery-provider-service-name';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url_prefix_param = '/';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $delivery_domain_allowed = true;
|
||||
|
||||
/**
|
||||
* Which storage providers does the delivery provider support, empty means all.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $supported_storage_providers = array();
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $signed_urls_key_id_setting_name = 'signed-urls-key-id';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $signed_urls_key_file_path_setting_name = 'signed-urls-key-file-path';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $signed_urls_object_prefix_setting_name = 'signed-urls-object-prefix';
|
||||
|
||||
/**
|
||||
* If left empty, private signing key file not allowed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $signed_urls_key_id_constants = array();
|
||||
|
||||
/**
|
||||
* If left empty, private signing key file not allowed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $signed_urls_key_file_path_constants = array();
|
||||
|
||||
/**
|
||||
* If left empty, private signing key file not allowed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $signed_urls_object_prefix_constants = array();
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $validator_priority = 10;
|
||||
|
||||
/**
|
||||
* A description for the Rewrite Media URLs setting.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_rewrite_media_urls_desc(): string {
|
||||
global $as3cf;
|
||||
|
||||
$mesg = sprintf(
|
||||
_x( 'Serves offloaded media files by rewriting local URLs so that they point to %s.', 'Setting description', 'amazon-s3-and-cloudfront' ),
|
||||
static::get_provider_service_name()
|
||||
);
|
||||
$mesg .= ' ' . $as3cf::settings_more_info_link( 'serve-from-s3', 'How URL rewriting works' );
|
||||
|
||||
return $mesg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the delivery provider allow for setting a custom delivery domain?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function delivery_domain_allowed() {
|
||||
return static::$delivery_domain_allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* A description for the delivery domain settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_delivery_domain_desc(): string {
|
||||
return sprintf(
|
||||
__( 'Serves media from a custom domain that has been pointed to %1$s. <a href="%2$s" target="_blank">How to set a custom domain name</a>', 'amazon-s3-and-cloudfront' ),
|
||||
static::get_provider_service_name(),
|
||||
static::get_provider_service_quick_start_url() . '#create-cname'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of supported storage provider key names, empty array means all supported.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_supported_storage_providers() {
|
||||
return static::$supported_storage_providers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does provider support given storage provider?
|
||||
*
|
||||
* @param string $storage_provider_key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function supports_storage( $storage_provider_key ) {
|
||||
if ( empty( static::$supported_storage_providers ) || in_array( $storage_provider_key, static::$supported_storage_providers ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Title used in various places for enabling Signed URLs.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function signed_urls_option_name() {
|
||||
return __( 'Serve Private Media from Delivery Provider', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Description used in various places for enabling Signed URLs.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function signed_urls_option_description() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Title used in various places for the Signed URLs Key ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function signed_urls_key_id_name() {
|
||||
return __( 'Signing Key ID', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Description used in various places for the Signed URLs Key ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function signed_urls_key_id_description() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Title used in various places for the Signed URLs Key File Path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function signed_urls_key_file_path_name() {
|
||||
return __( 'Signing Key File Path', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Description used in various places for the Signed URLs Key File Path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function signed_urls_key_file_path_description() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Title used in various places for the Signed URLs Private Object Prefix.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function signed_urls_object_prefix_name() {
|
||||
return __( 'Private Bucket Path', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Description used in various places for the Signed URLs Private Object Prefix.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function signed_urls_object_prefix_description() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Description used in settings notice when all tests pass.
|
||||
*
|
||||
* @param array $recommendations Array of hints/recommendation to add to the success message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function delivery_tests_pass_desc( array $recommendations = array() ): string {
|
||||
$message = __( 'Delivery provider is successfully connected and serving offloaded media.', 'amazon-s3-and-cloudfront' );
|
||||
|
||||
if ( ! empty( $recommendations ) ) {
|
||||
$message = __( 'Delivery settings validated.', 'amazon-s3-and-cloudfront' );
|
||||
$message .= '<br><br>';
|
||||
$message .= join( '<br><br>', $recommendations );
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the provider able to use a private signing key file?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function use_signed_urls_key_file_allowed() {
|
||||
return ! empty( static::$signed_urls_key_id_constants ) && ! empty( static::$signed_urls_key_file_path_constants ) && ! empty( static::$signed_urls_object_prefix_constants );
|
||||
}
|
||||
|
||||
/**
|
||||
* If private signing key file allowed, returns first (preferred) key id constant that should be defined, otherwise blank.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function preferred_signed_urls_key_id_constant() {
|
||||
if ( static::use_signed_urls_key_file_allowed() ) {
|
||||
return static::$signed_urls_key_id_constants[0];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If private signing key file allowed, returns first (preferred) key file path constant that should be defined, otherwise blank.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function preferred_signed_urls_key_file_path_constant() {
|
||||
if ( static::use_signed_urls_key_file_allowed() ) {
|
||||
return static::$signed_urls_key_file_path_constants[0];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If private signing key file allowed, returns first (preferred) object prefix constant that should be defined, otherwise blank.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function preferred_signed_urls_object_prefix_constant() {
|
||||
if ( static::use_signed_urls_key_file_allowed() ) {
|
||||
return static::$signed_urls_object_prefix_constants[0];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if private signing key id and file path set.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function use_signed_urls_key_file() {
|
||||
if ( ! static::use_signed_urls_key_file_allowed() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->get_signed_urls_key_id() && $this->get_signed_urls_key_file_path() && $this->get_signed_urls_object_prefix();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the private signing key id from a constant or the settings.
|
||||
*
|
||||
* Falls back to settings if constant is not defined.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_signed_urls_key_id() {
|
||||
if ( static::is_signed_urls_key_id_constant_defined() ) {
|
||||
$constant = static::signed_urls_key_id_constant();
|
||||
|
||||
return $constant ? constant( $constant ) : '';
|
||||
}
|
||||
|
||||
return $this->as3cf->get_core_setting( static::$signed_urls_key_id_setting_name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the private signing key file path from a constant or the settings.
|
||||
*
|
||||
* Falls back to settings if constant is not defined.
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_signed_urls_key_file_path() {
|
||||
if ( static::is_signed_urls_key_file_path_constant_defined() ) {
|
||||
$constant = static::signed_urls_key_file_path_constant();
|
||||
|
||||
if ( $constant ) {
|
||||
return $this->validate_signed_urls_key_file_path( constant( $constant ) );
|
||||
} else {
|
||||
// Constant defined but value is not a non-empty string.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->validate_signed_urls_key_file_path( $this->as3cf->get_core_setting( static::$signed_urls_key_file_path_setting_name, false ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the private signing object prefix from a constant or the settings.
|
||||
*
|
||||
* Falls back to settings if constant is not defined.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_signed_urls_object_prefix() {
|
||||
if ( static::is_signed_urls_object_prefix_constant_defined() ) {
|
||||
$constant = static::signed_urls_object_prefix_constant();
|
||||
|
||||
return $constant ? constant( $constant ) : '';
|
||||
}
|
||||
|
||||
return $this->as3cf->get_core_setting( static::$signed_urls_object_prefix_setting_name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a private signing key file path to ensure it exists, is readable, and contains something.
|
||||
*
|
||||
* @param string $signed_urls_key_file_path
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function validate_signed_urls_key_file_path( $signed_urls_key_file_path ) {
|
||||
$notice_id = ( $this->as3cf->saving_settings() ? 'temp-' : '' ) . 'validate-signed-urls-key-file-path';
|
||||
$this->as3cf->notices->remove_notice_by_id( $notice_id );
|
||||
|
||||
$notice_settings = array(
|
||||
'type' => 'error',
|
||||
'only_show_in_settings' => true,
|
||||
'only_show_on_tab' => 'media',
|
||||
'custom_id' => $notice_id,
|
||||
'hide_on_parent' => ! $this->as3cf->saving_settings(),
|
||||
);
|
||||
|
||||
if ( empty( $signed_urls_key_file_path ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! file_exists( $signed_urls_key_file_path ) ) {
|
||||
$this->as3cf->notices->add_notice( __( 'Given Signing Key File Path is invalid or could not be accessed.', 'amazon-s3-and-cloudfront' ), $notice_settings );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$value = file_get_contents( $signed_urls_key_file_path );
|
||||
|
||||
// An exception isn't always thrown, so check value instead.
|
||||
if ( empty( $value ) ) {
|
||||
$this->as3cf->notices->add_notice( __( 'Could not read Signing Key File Path\'s contents.', 'amazon-s3-and-cloudfront' ), $notice_settings );
|
||||
|
||||
return false;
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
$this->as3cf->notices->add_notice( __( 'Could not read Signing Key File Path\'s contents.', 'amazon-s3-and-cloudfront' ), $notice_settings );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// File exists and has contents.
|
||||
return $signed_urls_key_file_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if private signing key id constant is defined.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_signed_urls_key_id_constant_defined() {
|
||||
$constant = static::signed_urls_key_id_constant();
|
||||
|
||||
return $constant && constant( $constant );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if private signing key file path constant is defined, for speed, does not check validity of file path.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_signed_urls_key_file_path_constant_defined() {
|
||||
$constant = static::signed_urls_key_file_path_constant();
|
||||
|
||||
return $constant && constant( $constant );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if private signing object prefix constant is defined.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_signed_urls_object_prefix_constant_defined() {
|
||||
$constant = static::signed_urls_object_prefix_constant();
|
||||
|
||||
return $constant && constant( $constant );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the constant used to define the private signing key id.
|
||||
*
|
||||
* @return string|false Constant name if defined, otherwise false
|
||||
*/
|
||||
public static function signed_urls_key_id_constant() {
|
||||
return AS3CF_Utils::get_first_defined_constant( static::$signed_urls_key_id_constants );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the constant used to define the private signing key file path.
|
||||
*
|
||||
* @return string|false Constant name if defined, otherwise false
|
||||
*/
|
||||
public static function signed_urls_key_file_path_constant() {
|
||||
return AS3CF_Utils::get_first_defined_constant( static::$signed_urls_key_file_path_constants );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the constant used to define the private signing object prefix.
|
||||
*
|
||||
* @return string|false Constant name if defined, otherwise false
|
||||
*/
|
||||
public static function signed_urls_object_prefix_constant() {
|
||||
return AS3CF_Utils::get_first_defined_constant( static::$signed_urls_object_prefix_constants );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a site specific file path example for a signed URL key file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function signed_urls_key_file_path_placeholder() {
|
||||
$filename = 'pk-12345678ABCDE.pem';
|
||||
|
||||
return dirname( ABSPATH ) . DIRECTORY_SEPARATOR . $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a fully formed and potentially expiring signed URL for the given Item.
|
||||
*
|
||||
* @param Item $as3cf_item
|
||||
* @param string $path The required bucket path, may differ from Item's path if image subsize etc.
|
||||
* @param string $domain The domain to use for the URL if at all possible.
|
||||
* @param string $scheme The scheme to be used if possible.
|
||||
* @param array|null $headers Optional array of headers to be passed along to underlying requests.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_url( Item $as3cf_item, $path, $domain, $scheme, $headers = array() ) {
|
||||
$item_path = $this->as3cf->maybe_update_delivery_path( $path, $domain );
|
||||
$item_path = AS3CF_Utils::encode_filename_in_path( $item_path );
|
||||
|
||||
return $scheme . '://' . $domain . '/' . $item_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a fully formed and expiring signed URL for the given Item.
|
||||
*
|
||||
* @param Item $as3cf_item
|
||||
* @param string $path The required bucket path, may differ from Item's path if image subsize etc.
|
||||
* @param string $domain The domain to use for the URL if at all possible.
|
||||
* @param string $scheme The scheme to be used if possible.
|
||||
* @param int $timestamp URL expires at the given time.
|
||||
* @param array|null $headers Optional array of headers to be passed along to underlying requests.
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get_signed_url( Item $as3cf_item, $path, $domain, $scheme, $timestamp, $headers = array() ) {
|
||||
/**
|
||||
* This default implementation defers to the storage provider's signed URLs.
|
||||
* Therefore, we need to use a storage provider client instance for the item's region.
|
||||
*/
|
||||
if ( ! empty( $as3cf_item->region() ) && ( $this->as3cf->get_storage_provider()->region_required() || $this->as3cf->get_storage_provider()->get_default_region() !== $as3cf_item->region() ) ) {
|
||||
$region = $this->as3cf->get_storage_provider()->sanitize_region( $as3cf_item->region() );
|
||||
} else {
|
||||
$region = '';
|
||||
}
|
||||
|
||||
// Storage Provider may support signing custom domain, e.g. GCP.
|
||||
if ( $this->as3cf->get_storage_provider()->get_domain() !== $domain ) {
|
||||
$headers['BaseURL'] = $scheme . '://' . $domain;
|
||||
}
|
||||
|
||||
return $this->as3cf->get_provider_client( $region )->get_object_url( $as3cf_item->bucket(), $path, $timestamp, $headers );
|
||||
}
|
||||
|
||||
/**
|
||||
* A short description of whether delivery is fast (distributed) or not.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function edge_server_support_desc() {
|
||||
return __( 'Fast', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* A short description of whether signed URLs for private media is supported or not.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function signed_urls_support_desc() {
|
||||
return __( 'No Private Media', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Block All Public Access is enabled and Delivery Provider does not support it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_block_public_access_enabled_unsupported_desc() {
|
||||
return sprintf(
|
||||
__( 'You need to disable Block All Public Access so that %1$s can access your bucket for delivery.', 'amazon-s3-and-cloudfront' ),
|
||||
static::get_provider_name()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt text to confirm that everything is in place to enable Block All Public Access without issues for Delivery Provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_block_public_access_confirm_setup_prompt() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Object Ownership is enforced and Delivery Provider does not support it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_object_ownership_enforced_unsupported_desc(): string {
|
||||
global $as3cf;
|
||||
|
||||
$object_ownership_doc = $as3cf::dbrains_url(
|
||||
'/wp-offload-media/doc/amazon-s3-bucket-object-ownership/',
|
||||
array( 'utm_campaign' => 'support+docs', 'utm_content' => 'change+bucket+access' )
|
||||
);
|
||||
|
||||
return sprintf(
|
||||
__( 'You need to edit the bucket\'s Object Ownership setting and <a href="%1$s">enable ACLs</a> so that %2$s can access your bucket for delivery.', 'amazon-s3-and-cloudfront' ),
|
||||
$object_ownership_doc,
|
||||
static::get_provider_name()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice text for when a public file can't be accessed.
|
||||
*
|
||||
* @param string $error_message
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_cannot_access_public_file_desc( string $error_message ): string {
|
||||
return sprintf(
|
||||
__(
|
||||
'Offloaded media URLs may be broken. %1$s <a href="%2$s" target="_blank">Read more</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
$error_message,
|
||||
static::get_provider_service_quick_start_url()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice text for when a private file can't be accessed using a signed private URL.
|
||||
*
|
||||
* @param string $error_message
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_cannot_access_private_file_desc( string $error_message ): string {
|
||||
return sprintf(
|
||||
__(
|
||||
'Private offloaded media URLs may be broken. %1$s <a href="%2$s" target="_blank">Read more</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
$error_message,
|
||||
static::get_provider_service_quick_start_url()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice text for when a private file can be accessed using an unsigned URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_unsigned_url_can_access_private_file_desc(): string {
|
||||
global $as3cf;
|
||||
|
||||
$storage_provider = $as3cf->get_storage_provider();
|
||||
|
||||
return apply_filters(
|
||||
'as3cf_get_unsigned_url_can_access_private_file_desc_' . $storage_provider->get_provider_key_name(),
|
||||
sprintf(
|
||||
__(
|
||||
'Delivery provider is connected, but private media is currently exposed through unsigned URLs. Restore privacy by verifying the configuration of private media settings. <a href="%1$s" target="_blank">Read more</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
static::get_provider_service_quick_start_url()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt text to confirm that everything is in place to enforce Object Ownership without issues for Delivery Provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_object_ownership_confirm_setup_prompt(): string {
|
||||
// Using the same text as for the Block Public Access prompt.
|
||||
return static::get_block_public_access_confirm_setup_prompt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the link to the provider's console.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param string $prefix
|
||||
* @param string $region
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* NOTE: By default delivery providers append the suffix to the base console URL only.
|
||||
* The usual bucket, prefix and region params are still processed and the suffix
|
||||
* may end up being either a path, params or both that get deeper into the console.
|
||||
*/
|
||||
public function get_console_url( string $bucket = '', string $prefix = '', string $region = '' ): string {
|
||||
if ( '' !== $prefix ) {
|
||||
$prefix = $this->get_console_url_prefix_param() . apply_filters( 'as3cf_' . static::$provider_key_name . '_' . static::$service_key_name . '_console_url_prefix_value', $prefix );
|
||||
}
|
||||
|
||||
$suffix = apply_filters( 'as3cf_' . static::$provider_key_name . '_' . static::$service_key_name . '_console_url_suffix_param', $this->get_console_url_suffix_param( $bucket, $prefix, $region ) );
|
||||
|
||||
return apply_filters( 'as3cf_' . static::$provider_key_name . '_' . static::$service_key_name . '_console_url', $this->console_url ) . $suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the suffix param to append to the link to the provider's console.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param string $prefix
|
||||
* @param string $region
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_console_url_suffix_param( string $bucket = '', string $prefix = '', string $region = '' ): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate delivery settings for the configured provider for the delivery status indicator.
|
||||
*
|
||||
* @param bool $force Force time resource consuming or state altering tests to run.
|
||||
*
|
||||
* @return AS3CF_Result
|
||||
*/
|
||||
public function validate_settings( bool $force = false ): AS3CF_Result {
|
||||
$storage_provider = $this->as3cf->get_storage_provider();
|
||||
$bucket = $this->as3cf->get_setting( 'bucket' );
|
||||
$region = $this->as3cf->get_setting( 'region' );
|
||||
$recommendations = array();
|
||||
|
||||
// Validate the delivery provider key.
|
||||
$valid_delivery_provider_key = $this->validate_delivery_provider_key();
|
||||
if ( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS !== $valid_delivery_provider_key->get_error_code() ) {
|
||||
return $valid_delivery_provider_key;
|
||||
}
|
||||
|
||||
// The storage provider has lower priority and runs before delivery, so we should always have a fresh result.
|
||||
if ( $this->is_result_code_unknown_or_error( $this->as3cf->validation_manager->get_validation_status( 'storage' ) ) ) {
|
||||
return new AS3CF_Result(
|
||||
Validator_Interface::AS3CF_STATUS_MESSAGE_WARNING,
|
||||
__( 'Delivery of offloaded media cannot be tested until the storage provider is successfully connected. See "Storage Settings" for more information.', 'amazon-s3-and-cloudfront' )
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure the storage provider client is initiated before BAPA/OOE tests.
|
||||
$storage_provider->get_client( array( 'region' => $region ) );
|
||||
|
||||
// If storage BAPA setting is enabled, validate that it's supported by delivery provider.
|
||||
if ( ! static::block_public_access_supported() && $storage_provider->block_public_access_supported() && $storage_provider->public_access_blocked( $bucket ) ) {
|
||||
return new AS3CF_Result(
|
||||
Validator_Interface::AS3CF_STATUS_MESSAGE_ERROR,
|
||||
sprintf(
|
||||
_x(
|
||||
'Offloaded media cannot be delivered because <strong>Block All Public Access</strong> is enabled. <a href="%1$s">Edit bucket security</a>',
|
||||
'Delivery setting notice for issue with BAPA enabled on Storage Provider',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
'#/storage/security'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$delivery_domain_settings = $this->validate_delivery_domain();
|
||||
if ( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS !== $delivery_domain_settings->get_error_code() ) {
|
||||
return $delivery_domain_settings;
|
||||
}
|
||||
|
||||
// Are settings for delivering signed URLs valid?
|
||||
$signed_url_settings = $this->validate_signed_url_settings();
|
||||
if ( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS !== $signed_url_settings->get_error_code() ) {
|
||||
return $signed_url_settings;
|
||||
}
|
||||
|
||||
// Test accessing files via provider.
|
||||
$connection_test = $this->provider_connection_test();
|
||||
if ( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS !== $connection_test->get_error_code() ) {
|
||||
return $connection_test;
|
||||
}
|
||||
|
||||
// Is Deliver Offloaded Media enabled?
|
||||
$deliver_media = $this->validate_deliver_offloaded_media_enabled();
|
||||
if ( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS !== $deliver_media->get_error_code() ) {
|
||||
return $deliver_media;
|
||||
}
|
||||
|
||||
// All good.
|
||||
return new AS3CF_Result(
|
||||
count( $recommendations ) === 0 ? Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS : Validator_Interface::AS3CF_STATUS_MESSAGE_WARNING,
|
||||
static::delivery_tests_pass_desc( $recommendations )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the delivery provider key provided in settings is valid for the storage provider. This should
|
||||
* only happen if the user is using defines statements or has manually edited settings in the db.
|
||||
*
|
||||
* @return AS3CF_Result
|
||||
*/
|
||||
protected function validate_delivery_provider_key(): AS3CF_Result {
|
||||
$storage_provider = $this->as3cf->get_storage_provider();
|
||||
$storage_provider_key = $storage_provider->get_provider_key_name();
|
||||
$delivery_provider_key = $this->as3cf->get_core_setting( 'delivery-provider' );
|
||||
|
||||
$valid_providers = array_keys( $this->as3cf->get_available_delivery_provider_details( $storage_provider_key ) );
|
||||
if ( ! in_array( $delivery_provider_key, $valid_providers ) ) {
|
||||
return new AS3CF_Result(
|
||||
Validator_Interface::AS3CF_STATUS_MESSAGE_ERROR,
|
||||
sprintf(
|
||||
__( 'An invalid delivery provider has been defined for the active storage provider. Please use %1$s.', 'amazon-s3-and-cloudfront' ),
|
||||
"<code>" . AS3CF_Utils::human_readable_join( "</code>, <code>", "</code> or <code>", $valid_providers ) . "</code>"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return new AS3CF_Result( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate settings for serving signed URLs.
|
||||
*
|
||||
* @return AS3CF_Result
|
||||
*/
|
||||
protected function validate_signed_url_settings(): AS3CF_Result {
|
||||
return new AS3CF_Result( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Deliver Offloaded Media is enabled.
|
||||
*
|
||||
* @return AS3CF_Result
|
||||
*/
|
||||
protected function validate_deliver_offloaded_media_enabled(): AS3CF_Result {
|
||||
if ( ! $this->as3cf->get_setting( 'serve-from-s3' ) ) {
|
||||
return new AS3CF_Result(
|
||||
Validator_Interface::AS3CF_STATUS_MESSAGE_WARNING,
|
||||
__(
|
||||
'Delivery provider is successfully connected, but offloaded media will not be served until <strong>Deliver Offloaded Media</strong> is enabled. In the meantime, local media is being served if available.',
|
||||
'amazon-s3-and-cloudfront'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return new AS3CF_Result( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test settings for custom delivery domain.
|
||||
*
|
||||
* @return AS3CF_Result
|
||||
*/
|
||||
protected function validate_delivery_domain(): AS3CF_Result {
|
||||
$delivery_domain = $this->as3cf->get_setting( 'delivery-domain' );
|
||||
$enable_delivery_domain = $this->as3cf->get_setting( 'enable-delivery-domain' );
|
||||
|
||||
if ( ! static::delivery_domain_allowed() ) {
|
||||
return new AS3CF_Result( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS );
|
||||
}
|
||||
|
||||
// Custom domain enabled?
|
||||
if ( ! $enable_delivery_domain || empty( $delivery_domain ) ) {
|
||||
return new AS3CF_Result(
|
||||
Validator_Interface::AS3CF_STATUS_MESSAGE_WARNING,
|
||||
sprintf(
|
||||
__(
|
||||
'Offloaded media cannot be delivered from the CDN until a delivery domain is set. <a href="%1$s" target="_blank">Read more</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
static::get_provider_service_quick_start_url() . '#configure-plugin'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Is the custom domain name valid?
|
||||
$domain_check = new Domain_Check( $delivery_domain );
|
||||
$domain_issue = $domain_check->get_validation_issue();
|
||||
if ( ! empty( $domain_issue ) ) {
|
||||
return new AS3CF_Result(
|
||||
Validator_Interface::AS3CF_STATUS_MESSAGE_ERROR,
|
||||
sprintf(
|
||||
__(
|
||||
'Offloaded media URLs may be broken due to an invalid delivery domain. %1$s <a href="%2$s">How to set a delivery domain</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
$domain_issue,
|
||||
static::get_provider_service_quick_start_url() . '#configure-plugin'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return new AS3CF_Result( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test public and private delivery from bucket using test files.
|
||||
*
|
||||
* @return AS3CF_Result
|
||||
*/
|
||||
protected function provider_connection_test(): AS3CF_Result {
|
||||
$delivery_check = new Delivery_Check( $this->as3cf );
|
||||
|
||||
$setup_files = $delivery_check->setup_test_file( false );
|
||||
if ( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS !== $setup_files->get_error_code() ) {
|
||||
return new AS3CF_Result( $setup_files->get_error_code(), $setup_files->get_error_message() );
|
||||
}
|
||||
|
||||
// Verify that the public file is accessible.
|
||||
$delivery_issue = $delivery_check->test_public_file_access();
|
||||
if ( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS !== $delivery_issue->get_error_code() ) {
|
||||
$delivery_check->remove_test_files();
|
||||
|
||||
return new AS3CF_Result(
|
||||
$delivery_issue->get_error_code(),
|
||||
static::get_cannot_access_public_file_desc( $delivery_issue->get_error_message() )
|
||||
);
|
||||
}
|
||||
|
||||
$setup_files = $delivery_check->setup_test_file( true );
|
||||
if ( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS !== $setup_files->get_error_code() ) {
|
||||
return new AS3CF_Result( $setup_files->get_error_code(), $setup_files->get_error_message() );
|
||||
}
|
||||
|
||||
// Verify that the private file is accessible.
|
||||
$delivery_issue = $delivery_check->test_private_file_access();
|
||||
if ( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS !== $delivery_issue->get_error_code() ) {
|
||||
$delivery_check->remove_test_files();
|
||||
|
||||
return new AS3CF_Result(
|
||||
$delivery_issue->get_error_code(),
|
||||
static::get_cannot_access_private_file_desc( $delivery_issue->get_error_message() )
|
||||
);
|
||||
}
|
||||
|
||||
// Verify that the private file can't be accessed with unsigned URL.
|
||||
$delivery_issue = $delivery_check->test_private_file_access_unsigned();
|
||||
if ( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS !== $delivery_issue->get_error_code() ) {
|
||||
$delivery_check->remove_test_files();
|
||||
|
||||
return new AS3CF_Result(
|
||||
$delivery_issue->get_error_code(),
|
||||
static::get_unsigned_url_can_access_private_file_desc()
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure all test files are removed.
|
||||
$delivery_check->remove_test_files();
|
||||
|
||||
return new AS3CF_Result( Validator_Interface::AS3CF_STATUS_MESSAGE_SUCCESS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the actions that are fired when the settings that the validator
|
||||
* is responsible for are saved.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function post_save_settings_actions(): array {
|
||||
return array( 'as3cf_post_save_settings', 'as3cf_post_update_bucket' );
|
||||
}
|
||||
}
|
||||
102
classes/providers/delivery/digitalocean-spaces-cdn.php
Normal file
102
classes/providers/delivery/digitalocean-spaces-cdn.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Delivery;
|
||||
|
||||
class DigitalOcean_Spaces_CDN extends Delivery_Provider {
|
||||
|
||||
/**
|
||||
* Which storage providers does the delivery provider support, empty means all.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $supported_storage_providers = array(
|
||||
'do',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = 'DigitalOcean';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = 'DigitalOcean';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = 'do';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = 'Spaces CDN';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = 'Spaces CDN';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = 'spaces-cdn';
|
||||
|
||||
/**
|
||||
* Optional override of "Provider Name" + "Service Name" for friendly name for service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name = 'DigitalOcean Spaces CDN';
|
||||
|
||||
/**
|
||||
* The slug for the service's quick start guide doc.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_quick_start_slug = 'digitalocean-spaces-cdn-setup';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $default_domain = 'cdn.digitaloceanspaces.com';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url = 'https://cloud.digitalocean.com/spaces/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url_prefix_param = '?path=';
|
||||
|
||||
/**
|
||||
* Get the link to the provider's console.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param string $prefix
|
||||
* @param string $region
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* NOTE: DigitalOcean Spaces CDN is tied to the Space and does not have a separate means of access.
|
||||
*/
|
||||
public function get_console_url( string $bucket = '', string $prefix = '', string $region = '' ): string {
|
||||
return $this->as3cf->get_storage_provider()->get_console_url( $bucket, $prefix, $region );
|
||||
}
|
||||
|
||||
/**
|
||||
* Title to be shown for provider's console link.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_console_title(): string {
|
||||
return _x( 'Control Panel', 'Provider console link text', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
}
|
||||
84
classes/providers/delivery/gcp-cdn.php
Normal file
84
classes/providers/delivery/gcp-cdn.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Delivery;
|
||||
|
||||
class GCP_CDN extends Delivery_Provider {
|
||||
|
||||
/**
|
||||
* Which storage providers does the delivery provider support, empty means all.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $supported_storage_providers = array(
|
||||
'gcp',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = 'Google Cloud Platform';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = 'GCP';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = 'gcp';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = 'Cloud CDN';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = 'Cloud CDN';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = 'cdn';
|
||||
|
||||
/**
|
||||
* Optional override of "Provider Name" + "Service Name" for friendly name for service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name = 'GCP Cloud CDN';
|
||||
|
||||
/**
|
||||
* The slug for the service's quick start guide doc.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_quick_start_slug = 'how-to-set-up-a-custom-domain-cdn-for-google-cloud-storage';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url = 'https://console.cloud.google.com/net-services/cdn/list';
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function signed_urls_support_desc() {
|
||||
return __( 'Private Media Supported', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Title to be shown for provider's console link.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_console_title(): string {
|
||||
return _x( 'Google Cloud Console', 'Provider console link text', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
}
|
||||
76
classes/providers/delivery/keycdn.php
Normal file
76
classes/providers/delivery/keycdn.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Delivery;
|
||||
|
||||
class KeyCDN extends Delivery_Provider {
|
||||
|
||||
/**
|
||||
* Which storage providers does the delivery provider support, empty means all.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $supported_storage_providers = array(
|
||||
// TODO: Add 'aws' after testing and documenting.
|
||||
'do',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = 'KeyCDN';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = 'KeyCDN';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = 'keycdn';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = 'CDN';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = 'CDN';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = 'cdn';
|
||||
|
||||
/**
|
||||
* Optional override of "Provider Name" + "Service Name" for friendly name for service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name = 'KeyCDN';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_quick_start_slug = 'how-to-set-up-a-custom-domain-for-digitalocean-spaces-with-keycdn';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url = 'https://app.keycdn.com/zones/index';
|
||||
|
||||
/**
|
||||
* Title to be shown for provider's console link.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_console_title(): string {
|
||||
return _x( 'KeyCDN Dashboard', 'Provider console link text', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
}
|
||||
61
classes/providers/delivery/other.php
Normal file
61
classes/providers/delivery/other.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Delivery;
|
||||
|
||||
/**
|
||||
* Class Other
|
||||
*
|
||||
* This is a fallback CDN where the user can add their own name.
|
||||
*
|
||||
* @package DeliciousBrains\WP_Offload_Media\Providers\Delivery
|
||||
*/
|
||||
class Other extends Delivery_Provider {
|
||||
|
||||
/**
|
||||
* Can the displayed provider service name be overridden by the user?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $provider_service_name_override_allowed = true;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = 'Other';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = 'Other';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = 'other';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = 'Unknown';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = 'Unknown';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = 'unknown';
|
||||
|
||||
/**
|
||||
* Optional override of "Provider Name" + "Service Name" for friendly name for service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name = 'Other';
|
||||
}
|
||||
76
classes/providers/delivery/stackpath.php
Normal file
76
classes/providers/delivery/stackpath.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Delivery;
|
||||
|
||||
class StackPath extends Delivery_Provider {
|
||||
|
||||
/**
|
||||
* Which storage providers does the delivery provider support, empty means all.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $supported_storage_providers = array(
|
||||
// TODO: Add 'do' after testing and documenting.
|
||||
'aws',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = 'StackPath';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = 'StackPath';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = 'stackpath';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = 'CDN';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = 'CDN';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = 'cdn';
|
||||
|
||||
/**
|
||||
* Optional override of "Provider Name" + "Service Name" for friendly name for service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name = 'StackPath';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_quick_start_slug = 'stackpath-setup';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url = 'https://control.stackpath.com/stacks';
|
||||
|
||||
/**
|
||||
* Title to be shown for provider's console link.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_console_title(): string {
|
||||
return _x( 'Control Portal', 'Provider console link text', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
}
|
||||
161
classes/providers/delivery/storage.php
Normal file
161
classes/providers/delivery/storage.php
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Delivery;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
||||
|
||||
class Storage extends Delivery_Provider {
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $delivery_domain_allowed = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = 'Storage Provider';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = 'Storage';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = 'storage';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = 'Bucket';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = 'Bucket';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = 'bucket';
|
||||
|
||||
/**
|
||||
* Returns the full name for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_provider_name() {
|
||||
/** @var \Amazon_S3_And_CloudFront $as3cf */
|
||||
global $as3cf;
|
||||
|
||||
return $as3cf->get_storage_provider()->get_provider_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full name for the service.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_service_name() {
|
||||
/** @var \Amazon_S3_And_CloudFront $as3cf */
|
||||
global $as3cf;
|
||||
|
||||
return $as3cf->get_storage_provider()->get_service_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full name for the provider and service for display.
|
||||
*
|
||||
* @param bool $override_allowed Not used.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_provider_service_name( $override_allowed = true ) {
|
||||
/** @var \Amazon_S3_And_CloudFront $as3cf */
|
||||
global $as3cf;
|
||||
|
||||
return $as3cf->get_storage_provider()->get_provider_service_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function edge_server_support_desc() {
|
||||
return __( 'Slow', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function signed_urls_support_desc() {
|
||||
return __( 'Private Media Supported', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get_url( Item $as3cf_item, $path, $domain, $scheme, $headers = array() ) {
|
||||
$lookup_domain = $this->as3cf->get_storage_provider_instance( $as3cf_item->provider() )->get_url_domain( $as3cf_item->bucket(), $as3cf_item->region() );
|
||||
|
||||
return parent::get_url( $as3cf_item, $path, $lookup_domain, $scheme, $headers );
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Block All Public Access is enabled and Delivery Provider does not support it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_block_public_access_enabled_unsupported_desc() {
|
||||
return __( 'You need to disable Block All Public Access so that your bucket is accessible for delivery.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Object Ownership is enforced and Delivery Provider does not support it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_object_ownership_enforced_unsupported_desc(): string {
|
||||
global $as3cf;
|
||||
|
||||
$object_ownership_doc = $as3cf::dbrains_url(
|
||||
'/wp-offload-media/doc/amazon-s3-bucket-object-ownership/',
|
||||
array( 'utm_campaign' => 'support+docs', 'utm_content' => 'change+bucket+access' )
|
||||
);
|
||||
|
||||
return sprintf(
|
||||
__( 'You need to edit the bucket\'s Object Ownership setting and <a href="%1$s">enable ACLs</a> or add a <a href="%2$s">Bucket Policy</a> so that objects can be made available for delivery.', 'amazon-s3-and-cloudfront' ),
|
||||
$object_ownership_doc . '#acls',
|
||||
$object_ownership_doc . '#bucket-policy'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the link to the provider's console.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param string $prefix
|
||||
* @param string $region
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_console_url( string $bucket = '', string $prefix = '', string $region = '' ): string {
|
||||
return $this->as3cf->get_storage_provider()->get_console_url( $bucket, $prefix, $region );
|
||||
}
|
||||
|
||||
/**
|
||||
* Title to be shown for provider's console link.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_console_title(): string {
|
||||
global $as3cf;
|
||||
|
||||
return $as3cf->get_storage_provider()->get_console_title();
|
||||
}
|
||||
}
|
||||
396
classes/providers/provider.php
Normal file
396
classes/providers/provider.php
Normal file
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers;
|
||||
|
||||
use Amazon_S3_And_CloudFront;
|
||||
use AS3CF_Plugin_Base;
|
||||
|
||||
abstract class Provider {
|
||||
|
||||
/**
|
||||
* @var Amazon_S3_And_CloudFront
|
||||
*/
|
||||
protected $as3cf;
|
||||
|
||||
/**
|
||||
* Can the displayed provider service name be overridden by the user?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $provider_service_name_override_allowed = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name_setting_name = 'provider-service-name';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = '';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = '';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = '';
|
||||
|
||||
/**
|
||||
* Optional override of "Provider Name" + "Service Name" for friendly name for service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name = '';
|
||||
|
||||
/**
|
||||
* The slug for the service's quick start guide doc.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_quick_start_slug = 'quick-start-guide';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $default_domain = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url_prefix_param = '';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $block_public_access_supported = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $object_ownership_supported = false;
|
||||
|
||||
/**
|
||||
* Provider constructor.
|
||||
*
|
||||
* @param AS3CF_Plugin_Base $as3cf
|
||||
*/
|
||||
public function __construct( AS3CF_Plugin_Base $as3cf ) {
|
||||
$this->as3cf = $as3cf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full name for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_provider_name() {
|
||||
return static::$provider_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key friendly name for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_provider_key_name() {
|
||||
return static::$provider_key_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full name for the service.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_service_name() {
|
||||
return static::$service_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key friendly name for the service.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_service_key_name() {
|
||||
return static::$service_key_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full name for the provider and service for display.
|
||||
*
|
||||
* @param bool $override_allowed Use override if available? Defaults to true.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_provider_service_name( $override_allowed = true ) {
|
||||
if ( ! empty( static::$provider_service_name ) ) {
|
||||
$result = static::$provider_service_name;
|
||||
} else {
|
||||
$result = static::$provider_name . ' ' . static::$service_name;
|
||||
}
|
||||
|
||||
if ( false === $override_allowed || false === static::provider_service_name_override_allowed() ) {
|
||||
return $result;
|
||||
} else {
|
||||
/** @var Amazon_S3_And_CloudFront $as3cf */
|
||||
global $as3cf;
|
||||
|
||||
$override = stripslashes( $as3cf->get_setting( static::$provider_service_name_setting_name ) );
|
||||
|
||||
if ( empty( $override ) ) {
|
||||
return $result;
|
||||
} else {
|
||||
return $override;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full name for the provider and service for use as logo's alt text.
|
||||
*
|
||||
* @param bool $override_allowed Use override if available? Defaults to true.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* Note: For accessibility reasons, returned string should differ from `get_provider_service_name`.
|
||||
*/
|
||||
public static function get_icon_desc( $override_allowed = true ) {
|
||||
return sprintf( _x( '%s logo', 'Provider icon\'s alt text', 'amazon-s3-and-cloudfront' ), static::get_provider_service_name( $override_allowed ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the displayed provider service name be overridden by the user?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function provider_service_name_override_allowed() {
|
||||
return static::$provider_service_name_override_allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the slug for the service's quick start guide doc.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_provider_service_quick_start_slug() {
|
||||
return static::$provider_service_quick_start_slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns URL for quick start guide.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_provider_service_quick_start_url() {
|
||||
global $as3cf;
|
||||
|
||||
return $as3cf::dbrains_url( '/wp-offload-media/doc/' . static::get_provider_service_quick_start_slug() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Provider's base domain.
|
||||
*
|
||||
* Does not include region prefix or bucket path etc.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_domain() {
|
||||
return apply_filters( 'as3cf_' . static::$provider_key_name . '_' . static::$service_key_name . '_domain', $this->default_domain );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the link to the provider's console.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param string $prefix
|
||||
* @param string $region
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_console_url( string $bucket = '', string $prefix = '', string $region = '' ): string {
|
||||
if ( '' !== $prefix ) {
|
||||
$prefix = $this->get_console_url_prefix_param() . apply_filters( 'as3cf_' . static::$provider_key_name . '_' . static::$service_key_name . '_console_url_prefix_value', $prefix );
|
||||
}
|
||||
|
||||
$suffix = apply_filters( 'as3cf_' . static::$provider_key_name . '_' . static::$service_key_name . '_console_url_suffix_param', $this->get_console_url_suffix_param( $bucket, $prefix, $region ) );
|
||||
|
||||
return apply_filters( 'as3cf_' . static::$provider_key_name . '_' . static::$service_key_name . '_console_url', $this->console_url ) . $bucket . $prefix . $suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the prefix param to append to the link to the provider's console.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_console_url_prefix_param(): string {
|
||||
return apply_filters( 'as3cf_' . static::$provider_key_name . '_' . static::$service_key_name . '_console_url_prefix_param', $this->console_url_prefix_param );
|
||||
}
|
||||
|
||||
/**
|
||||
* Title to be shown for provider's console link.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_console_title(): string {
|
||||
return _x( 'Provider Console', 'Default provider console link text', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Does provider support blocking direct public access to bucket?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function block_public_access_supported() {
|
||||
return static::$block_public_access_supported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Block All Public Access is enabled and Delivery Provider supports it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_block_public_access_enabled_supported_desc() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Block All Public Access is enabled and Delivery Provider does not support it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_block_public_access_enabled_unsupported_desc() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Block All Public Access is enabled during initial setup.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_block_public_access_enabled_unsupported_setup_desc() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Block All Public Access is disabled and Delivery Provider supports it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_block_public_access_disabled_supported_desc() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Block All Public Access is disabled and Delivery Provider does not support it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_block_public_access_disabled_unsupported_desc() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Does provider support object ownership controls?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function object_ownership_supported(): bool {
|
||||
return static::$object_ownership_supported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Object Ownership is enforced and Delivery Provider supports it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_object_ownership_enforced_supported_desc(): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Object Ownership is enforced and Delivery Provider does not support it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_object_ownership_enforced_unsupported_desc(): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Object Ownership is enforced during initial setup.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_object_ownership_enforced_unsupported_setup_desc(): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Object Ownership is not enforced and Delivery Provider supports it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_object_ownership_not_enforced_supported_desc(): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Description for when Object Ownership is not enforced and Delivery Provider does not support it.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_object_ownership_not_enforced_unsupported_desc(): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the provider require ACLs to be used?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function requires_acls(): bool {
|
||||
if ( static::block_public_access_supported() || static::object_ownership_supported() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the suffix param to append to the link to the provider's console.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param string $prefix
|
||||
* @param string $region
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_console_url_suffix_param( string $bucket = '', string $prefix = '', string $region = '' ): string;
|
||||
}
|
||||
1106
classes/providers/storage/aws-provider.php
Normal file
1106
classes/providers/storage/aws-provider.php
Normal file
File diff suppressed because it is too large
Load Diff
249
classes/providers/storage/digitalocean-provider.php
Normal file
249
classes/providers/storage/digitalocean-provider.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Storage;
|
||||
|
||||
use Exception;
|
||||
|
||||
class DigitalOcean_Provider extends AWS_Provider {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = 'DigitalOcean';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = 'DigitalOcean';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = 'do';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = 'Spaces';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = 'Spaces';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = 'spaces';
|
||||
|
||||
/**
|
||||
* Optional override of "Provider Name" + "Service Name" for friendly name for service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name = '';
|
||||
|
||||
/**
|
||||
* The slug for the service's quick start guide doc.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_quick_start_slug = 'digitalocean-spaces-quick-start-guide';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $access_key_id_constants = array(
|
||||
'AS3CF_DO_ACCESS_KEY_ID',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $secret_access_key_constants = array(
|
||||
'AS3CF_DO_SECRET_ACCESS_KEY',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $use_server_roles_constants = array();
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $block_public_access_supported = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $object_ownership_supported = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $regions = array(
|
||||
'nyc3' => 'New York',
|
||||
'ams3' => 'Amsterdam',
|
||||
'sgp1' => 'Singapore',
|
||||
'sfo2' => 'San Francisco 2',
|
||||
'sfo3' => 'San Francisco 3',
|
||||
'fra1' => 'Frankfurt',
|
||||
'blr1' => 'Bangalore',
|
||||
'syd1' => 'Sydney',
|
||||
'lon1' => 'London',
|
||||
'tor1' => 'Toronto',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $region_required = true;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $default_region = 'nyc3';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $default_domain = 'digitaloceanspaces.com';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url = 'https://cloud.digitalocean.com/spaces/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url_prefix_param = '?path=';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $client_args = array();
|
||||
|
||||
/**
|
||||
* Process the args before instantiating a new client for the provider's SDK.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function init_client_args( array $args ) {
|
||||
if ( empty( $args['endpoint'] ) ) {
|
||||
// DigitalOcean endpoints always require a region.
|
||||
$args['region'] = empty( $args['region'] ) ? static::get_default_region() : $args['region'];
|
||||
|
||||
$args['endpoint'] = 'https://' . $args['region'] . '.' . $this->get_domain();
|
||||
}
|
||||
|
||||
$this->client_args = $args;
|
||||
|
||||
return $this->client_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the args before instantiating a new service specific client.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function init_service_client_args( array $args ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the block public access setting for the given bucket.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param bool $block
|
||||
*/
|
||||
public function block_public_access( string $bucket, bool $block ) {
|
||||
// DigitalOcean doesn't support this, so do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the object ownership enforced setting for the given bucket.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param bool $enforce
|
||||
*/
|
||||
public function enforce_object_ownership( string $bucket, bool $enforce ) {
|
||||
// DigitalOcean doesn't support this, so do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Create bucket.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function create_bucket( array $args ) {
|
||||
// DigitalOcean requests always require a region, and it must be an AWS S3 one.
|
||||
// The region in the endpoint is all that matters to DigitalOcean Spaces.
|
||||
// @see https://docs.digitalocean.com/products/spaces/reference/s3-sdk-examples/#configure-a-client
|
||||
if ( ! empty( $this->client_args['region'] ) && 'us-east-1' === $this->client_args['region'] ) {
|
||||
parent::create_bucket( $args );
|
||||
} else {
|
||||
$client_args = $this->client_args;
|
||||
$client_args['region'] = 'us-east-1';
|
||||
unset( $args['LocationConstraint'] ); // Not needed and breaks signature.
|
||||
$this->get_client( $client_args, true )->create_bucket( $args );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns region for bucket.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_bucket_location( array $args ) {
|
||||
// For some reason DigitalOcean Spaces returns an XML LocationConstraint segment prepended to the region key.
|
||||
return strip_tags( parent::get_bucket_location( $args ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the region specific prefix for raw URL
|
||||
*
|
||||
* @param string $region
|
||||
* @param null|int $expires
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function url_prefix( $region = '', $expires = null ) {
|
||||
return $region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the suffix param to append to the link to the provider's console.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param string $prefix
|
||||
* @param string $region
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_console_url_suffix_param( string $bucket = '', string $prefix = '', string $region = '' ): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Title to be shown for provider's console link.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_console_title(): string {
|
||||
return _x( 'Control Panel', 'Provider console link text', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
}
|
||||
911
classes/providers/storage/gcp-provider.php
Normal file
911
classes/providers/storage/gcp-provider.php
Normal file
@@ -0,0 +1,911 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Storage;
|
||||
|
||||
use AS3CF_Plugin_Base;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Exception\GoogleException;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\ServiceBuilder;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Bucket;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\StorageClient;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\StorageObject;
|
||||
use DeliciousBrains\WP_Offload_Media\Providers\Storage\Streams\GCP_GCS_Stream_Wrapper;
|
||||
use Exception;
|
||||
use WP_Error;
|
||||
|
||||
class GCP_Provider extends Storage_Provider {
|
||||
|
||||
/**
|
||||
* @var ServiceBuilder
|
||||
*/
|
||||
private $cloud;
|
||||
|
||||
/**
|
||||
* @var StorageClient
|
||||
*/
|
||||
private $storage;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = 'Google Cloud Platform';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = 'GCP';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = 'gcp';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = 'Google Cloud Storage';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = 'GCS';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = 'gcs';
|
||||
|
||||
/**
|
||||
* Optional override of "Provider Name" + "Service Name" for friendly name for service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name = 'Google Cloud Storage';
|
||||
|
||||
/**
|
||||
* The slug for the service's quick start guide doc.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_quick_start_slug = 'google-cloud-storage-quick-start-guide';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $use_server_roles_constants = array(
|
||||
'AS3CF_GCP_USE_GCE_IAM_ROLE',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $key_file_path_constants = array(
|
||||
'AS3CF_GCP_KEY_FILE_PATH',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $regions = array(
|
||||
'asia' => 'Multi-Region (Asia)',
|
||||
'eu' => 'Multi-Region (EU)',
|
||||
'us' => 'Multi-Region (US)',
|
||||
'us-central1' => 'North America (Iowa)',
|
||||
'us-east1' => 'North America (South Carolina)',
|
||||
'us-east4' => 'North America (Northern Virginia)',
|
||||
'us-east5' => 'North America (Columbus)',
|
||||
'us-west1' => 'North America (Oregon)',
|
||||
'us-west2' => 'North America (Los Angeles)',
|
||||
'us-west3' => 'North America (Salt Lake City)',
|
||||
'us-west4' => 'North America (Las Vegas)',
|
||||
'us-south1' => 'North America (Dallas)',
|
||||
'northamerica-northeast1' => 'North America (Montréal)',
|
||||
'northamerica-northeast2' => 'North America (Toronto)',
|
||||
'southamerica-east1' => 'South America (São Paulo)',
|
||||
'southamerica-west1' => 'South America (Santiago)',
|
||||
'europe-central2' => 'Europe (Warsaw)',
|
||||
'europe-north1' => 'Europe (Finland)',
|
||||
'europe-west1' => 'Europe (Belgium)',
|
||||
'europe-west2' => 'Europe (London)',
|
||||
'europe-west3' => 'Europe (Frankfurt)',
|
||||
'europe-west4' => 'Europe (Netherlands)',
|
||||
'europe-west6' => 'Europe (Zürich)',
|
||||
'europe-west8' => 'Europe (Milan)',
|
||||
'europe-west9' => 'Europe (Paris)',
|
||||
'europe-west10' => 'Europe (Berlin)',
|
||||
'europe-west12' => 'Europe (Turin)',
|
||||
'europe-southwest1' => 'Europe (Madrid)',
|
||||
'asia-east1' => 'Asia (Taiwan)',
|
||||
'asia-east2' => 'Asia (Hong Kong)',
|
||||
'asia-northeast1' => 'Asia (Tokyo)',
|
||||
'asia-northeast2' => 'Asia (Osaka)',
|
||||
'asia-northeast3' => 'Asia (Seoul)',
|
||||
'asia-southeast1' => 'Asia (Singapore)',
|
||||
'asia-south1' => 'India (Mumbai)',
|
||||
'asia-south2' => 'India (Dehli)',
|
||||
'asia-southeast2' => 'Indonesia (Jakarta)',
|
||||
'me-central1' => 'Middle East (Doha)',
|
||||
'me-central2' => 'Middle East (Dammam, Saudi Arabia)',
|
||||
'me-west1' => 'Middle East (Tel Aviv)',
|
||||
'australia-southeast1' => 'Australia (Sydney)',
|
||||
'australia-southeast2' => 'Australia (Melbourne)',
|
||||
'africa-south1' => 'Africa (Johannesburg)',
|
||||
'asia1' => 'Dual-Region (Tokyo/Osaka)',
|
||||
'eur4' => 'Dual-Region (Finland/Netherlands)',
|
||||
'eur5' => 'Dual-Region (Belgium/London)',
|
||||
'eur7' => 'Dual-Region (London/Frankfurt)',
|
||||
'eur8' => 'Dual-Region (Frankfurt/Zürich)',
|
||||
'nam4' => 'Dual-Region (Iowa/South Carolina)',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $default_region = 'us';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $default_domain = 'storage.googleapis.com';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url = 'https://console.cloud.google.com/storage/browser/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url_prefix_param = '/';
|
||||
|
||||
const PUBLIC_ACL = 'publicRead';
|
||||
const PRIVATE_ACL = 'projectPrivate';
|
||||
|
||||
/**
|
||||
* GCP_Provider constructor.
|
||||
*
|
||||
* @param AS3CF_Plugin_Base $as3cf
|
||||
*/
|
||||
public function __construct( AS3CF_Plugin_Base $as3cf ) {
|
||||
parent::__construct( $as3cf );
|
||||
|
||||
// Autoloader.
|
||||
require_once $as3cf->get_plugin_sdks_dir_path() . '/Gcp/autoload.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default args array for the client.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function default_client_args() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the args before instantiating a new client for the provider's SDK.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function init_client_args( array $args ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a new client for the provider's SDK.
|
||||
*
|
||||
* @param array $args
|
||||
*/
|
||||
protected function init_client( array $args ) {
|
||||
$this->cloud = new ServiceBuilder( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the args before instantiating a new service specific client.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function init_service_client_args( array $args ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a new service specific client.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return StorageClient
|
||||
*/
|
||||
protected function init_service_client( array $args ) {
|
||||
$this->storage = $this->cloud->storage( $args );
|
||||
|
||||
return $this->storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure region "slug" fits expected format.
|
||||
*
|
||||
* @param string $region
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function sanitize_region( $region ) {
|
||||
if ( ! is_string( $region ) ) {
|
||||
// Don't translate any region errors
|
||||
return $region;
|
||||
}
|
||||
|
||||
return strtolower( $region );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create bucket.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @throws GoogleException
|
||||
*/
|
||||
public function create_bucket( array $args ) {
|
||||
$name = '';
|
||||
if ( ! empty( $args['Bucket'] ) ) {
|
||||
$name = $args['Bucket'];
|
||||
unset( $args['Bucket'] );
|
||||
}
|
||||
|
||||
if ( ! empty( $args['LocationConstraint'] ) ) {
|
||||
$args['location'] = $args['LocationConstraint'];
|
||||
unset( $args['LocationConstraint'] );
|
||||
}
|
||||
|
||||
$this->storage->createBucket( $name, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether bucket exists.
|
||||
*
|
||||
* @param string $bucket
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function does_bucket_exist( $bucket ) {
|
||||
return $this->storage->bucket( $bucket )->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns region for bucket.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_bucket_location( array $args ) {
|
||||
$info = $this->storage->bucket( $args['Bucket'] )->info();
|
||||
$region = empty( $info['location'] ) ? '' : $info['location'];
|
||||
|
||||
return $region;
|
||||
}
|
||||
|
||||
/**
|
||||
* List buckets.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
* @throws GoogleException
|
||||
*/
|
||||
public function list_buckets( array $args = array() ) {
|
||||
$result = array();
|
||||
|
||||
$buckets = $this->storage->buckets( $args );
|
||||
|
||||
if ( ! empty( $buckets ) ) {
|
||||
/** @var Bucket $bucket */
|
||||
foreach ( $buckets as $bucket ) {
|
||||
$result['Buckets'][] = array(
|
||||
'Name' => $bucket->name(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether key exists in bucket.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param string $key
|
||||
* @param array $options
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function does_object_exist( $bucket, $key, array $options = array() ) {
|
||||
return $this->storage->bucket( $bucket )->object( $key )->exists( $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get public "canned" ACL string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_public_acl() {
|
||||
return static::PUBLIC_ACL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get private "canned" ACL string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_private_acl() {
|
||||
return static::PRIVATE_ACL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download object, destination specified in args.
|
||||
*
|
||||
* @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#getobject
|
||||
* @see https://googleapis.github.io/google-cloud-php/#/docs/google-cloud/v0.90.0/storage/storageobject?method=downloadToFile
|
||||
*
|
||||
* @param array $args
|
||||
*/
|
||||
public function get_object( array $args ) {
|
||||
$this->storage->bucket( $args['Bucket'] )->object( $args['Key'] )->downloadToFile( $args['SaveAs'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object's URL.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param string $key
|
||||
* @param int $timestamp
|
||||
* @param array $args
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_object_url( $bucket, $key, $timestamp, array $args = array() ) {
|
||||
if ( empty( $timestamp ) || ! is_int( $timestamp ) || $timestamp < 0 ) {
|
||||
$info = $this->storage->bucket( $bucket )->object( $key )->info();
|
||||
$link = empty( $info['selfLink'] ) ? '' : $info['selfLink'];
|
||||
|
||||
return $link;
|
||||
} else {
|
||||
$options = array();
|
||||
|
||||
if ( ! empty( $args['BaseURL'] ) ) {
|
||||
$options['cname'] = $args['BaseURL'];
|
||||
}
|
||||
|
||||
return $this->storage->bucket( $bucket )->object( $key )->signedUrl( $timestamp, $options );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List objects.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function list_objects( array $args = array() ) {
|
||||
$result = array();
|
||||
|
||||
$objects = $this->storage->bucket( $args['Bucket'] )->objects( $args['Prefix'] );
|
||||
|
||||
if ( ! empty( $objects ) ) {
|
||||
/** @var StorageObject $object */
|
||||
foreach ( $objects as $object ) {
|
||||
$info = $object->info();
|
||||
$result['Contents'][] = array(
|
||||
'Key' => $object->name(),
|
||||
'Size' => $info['size'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the ACL for an object.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update_object_acl( array $args ) {
|
||||
if ( empty( $args['ACL'] ) ) {
|
||||
throw new Exception( __METHOD__ . ' called without "ACL" arg.' );
|
||||
}
|
||||
|
||||
$this->storage->bucket( $args['Bucket'] )->object( $args['Key'] )->update( array( 'predefinedAcl' => $args['ACL'] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the ACL for multiple objects.
|
||||
*
|
||||
* @param array $items
|
||||
*
|
||||
* @return array Failures with elements Key and Message
|
||||
*/
|
||||
public function update_object_acls( array $items ) {
|
||||
$failures = array();
|
||||
|
||||
// Unfortunately the GCP PHP SDK does not have batch operations.
|
||||
foreach ( $items as $item ) {
|
||||
try {
|
||||
$this->update_object_acl( $item );
|
||||
} catch ( Exception $e ) {
|
||||
$failures[] = array(
|
||||
'Key' => $item['Key'],
|
||||
'Message' => $e->getMessage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $failures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload file to bucket.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function upload_object( array $args ) {
|
||||
if ( ! empty( $args['SourceFile'] ) ) {
|
||||
$file = fopen( $args['SourceFile'], 'r' );
|
||||
} elseif ( ! empty( $args['Body'] ) ) {
|
||||
$file = $args['Body'];
|
||||
} else {
|
||||
throw new Exception( __METHOD__ . ' called without either "SourceFile" or "Body" arg.' );
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'name' => $args['Key'],
|
||||
);
|
||||
|
||||
if ( ! empty( $args['ACL'] ) ) {
|
||||
$options['predefinedAcl'] = $args['ACL'];
|
||||
}
|
||||
|
||||
if ( ! empty( $args['ContentType'] ) ) {
|
||||
$options['metadata']['contentType'] = $args['ContentType'];
|
||||
}
|
||||
|
||||
if ( ! empty( $args['CacheControl'] ) ) {
|
||||
$options['metadata']['cacheControl'] = $args['CacheControl'];
|
||||
}
|
||||
|
||||
// TODO: Potentially strip out known keys from $args and then put rest in $options['metadata']['metadata'].
|
||||
|
||||
$object = $this->storage->bucket( $args['Bucket'] )->upload( $file, $options ); // phpcs:ignore
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete object from bucket.
|
||||
*
|
||||
* @param array $args
|
||||
*/
|
||||
public function delete_object( array $args ) {
|
||||
$this->storage->bucket( $args['Bucket'] )->object( $args['Key'] )->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete multiple objects from bucket.
|
||||
*
|
||||
* @param array $args
|
||||
*/
|
||||
public function delete_objects( array $args ) {
|
||||
if ( isset( $args['Delete']['Objects'] ) ) {
|
||||
$keys = $args['Delete']['Objects'];
|
||||
} elseif ( isset( $args['Objects'] ) ) {
|
||||
$keys = $args['Objects'];
|
||||
}
|
||||
|
||||
if ( ! empty( $keys ) ) {
|
||||
$bucket = $this->storage->bucket( $args['Bucket'] );
|
||||
|
||||
// Unfortunately the GCP PHP SDK does not have batch operations.
|
||||
foreach ( $keys as $key ) {
|
||||
$bucket->object( $key['Key'] )->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns arrays of found keys for given bucket and prefix locations, retaining given array's integer based index.
|
||||
*
|
||||
* @param array $locations Array with attachment ID as key and Bucket and Prefix in an associative array as values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function list_keys( array $locations ) {
|
||||
$keys = array();
|
||||
|
||||
$results = array_map( function ( $location ) {
|
||||
return $this->storage->bucket( $location['Bucket'] )->objects( array(
|
||||
'prefix' => $location['Prefix'],
|
||||
'fields' => 'items/name',
|
||||
) );
|
||||
}, $locations );
|
||||
|
||||
foreach ( $results as $attachment_id => $objects ) {
|
||||
/** @var StorageObject $object */
|
||||
foreach ( $objects as $object ) {
|
||||
$keys[ $attachment_id ][] = $object->name();
|
||||
}
|
||||
}
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies objects into current bucket from another bucket hosted with provider.
|
||||
*
|
||||
* @param array $items
|
||||
*
|
||||
* @return array Failures with elements Key and Message
|
||||
*/
|
||||
public function copy_objects( array $items ) {
|
||||
$failures = array();
|
||||
|
||||
// Unfortunately the GCP PHP SDK does not have batch operations.
|
||||
foreach ( $items as $item ) {
|
||||
list( $bucket, $key ) = explode( '/', urldecode( $item['CopySource'] ), 2 );
|
||||
|
||||
$options = array(
|
||||
'name' => $item['Key'],
|
||||
);
|
||||
|
||||
if ( ! empty( $item['ACL'] ) ) {
|
||||
$options['predefinedAcl'] = $item['ACL'];
|
||||
}
|
||||
|
||||
try {
|
||||
$this->storage->bucket( $bucket )->object( $key )->copy( $item['Bucket'], $options );
|
||||
} catch ( Exception $e ) {
|
||||
$failures[] = array(
|
||||
'Key' => $item['Key'],
|
||||
'Message' => $e->getMessage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $failures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the stream wrapper protocol
|
||||
*
|
||||
* @param string $region
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_stream_wrapper_protocol( $region ) {
|
||||
$protocol = 'gs';
|
||||
|
||||
// TODO: Determine whether same protocol for all regions is ok.
|
||||
// Assumption not as each may have client instance, hence keeping this for time being.
|
||||
$protocol .= str_replace( '-', '', $region );
|
||||
|
||||
return $protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a stream wrapper for specific region.
|
||||
*
|
||||
* @param string $region
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function register_stream_wrapper( $region ) {
|
||||
$protocol = $this->get_stream_wrapper_protocol( $region );
|
||||
|
||||
// Register the region specific stream wrapper to be used by plugins
|
||||
GCP_GCS_Stream_Wrapper::register( $this->storage, $protocol );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a bucket and key can be written to.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param string $key
|
||||
* @param string $file_contents
|
||||
*
|
||||
* @return bool|string Error message on unexpected exception
|
||||
*/
|
||||
public function can_write( $bucket, $key, $file_contents ) {
|
||||
try {
|
||||
// Attempt to create the test file.
|
||||
$this->upload_object(
|
||||
static::filter_object_meta(
|
||||
array(
|
||||
'Bucket' => $bucket,
|
||||
'Key' => $key,
|
||||
'Body' => $file_contents,
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// delete it straight away if created
|
||||
$this->delete_object( array(
|
||||
'Bucket' => $bucket,
|
||||
'Key' => $key,
|
||||
) );
|
||||
|
||||
return true;
|
||||
} catch ( Exception $e ) {
|
||||
// If we encounter an error that isn't from Google, throw that error.
|
||||
if ( ! $e instanceof GoogleException ) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the region specific prefix for raw URL
|
||||
*
|
||||
* @param string $region
|
||||
* @param null|int $expires
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function url_prefix( $region = '', $expires = null ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the url domain for the files
|
||||
*
|
||||
* @param string $domain Likely prefixed with region
|
||||
* @param string $bucket
|
||||
* @param string $region
|
||||
* @param int $expires
|
||||
* @param array $args Allows you to specify custom URL settings
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function url_domain( $domain, $bucket, $region = '', $expires = null, $args = array() ) {
|
||||
if (
|
||||
apply_filters(
|
||||
'as3cf_' . static::get_provider_key_name() . '_' . static::get_service_key_name() . '_bucket_in_path',
|
||||
false !== strpos( $bucket, '.' )
|
||||
)
|
||||
) {
|
||||
$domain = $domain . '/' . $bucket;
|
||||
} else {
|
||||
// TODO: Is this mode allowed for GCS native URLs?
|
||||
$domain = $bucket . '.' . $domain;
|
||||
}
|
||||
|
||||
return $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the suffix param to append to the link to the provider's console.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param string $prefix
|
||||
* @param string $region
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_console_url_suffix_param(
|
||||
string $bucket = '',
|
||||
string $prefix = '',
|
||||
string $region = ''
|
||||
): string {
|
||||
if ( ! empty( $this->get_project_id() ) ) {
|
||||
return '?project=' . $this->get_project_id();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Project ID for the current client.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function get_project_id() {
|
||||
static $project_id = null;
|
||||
|
||||
// If not already grabbed, get project id from key file data but only if client properly instantiated.
|
||||
if ( null === $project_id && ! empty( $this->storage ) && $this->use_key_file() ) {
|
||||
$key_file_path = $this->get_key_file_path();
|
||||
|
||||
if ( ! empty( $key_file_path ) && file_exists( $key_file_path ) ) {
|
||||
$key_file_contents = json_decode( file_get_contents( $key_file_path ), true );
|
||||
|
||||
if ( ! empty( $key_file_contents['project_id'] ) ) {
|
||||
$project_id = $key_file_contents['project_id'];
|
||||
|
||||
return $project_id;
|
||||
}
|
||||
}
|
||||
|
||||
$key_file_contents = $this->get_key_file();
|
||||
|
||||
if ( is_array( $key_file_contents ) && ! empty( $key_file_contents['project_id'] ) ) {
|
||||
$project_id = $key_file_contents['project_id'];
|
||||
|
||||
return $project_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $project_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read key file contents from path and convert it to the appropriate format for this provider.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_key_file_path_contents( string $path ) {
|
||||
$notice_id = 'validate-key-file-path';
|
||||
$notice_args = array(
|
||||
'type' => 'error',
|
||||
'only_show_in_settings' => true,
|
||||
'only_show_on_tab' => 'media',
|
||||
'hide_on_parent' => true,
|
||||
'custom_id' => $notice_id,
|
||||
);
|
||||
|
||||
$content = json_decode( file_get_contents( $path ), true );
|
||||
|
||||
if ( empty( $content ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
__( 'Media cannot be offloaded due to invalid JSON in the key file.', 'amazon-s3-and-cloudfront' ),
|
||||
$notice_args
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Google specific validation of the key file contents.
|
||||
*
|
||||
* @param array $key_file_content
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validate_key_file_content( $key_file_content ): bool {
|
||||
$notice_id = 'validate-key-file-content';
|
||||
$this->as3cf->notices->remove_notice_by_id( $notice_id );
|
||||
|
||||
$notice_args = array(
|
||||
'type' => 'error',
|
||||
'only_show_in_settings' => true,
|
||||
'only_show_on_tab' => 'media',
|
||||
'hide_on_parent' => true,
|
||||
'custom_id' => $notice_id,
|
||||
);
|
||||
|
||||
if ( ! isset( $key_file_content['project_id'] ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
sprintf(
|
||||
__(
|
||||
'Media cannot be offloaded due to a missing <code>project_id</code> field which may be the result of an old or obsolete key file. <a href="%1$s" target="_blank">Create a new key file</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
static::get_provider_service_quick_start_url() . '#service-account-key-file'
|
||||
),
|
||||
$notice_args
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $key_file_content['private_key'] ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
sprintf(
|
||||
__(
|
||||
'Media cannot be offloaded due to a missing <code>private_key</code> field in the key file. <a href="%1$s" target="_blank"">Create a new key file</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
static::get_provider_service_quick_start_url() . '#service-account-key-file'
|
||||
),
|
||||
$notice_args
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $key_file_content['type'] ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
sprintf(
|
||||
__(
|
||||
'Media cannot be offloaded due to a missing <code>type</code> field in the key file. <a href="%1$s" target="_blank">Create a new key file</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
static::get_provider_service_quick_start_url() . '#service-account-key-file'
|
||||
),
|
||||
$notice_args
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $key_file_content['client_email'] ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
sprintf(
|
||||
__(
|
||||
'Media cannot be offloaded due to a missing <code>client_email</code> field in the key file. <a href="%1$s" target="_blank">Create a new key file</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
static::get_provider_service_quick_start_url() . '#service-account-key-file'
|
||||
),
|
||||
$notice_args
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the bucket error.
|
||||
*
|
||||
* @param WP_Error $object
|
||||
* @param bool $single Are we dealing with a single bucket?
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function prepare_bucket_error( WP_Error $object, bool $single = true ): string {
|
||||
if ( false !== strpos( $object->get_error_message(), "OpenSSL unable to sign" ) ) {
|
||||
return sprintf(
|
||||
__(
|
||||
'Media cannot be offloaded due to an invalid OpenSSL Private Key. <a href="%1$s" target="_blank">Update the key file</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
static::get_provider_service_quick_start_url() . '#service-account-key-file'
|
||||
);
|
||||
}
|
||||
|
||||
// This may be a JSON error message from Google.
|
||||
$message = json_decode( $object->get_error_message() );
|
||||
if ( ! is_null( $message ) ) {
|
||||
if ( isset( $message->error ) && 'invalid_grant' === $message->error ) {
|
||||
return sprintf(
|
||||
__(
|
||||
'Media cannot be offloaded using the provided service account. <a href="%1$s" target="_blank">Read more</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
static::get_provider_service_quick_start_url() . '#service-account-key-file'
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset( $message->error->code ) && 404 === $message->error->code ) {
|
||||
return sprintf(
|
||||
__(
|
||||
'Media cannot be offloaded because a bucket with the configured name does not exist. <a href="%1$s">Enter a different bucket</a>',
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
'#/storage/bucket'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to generic error parsing.
|
||||
return parent::prepare_bucket_error( $object, $single );
|
||||
}
|
||||
}
|
||||
35
classes/providers/storage/null-provider.php
Normal file
35
classes/providers/storage/null-provider.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Storage;
|
||||
|
||||
use AS3CF_Error;
|
||||
use Exception;
|
||||
|
||||
class Null_Provider {
|
||||
|
||||
/**
|
||||
* Log and fail calls to instance methods.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __call( $name, $arguments ) {
|
||||
AS3CF_Error::log( $arguments, __CLASS__ . "->$name()" );
|
||||
throw new Exception( 'Failed to instantiate the provider client. Check your error log. Function called:- ' . __CLASS__ . "->$name()" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Log and fail calls to static methods.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function __callStatic( $name, $arguments ) {
|
||||
AS3CF_Error::log( $arguments, __CLASS__ . "::$name()" );
|
||||
throw new Exception( 'Failed to instantiate the provider client. Check your error log. Function called:- ' . __CLASS__ . "->$name()" );
|
||||
}
|
||||
}
|
||||
237
classes/providers/storage/s3-compatible-provider.php
Normal file
237
classes/providers/storage/s3-compatible-provider.php
Normal file
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Storage;
|
||||
|
||||
use Exception;
|
||||
|
||||
class S3_Compatible_Provider extends AWS_Provider {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_name = 'S3-Compatible';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_short_name = 'S3 Compatible';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_key_name = 's3compatible';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_name = 'S3-Compatible Storage';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_short_name = 'S3';
|
||||
|
||||
/**
|
||||
* Used in filters and settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $service_key_name = 's3compat';
|
||||
|
||||
/**
|
||||
* Optional override of "Provider Name" + "Service Name" for friendly name for service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_name = 'S3-Compatible Storage';
|
||||
|
||||
/**
|
||||
* The slug for the service's quick start guide doc.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $provider_service_quick_start_slug = '';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $access_key_id_constants = array(
|
||||
'AS3CF_S3COMPAT_ACCESS_KEY_ID',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $secret_access_key_constants = array(
|
||||
'AS3CF_S3COMPAT_SECRET_ACCESS_KEY',
|
||||
);
|
||||
|
||||
/**
|
||||
* Server roles not supported for generic S3-compatible services.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $use_server_roles_constants = array();
|
||||
|
||||
/**
|
||||
* Block Public Access is not universally supported by S3-compatible services.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $block_public_access_supported = false;
|
||||
|
||||
/**
|
||||
* Object Ownership is not universally supported by S3-compatible services.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $object_ownership_supported = false;
|
||||
|
||||
/**
|
||||
* S3-compatible services use free-form region strings; no fixed list.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $regions = array();
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected static $region_required = false;
|
||||
|
||||
/**
|
||||
* Default region required by the AWS SDK, even for S3-compatible services.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $default_region = 'us-east-1';
|
||||
|
||||
/**
|
||||
* No fixed default domain; derived from the configured endpoint.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $default_domain = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $console_url_prefix_param = '/';
|
||||
|
||||
/**
|
||||
* Process the args before instantiating a new client for the provider's SDK.
|
||||
* Injects the custom endpoint and enables path-style access.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function init_client_args( array $args ) {
|
||||
$endpoint = $this->as3cf->get_setting( 'endpoint' );
|
||||
|
||||
if ( ! empty( $endpoint ) ) {
|
||||
$args['endpoint'] = rtrim( $endpoint, '/' );
|
||||
$args['use_path_style_endpoint'] = true;
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the host (and port if non-standard) extracted from the configured endpoint URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_domain() {
|
||||
$endpoint = $this->as3cf->get_setting( 'endpoint' );
|
||||
|
||||
if ( empty( $endpoint ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$parsed = parse_url( $endpoint );
|
||||
$host = isset( $parsed['host'] ) ? $parsed['host'] : '';
|
||||
|
||||
if ( ! empty( $parsed['port'] ) ) {
|
||||
$host .= ':' . $parsed['port'];
|
||||
}
|
||||
|
||||
return $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* No region-based prefix is needed for S3-compatible services.
|
||||
*
|
||||
* @param string $region
|
||||
* @param null|int $expires
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function url_prefix( $region = '', $expires = null ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Always use path-style URLs: endpoint-host/bucket instead of bucket.endpoint-host.
|
||||
*
|
||||
* @param string $domain
|
||||
* @param string $bucket
|
||||
* @param string $region
|
||||
* @param int $expires
|
||||
* @param array $args
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function url_domain( $domain, $bucket, $region = '', $expires = null, $args = array() ) {
|
||||
return $domain . '/' . $bucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create bucket without a LocationConstraint, which many S3-compatible
|
||||
* services do not support.
|
||||
*
|
||||
* @param array $args
|
||||
*/
|
||||
public function create_bucket( array $args ) {
|
||||
// Remove AWS-specific location constraint; S3-compatible services
|
||||
// typically don't support it and use the endpoint region instead.
|
||||
unset( $args['LocationConstraint'] );
|
||||
parent::create_bucket( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Block Public Access is not supported by most S3-compatible services.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param bool $block
|
||||
*/
|
||||
public function block_public_access( string $bucket, bool $block ) {
|
||||
// Not supported — do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Object Ownership enforcement is not supported by most S3-compatible services.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param bool $enforce
|
||||
*/
|
||||
public function enforce_object_ownership( string $bucket, bool $enforce ) {
|
||||
// Not supported — do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the console title (not applicable for generic S3-compatible services).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_console_title(): string {
|
||||
return _x( 'Console', 'Provider console link text', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
}
|
||||
1631
classes/providers/storage/storage-provider.php
Normal file
1631
classes/providers/storage/storage-provider.php
Normal file
File diff suppressed because it is too large
Load Diff
116
classes/providers/storage/streams/aws-s3-stream-wrapper.php
Normal file
116
classes/providers/storage/streams/aws-s3-stream-wrapper.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Storage\Streams;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\CacheInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\S3\S3ClientInterface;
|
||||
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\S3\StreamWrapper;
|
||||
|
||||
class AWS_S3_Stream_Wrapper extends StreamWrapper {
|
||||
|
||||
public static $wrapper;
|
||||
|
||||
/**
|
||||
* Register the 's3://' stream wrapper
|
||||
*
|
||||
* @param S3ClientInterface $client Client to use with the stream wrapper
|
||||
* @param string $protocol Protocol to register as.
|
||||
* @param CacheInterface $cache Default cache for the protocol.
|
||||
* @param bool $v2_existence Whether or not to use V2 bucket and object existence methods
|
||||
*/
|
||||
public static function register( S3ClientInterface $client, $protocol = 's3', CacheInterface $cache = null, $v2_existence = false ) {
|
||||
// Keep a shadow copy of the protocol for use with context options.
|
||||
static::$wrapper = $protocol;
|
||||
|
||||
parent::register( $client, $protocol, $cache, $v2_existence );
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides so we don't check for stat on directories
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $flags
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function url_stat( $path, $flags ) {
|
||||
$extension = pathinfo( $path, PATHINFO_EXTENSION );
|
||||
// If the path is a directory then return it as always existing.
|
||||
if ( ! $extension ) {
|
||||
return array(
|
||||
0 => 0,
|
||||
'dev' => 0,
|
||||
1 => 0,
|
||||
'ino' => 0,
|
||||
2 => 16895,
|
||||
'mode' => 16895,
|
||||
3 => 0,
|
||||
'nlink' => 0,
|
||||
4 => 0,
|
||||
'uid' => 0,
|
||||
5 => 0,
|
||||
'gid' => 0,
|
||||
6 => -1,
|
||||
'rdev' => -1,
|
||||
7 => 0,
|
||||
'size' => 0,
|
||||
8 => 0,
|
||||
'atime' => 0,
|
||||
9 => 0,
|
||||
'mtime' => 0,
|
||||
10 => 0,
|
||||
'ctime' => 0,
|
||||
11 => -1,
|
||||
'blksize' => -1,
|
||||
12 => -1,
|
||||
'blocks' => -1,
|
||||
);
|
||||
}
|
||||
|
||||
return parent::url_stat( $path, $flags );
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the S3 Put Object arguments
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_flush() {
|
||||
/** @var \Amazon_S3_And_CloudFront|\Amazon_S3_And_CloudFront_Pro $as3cf */
|
||||
global $as3cf;
|
||||
|
||||
if ( $as3cf->get_setting( 'use-bucket-acls' ) ) {
|
||||
$context = stream_context_get_default();
|
||||
|
||||
if ( null !== $this->context ) {
|
||||
$context = $this->context;
|
||||
}
|
||||
|
||||
$options = stream_context_get_options( $context );
|
||||
|
||||
// Set the ACL, usually defaults to public.
|
||||
$provider = $as3cf->get_storage_provider();
|
||||
$options[ static::$wrapper ]['ACL'] = $provider->get_default_acl();
|
||||
|
||||
$options = apply_filters( 'wpos3_stream_flush_params', $options ); // Backwards compatibility
|
||||
$options = apply_filters( 'as3cf_stream_flush_params', $options );
|
||||
|
||||
stream_context_set_option( $context, $options );
|
||||
}
|
||||
|
||||
return parent::stream_flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy function to stop PHP from throwing a wobbly.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $option
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_metadata( $path, $option, $value ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
69
classes/providers/storage/streams/gcp-gcs-stream-wrapper.php
Normal file
69
classes/providers/storage/streams/gcp-gcs-stream-wrapper.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\Providers\Storage\Streams;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\StorageClient;
|
||||
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\StreamWrapper;
|
||||
|
||||
class GCP_GCS_Stream_Wrapper extends StreamWrapper {
|
||||
|
||||
public static $wrapper;
|
||||
|
||||
/**
|
||||
* Register the 'gs://' stream wrapper
|
||||
*
|
||||
* @param StorageClient $client Client to use with the stream wrapper
|
||||
* @param string $protocol Protocol to register as.
|
||||
*/
|
||||
public static function register( StorageClient $client, $protocol = 'gs' ) {
|
||||
// Keep a shadow copy of the protocol for use with context options.
|
||||
static::$wrapper = $protocol;
|
||||
|
||||
parent::register( $client, $protocol );
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides so we don't check for stat on directories
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $flags
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function url_stat( $path, $flags ) {
|
||||
$extension = pathinfo( $path, PATHINFO_EXTENSION );
|
||||
// If the path is a directory then return it as always existing.
|
||||
if ( ! $extension ) {
|
||||
return array(
|
||||
0 => 0,
|
||||
'dev' => 0,
|
||||
1 => 0,
|
||||
'ino' => 0,
|
||||
2 => 16895,
|
||||
'mode' => 16895,
|
||||
3 => 0,
|
||||
'nlink' => 0,
|
||||
4 => 0,
|
||||
'uid' => 0,
|
||||
5 => 0,
|
||||
'gid' => 0,
|
||||
6 => -1,
|
||||
'rdev' => -1,
|
||||
7 => 0,
|
||||
'size' => 0,
|
||||
8 => 0,
|
||||
'atime' => 0,
|
||||
9 => 0,
|
||||
'mtime' => 0,
|
||||
10 => 0,
|
||||
'ctime' => 0,
|
||||
11 => -1,
|
||||
'blksize' => -1,
|
||||
12 => -1,
|
||||
'blocks' => -1,
|
||||
);
|
||||
}
|
||||
|
||||
return parent::url_stat( $path, $flags );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user