first commit

This commit is contained in:
Roman Pyrih
2026-04-21 15:48:41 +02:00
commit 7483681901
10216 changed files with 3236626 additions and 0 deletions

View File

@@ -0,0 +1,166 @@
<?php
/**
* FTP/SFTP ADDON
*
* Name: Duplicator PRO base
* Version: 1
* Author: Duplicator
* Author URI: https://duplicator.com/
*
* PHP version 5.3
*
* @category Duplicator
* @package Plugin
* @author Duplicator
* @copyright 2011-2021 Snapcreek LLC
* @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3
* @version GIT: $Id$
* @link https://duplicator.com/
*/
namespace Duplicator\Addons\AmazonS3Addon;
use Duplicator\Addons\AmazonS3Addon\Models\AmazonS3Storage;
use Duplicator\Addons\AmazonS3Addon\Models\AmazonS3CompatibleStorage;
use Duplicator\Addons\AmazonS3Addon\Models\BackblazeStorage;
use Duplicator\Addons\AmazonS3Addon\Models\CloudflareStorage;
use Duplicator\Addons\AmazonS3Addon\Models\DigitalOceanStorage;
use Duplicator\Addons\AmazonS3Addon\Models\DreamStorage;
use Duplicator\Addons\AmazonS3Addon\Models\GoogleCloudStorage;
use Duplicator\Addons\AmazonS3Addon\Models\VultrStorage;
use Duplicator\Addons\AmazonS3Addon\Models\WasabiStorage;
use Duplicator\Addons\AmazonS3Addon\Utils\Autoloader;
use Duplicator\Core\Addons\AbstractAddonCore;
use Duplicator\Models\Storages\AbstractStorageEntity;
/**
* Storage s3 and S3 compatible addon class
*/
class AmazonS3Addon extends AbstractAddonCore
{
const ADDON_PATH = __DIR__;
/**
* @return void
*/
public function init(): void
{
Autoloader::register();
add_action('duplicator_daily_actions', [self::class, 'purgeOldS3MultipartUploads']);
add_action('duplicator_register_storage_types', [$this, 'registerStorages']);
add_filter('duplicator_template_file', [self::class, 'getTemplateFile'], 10, 2);
add_filter('duplicator_usage_stats_storages_infos', [self::class, 'getStorageUsageStats'], 10, 1);
}
/**
* Register storages
*
* @return void
*/
public function registerStorages(): void
{
AmazonS3Storage::registerType();
AmazonS3CompatibleStorage::registerType();
GoogleCloudStorage::registerType();
BackblazeStorage::registerType();
DreamStorage::registerType();
DigitalOceanStorage::registerType();
VultrStorage::registerType();
CloudflareStorage::registerType();
WasabiStorage::registerType();
}
/**
* Return template file path
*
* @param string $path path to the template file
* @param string $slugTpl slug of the template
*
* @return string
*/
public static function getTemplateFile($path, $slugTpl)
{
if (strpos($slugTpl, 'amazons3addon/') === 0) {
return self::getAddonPath() . '/template/' . $slugTpl . '.php';
}
return $path;
}
/**
* Get storage usage stats
*
* @param array<string,int> $storageNums Storages num
*
* @return array<string,int>
*/
public static function getStorageUsageStats($storageNums)
{
if (($storages = AbstractStorageEntity::getAll()) === false) {
$storages = [];
}
$storageNums['storages_s3_count'] = 0;
$storageNums['storages_s3_compatible_count'] = 0;
foreach ($storages as $index => $storage) {
switch ($storage->getStype()) {
case AmazonS3Storage::getSType():
$storageNums['storages_s3_count']++;
break;
case AmazonS3CompatibleStorage::getSType():
case GoogleCloudStorage::getSType():
case BackblazeStorage::getSType():
case DreamStorage::getSType():
case DigitalOceanStorage::getSType():
case VultrStorage::getSType():
case CloudflareStorage::getSType():
case WasabiStorage::getSType():
$storageNums['storages_s3_compatible_count']++;
break;
}
}
return $storageNums;
}
/**
* Purge old S3 multipart uploads
*
* @return void
*/
public static function purgeOldS3MultipartUploads(): void
{
if (($storages = AbstractStorageEntity::getAll()) == false) {
return;
}
foreach ($storages as $storage) {
if (!$storage instanceof \Duplicator\Addons\AmazonS3Addon\Models\AmazonS3Storage) {
continue;
}
$storage->purgeMultipartUpload();
}
}
/**
*
* @return string
*/
public static function getAddonPath(): string
{
return __DIR__;
}
/**
*
* @return string
*/
public static function getAddonFile(): string
{
return __FILE__;
}
}

View File

@@ -0,0 +1,289 @@
<?php
/**
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\AmazonS3Addon\Models;
use Duplicator\Core\Views\TplMng;
use Duplicator\Libs\Snap\SnapUtil;
class AmazonS3CompatibleStorage extends AmazonS3Storage
{
/**
* Get default config
*
* @return array<string,scalar>
*/
protected static function getDefaultConfig(): array
{
$config = parent::getDefaultConfig();
return array_merge($config, ['ACL_full_control' => false]);
}
/**
* Return the storage type
*
* @return int
*/
public static function getSType(): int
{
return 8;
}
/**
* Returns the storage type name.
*
* @return string
*/
public static function getStypeName(): string
{
return __('S3 Compatible', 'duplicator-pro');
}
/**
* Returns the storage type icon URL
*
* @return string Returns the storage icon URL
*/
public static function getStypeIconURL(): string
{
return DUPLICATOR_IMG_URL . '/aws-compatible.svg';
}
/**
* Returns an html anchor tag of location or a string
*
* @return string Returns an html anchor tag with the storage location as a hyperlink or just a plain string
*/
public function getHtmlLocationLink(): string
{
if ($this->isValid()) {
return '<a href="' . esc_url($this->getLocationString()) . '" target="_blank" >' . esc_html($this->getLocationLabel()) . '</a>';
} else {
return '<span>' . esc_html($this->getLocationString()) . '</span>';
}
}
/**
* Get storage location string
*
* @return string
*/
public function getLocationString(): string
{
return '/' . $this->getBucketPath();
}
/**
* Returns the bucket path with optional storage folder
*
* @return string The bucket path
*/
protected function getBucketPath(): string
{
$folder = $this->getStorageFolder();
$suffix = ($folder !== '') ? '/' . ltrim($folder, '/') : '';
return $this->config['bucket'] . $suffix;
}
/**
* Returns the storage location label.
*
* @return string The storage location label
*/
protected function getLocationLabel(): string
{
return '/' . $this->getBucketPath();
}
/**
* Returns a list of S3 compatible providers
*
* @return string[]
*/
public static function getCompatibleProviders(): array
{
return [
'Aruba',
'Cloudian',
'Cloudn',
'Connectria',
'Constant',
'Exoscal',
'Eucalyptus',
'Nifty',
'Nimbula',
'Minio',
];
}
/**
* Get priority, used to sort storages.
* 100 is neutral value, 0 is the highest priority
*
* @return int
*/
public static function getPriority(): int
{
return 510;
}
/**
* Returns the config fields template data
*
* @return array<string, mixed>
*/
protected function getConfigFieldsData(): array
{
return $this->getDefaultConfigFieldsData();
}
/**
* Returns the default config fields template data
*
* @return array<string, mixed>
*/
protected function getDefaultConfigFieldsData(): array
{
return [
'storage' => $this,
'maxPackages' => $this->config['max_packages'],
'storageFolder' => $this->config['storage_folder'],
'accessKey' => $this->config['access_key'],
'bucket' => $this->config['bucket'],
'region' => $this->config['region'],
'endpoint' => $this->config['endpoint'],
'secretKey' => $this->config['secret_key'],
'storageClass' => $this->config['storage_class'],
'aclFullControl' => $this->config['ACL_full_control'],
'isAutofillEndpoint' => $this->isAutofillEndpoint(),
'isAutofillRegion' => $this->isAutofillRegion(),
'isAclSupported' => $this->isACLSupported(),
'aclDescription' => $this->getACLDescription(),
'documentationLinks' => static::getDocumentationLinks(),
];
}
/**
* Returns the config fields template path
*
* @return string
*/
protected function getConfigFieldsTemplatePath(): string
{
return 'amazons3addon/configs/all_s3_compatible';
}
/**
* Get documentation links
*
* @return array<int,array<string,string>>
*/
protected static function getDocumentationLinks(): array
{
return [
[
'label' => __('S3 Compatibility API', 'duplicator-pro'),
'url' => 'https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html',
],
];
}
/**
* Return true if the endpoint is generated automatically
*
* @return bool
*/
protected function isAutofillEndpoint(): bool
{
return false;
}
/**
* Return true if the region is generated automatically
*
* @return bool
*/
protected function isAutofillRegion(): bool
{
return false;
}
/**
* Return true if the ACL is supported
*
* @return bool
*/
protected function isACLSupported(): bool
{
return true;
}
/**
* Get ACL description
*
* @return string
*/
protected function getACLDescription()
{
return __(
"This option only works if the storage provider supports the 'bucket-owner-full-control' object-level canned ACL.",
'duplicator-pro'
);
}
/**
* Update data from http request, this method don't save data, just update object properties
*
* @param string $message Message
*
* @return bool True if success and all data is valid, false otherwise
*/
public function updateFromHttpRequest(&$message = ''): bool
{
if ((parent::updateFromHttpRequest($message) === false)) {
return false;
}
$this->config['endpoint'] = SnapUtil::sanitizeTextInput(SnapUtil::INPUT_REQUEST, 's3_endpoint');
$this->config['ACL_full_control'] = $this->isACLSupported() && SnapUtil::sanitizeBoolInput(SnapUtil::INPUT_REQUEST, 's3_ACL_full_control');
if (strlen($this->config['endpoint']) === 0) {
$message = sprintf(
__('The %s field is required.', 'duplicator-pro'),
self::getFieldLabel('endpoint')
);
return false;
}
return true;
}
/**
* Register storage type
*
* @return void
*/
public static function registerType(): void
{
parent::registerType();
if (self::class === static::class) {
// only add filter for current storage and not inherited
add_filter('duplicator_storage_type_class', function ($class, $type, $data) {
if ($type == AmazonS3Storage::getSType()) {
$isLegacy = (!isset($data['legacyEntity']) || $data['legacyEntity'] === true);
$provider = ($data['s3_provider'] ?? '');
if ($isLegacy && $provider == 'other') {
$class = self::class;
}
}
return $class;
}, 10, 3);
}
}
}

View File

@@ -0,0 +1,497 @@
<?php
/**
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\AmazonS3Addon\Models;
use Duplicator\Models\GlobalEntity;
use Duplicator\Utils\Logging\DupLog;
use Duplicator\Core\Views\TplMng;
use Duplicator\Libs\Snap\SnapUtil;
use Duplicator\Models\DynamicGlobalEntity;
use Duplicator\Models\Storages\AbstractStorageEntity;
use Exception;
/** @property S3StorageAdapter $adapter */
class AmazonS3Storage extends AbstractStorageEntity
{
/** @var int */
const DEFAULT_DOWNLOAD_CHUNK_SIZE_IN_KB = 10 * 1024;
/** @var int */
const DOWNLOAD_CHUNK_MIN_SIZE_IN_KB = 5 * 1024;
/** @var int */
const DOWNLOAD_CHUNK_MAX_SIZE_IN_KB = 5 * 1024 * 1024;
/** @var int */
const DEFAULT_UPLOAD_CHUNK_SIZE_IN_KB = 6000;
/** @var int */
const UPLOAD_CHUNK_MIN_SIZE_IN_KB = 5 * 1024;
/** @var int */
const UPLOAD_CHUNK_MAX_SIZE_IN_KB = 5 * 1024 * 1024;
/**
* Get default config
*
* @return array<string,scalar>
*/
protected static function getDefaultConfig(): array
{
$config = parent::getDefaultConfig();
return array_merge(
$config,
[
'access_key' => '',
'bucket' => '',
'region' => '',
'endpoint' => '',
'secret_key' => '',
'storage_class' => 'STANDARD',
'ACL_full_control' => true,
]
);
}
/**
* Return the field label
*
* @param string $field Field name
*
* @return string
*/
public static function getFieldLabel(string $field): string
{
switch ($field) {
case 'accessKey':
return __('Access Key', 'duplicator-pro');
case 'secretKey':
return __('Secret Key', 'duplicator-pro');
case 'region':
return __('Region', 'duplicator-pro');
case 'endpoint':
return __('Endpoint', 'duplicator-pro');
case 'bucket':
return __('Bucket', 'duplicator-pro');
case 'aclFullControl':
return __('Additional Settings', 'duplicator-pro');
default:
throw new Exception("Unknown field: $field");
}
}
/**
* Return the storage type
*
* @return int
*/
public static function getSType(): int
{
return 4;
}
/**
* Returns the storage type icon URL
*
* @return string Returns the storage icon URL
*/
public static function getStypeIconURL(): string
{
return DUPLICATOR_IMG_URL . '/aws.svg';
}
/**
* Returns the storage type name.
*
* @return string
*/
public static function getStypeName(): string
{
return __('Amazon S3', 'duplicator-pro');
}
/**
* Get priority, used to sort storages.
* 100 is neutral value, 0 is the highest priority
*
* @return int
*/
public static function getPriority(): int
{
return 500;
}
/**
* Get storage location string
*
* @return string
*/
public function getLocationString(): string
{
$params = [
'region' => $this->config['region'],
'bucket' => $this->config['bucket'],
'prefix' => $this->getStorageFolder(),
];
return 'https://console.aws.amazon.com/s3/home?' . http_build_query($params);
}
/**
* Returns an html anchor tag of location
*
* @return string Returns an html anchor tag with the storage location as a hyperlink.
*
* @example
* OneDrive Example return
* <a target="_blank" href="https://1drv.ms/f/sAFrQtasdrewasyghg">https://1drv.ms/f/sAFrQtasdrewasyghg</a>
*/
public function getHtmlLocationLink(): string
{
if ($this->isValid()) {
return '<a href="' . esc_url($this->getLocationString()) . '" target="_blank" >' . esc_html($this->getLocationLabel()) . '</a>';
} else {
return '<span>' . esc_html($this->getLocationLabel()) . '</span>';
}
}
/**
* Returns the storage location label.
*
* @return string The storage location label
*/
protected function getLocationLabel(): string
{
return 's3://' . $this->config['bucket'] . $this->getStorageFolder();
}
/**
* Check if storage is supported
*
* @return bool
*/
public static function isSupported(): bool
{
return SnapUtil::isCurlEnabled(true);
}
/**
* Get supported notice, displayed if storage isn't supported
*
* @return string html string or empty if storage is supported
*/
public static function getNotSupportedNotice(): string
{
if (static::isSupported()) {
return '';
}
if (!SnapUtil::isCurlEnabled()) {
$result = sprintf(
__(
"The Storage %s requires the PHP cURL extension and related functions to be enabled.",
'duplicator-pro'
),
static::getStypeName()
);
} elseif (!SnapUtil::isCurlEnabled(true)) {
$result = sprintf(
__(
"The Storage %s requires 'curl_multi_' type functions to be enabled. One or more are disabled on your server.",
'duplicator-pro'
),
static::getStypeName()
);
} else {
$result = sprintf(
__(
'The Storage %s is not supported on this server.',
'duplicator-pro'
),
static::getStypeName()
);
}
return esc_html($result);
}
/**
* Check if storage is valid
*
* @param ?string $errorMsg Reference to store error message
* @param bool $force Force the storage to be revalidated
*
* @return bool Return true if storage is valid and ready to use, false otherwise
*/
public function isValid(?string &$errorMsg = '', bool $force = false): bool
{
return $this->getAdapter()->isValid($errorMsg, $force);
}
/**
* Returns the config fields template data
*
* @return array<string, mixed>
*/
protected function getConfigFieldsData(): array
{
return $this->getDefaultConfigFieldsData();
}
/**
* Returns the default config fields template data
*
* @return array<string, mixed>
*/
protected function getDefaultConfigFieldsData(): array
{
return [
'storage' => $this,
'maxPackages' => $this->config['max_packages'],
'storageFolder' => $this->config['storage_folder'],
'accessKey' => $this->config['access_key'],
'bucket' => $this->config['bucket'],
'region' => $this->config['region'],
'endpoint' => $this->config['endpoint'],
'secretKey' => $this->config['secret_key'],
'storageClass' => $this->config['storage_class'],
'aclFullControl' => $this->config['ACL_full_control'],
'regionOptions' => self::regionOptions(),
];
}
/**
* Returns the config fields template path
*
* @return string
*/
protected function getConfigFieldsTemplatePath(): string
{
return 'amazons3addon/configs/amazon_s3';
}
/**
* Update data from http request, this method don't save data, just update object properties
*
* @param string $message Message
*
* @return bool True if success and all data is valid, false otherwise
*/
public function updateFromHttpRequest(&$message = ''): bool
{
if ((parent::updateFromHttpRequest($message) === false)) {
return false;
}
$this->config['max_packages'] = SnapUtil::sanitizeIntInput(SnapUtil::INPUT_REQUEST, 's3_max_files', 10);
$this->config['storage_folder'] = self::getSanitizedInputFolder('_s3_storage_folder');
$this->config['access_key'] = SnapUtil::sanitizeTextInput(SnapUtil::INPUT_REQUEST, 's3_access_key');
$secretKey = SnapUtil::sanitizeTextInput(SnapUtil::INPUT_REQUEST, 's3_secret_key');
if (strlen($secretKey) > 0) {
$this->config['secret_key'] = $secretKey;
}
$this->config['region'] = SnapUtil::sanitizeTextInput(SnapUtil::INPUT_REQUEST, 's3_region');
$this->config['storage_class'] = SnapUtil::sanitizeTextInput(SnapUtil::INPUT_REQUEST, 's3_storage_class');
$this->config['bucket'] = SnapUtil::sanitizeTextInput(SnapUtil::INPUT_REQUEST, 's3_bucket');
if (strlen($this->config['access_key']) === 0) {
$message = sprintf(
__('The %s field is required.', 'duplicator-pro'),
self::getFieldLabel('accessKey')
);
return false;
}
if (strlen($this->config['region']) === 0) {
$message = sprintf(
__('The %s field is required.', 'duplicator-pro'),
self::getFieldLabel('region')
);
return false;
}
if (strlen($this->config['bucket']) === 0) {
$message = sprintf(
__('The %s field is required.', 'duplicator-pro'),
self::getFieldLabel('bucket')
);
return false;
}
$message = __('Storage Updated.', 'duplicator-pro');
return true;
}
/**
* Get full s3 client
*
* @return S3StorageAdapter
*/
protected function getAdapter(): S3StorageAdapter
{
if ($this->adapter !== null) {
return $this->adapter;
}
try {
$global = GlobalEntity::getInstance();
$this->adapter = new S3StorageAdapter(
$this->config['access_key'],
$this->config['secret_key'],
$this->config['region'],
$this->config['bucket'],
$this->config['storage_folder'],
$this->config['endpoint'],
$this->config['storage_class'],
$global->ipv4_only,
!$global->ssl_disableverify,
($global->ssl_useservercerts ? '' : DUPLICATOR_CERT_PATH),
$this->config['ACL_full_control']
);
} catch (Exception $e) {
DupLog::infoTraceException($e, "Error creating S3 adapter: ");
throw new Exception("Failed to create S3 adapter: " . $e->getMessage());
}
return $this->adapter;
}
/**
* Returns value => label pairs for region drop-down options for S3 Amazon Direct storage type
*
* @return string[]
*/
protected static function regionOptions(): array
{
return [
"us-east-1" => __("US East (N. Virginia)", 'duplicator-pro'),
"us-east-2" => __("US East (Ohio)", 'duplicator-pro'),
"us-west-1" => __("US West (N. California)", 'duplicator-pro'),
"us-west-2" => __("US West (Oregon)", 'duplicator-pro'),
"af-south-1" => __("Africa (Cape Town)", 'duplicator-pro'),
"ap-east-1" => __("Asia Pacific (Hong Kong)", 'duplicator-pro'),
"ap-south-1" => __("Asia Pacific (Mumbai)", 'duplicator-pro'),
"ap-northeast-1" => __("Asia Pacific (Tokyo)", 'duplicator-pro'),
"ap-northeast-2" => __("Asia Pacific (Seoul)", 'duplicator-pro'),
"ap-northeast-3" => __("Asia Pacific (Osaka)", 'duplicator-pro'),
"ap-southeast-1" => __("Asia Pacific (Singapore)", 'duplicator-pro'),
"ap-southeast-2" => __("Asia Pacific (Sydney)", 'duplicator-pro'),
"ap-southeast-3" => __("Asia Pacific (Jakarta)", 'duplicator-pro'),
"ca-central-1" => __("Canada (Central)", 'duplicator-pro'),
"cn-north-1" => __("China (Beijing)", 'duplicator-pro'),
"cn-northwest-1" => __("China (Ningxia)", 'duplicator-pro'),
"eu-central-1" => __("EU (Frankfurt)", 'duplicator-pro'),
"eu-west-1" => __("EU (Ireland)", 'duplicator-pro'),
"eu-west-2" => __("EU (London)", 'duplicator-pro'),
"eu-west-3" => __("EU (Paris)", 'duplicator-pro'),
"eu-south-1" => __("Europe (Milan)", 'duplicator-pro'),
"eu-north-1" => __("Europe (Stockholm)", 'duplicator-pro'),
"me-south-1" => __("Middle East (Bahrain)", 'duplicator-pro'),
"sa-east-1" => __("South America (Sao Paulo)", 'duplicator-pro'),
];
}
/**
* Register storage type
*
* @return void
*/
public static function registerType(): void
{
parent::registerType();
add_action('duplicator_update_global_storage_settings', function (): void {
$dGlobal = DynamicGlobalEntity::getInstance();
foreach (static::getDefaultSettings() as $key => $default) {
$value = SnapUtil::sanitizeIntInput(SnapUtil::INPUT_REQUEST, $key, $default);
$dGlobal->setValInt($key, $value);
}
});
}
/**
* Get upload chunk size in bytes
*
* @return int bytes
*/
public function getUploadChunkSize(): int
{
$dGlobal = DynamicGlobalEntity::getInstance();
return $dGlobal->getValInt(
's3_upload_part_size_in_kb',
self::DEFAULT_UPLOAD_CHUNK_SIZE_IN_KB
) * KB_IN_BYTES;
}
/**
* Get download chunk size in bytes
*
* @return int bytes
*/
public function getDownloadChunkSize(): int
{
$dGlobal = DynamicGlobalEntity::getInstance();
return $dGlobal->getValInt(
's3_download_part_size_in_kb',
self::DEFAULT_DOWNLOAD_CHUNK_SIZE_IN_KB
) * KB_IN_BYTES;
}
/**
* Get upload chunk timeout in seconds
*
* @return int timeout in microseconds, 0 unlimited
*/
public function getUploadChunkTimeout(): int
{
$global = GlobalEntity::getInstance();
return (int) ($global->php_max_worker_time_in_sec <= 0 ? 0 : $global->php_max_worker_time_in_sec * SECONDS_IN_MICROSECONDS);
}
/**
* Get default settings
*
* @return array<string, scalar>
*/
protected static function getDefaultSettings(): array
{
return [
's3_upload_part_size_in_kb' => self::DEFAULT_UPLOAD_CHUNK_SIZE_IN_KB,
's3_download_part_size_in_kb' => self::DEFAULT_DOWNLOAD_CHUNK_SIZE_IN_KB,
];
}
/**
* @return void
*/
public static function renderGlobalOptions(): void
{
if (static::class !== self::class) {
return;
}
$dGlobal = DynamicGlobalEntity::getInstance();
TplMng::getInstance()->render(
'amazons3addon/configs/global_options',
[
'uploadPartSizeInKb' => $dGlobal->getValInt('s3_upload_part_size_in_kb', self::DEFAULT_UPLOAD_CHUNK_SIZE_IN_KB),
'downloadPartSizeInKb' => $dGlobal->getValInt('s3_download_part_size_in_kb', self::DEFAULT_DOWNLOAD_CHUNK_SIZE_IN_KB),
]
);
}
/**
* Purge old multipart uploads
*
* @return void
*/
public function purgeMultipartUpload(): void
{
$this->getAdapter()->abortMultipartUploads(2);
}
}

View File

@@ -0,0 +1,163 @@
<?php
/**
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\AmazonS3Addon\Models;
class BackblazeStorage extends AmazonS3CompatibleStorage
{
/**
* Get default config
*
* @return array<string,scalar>
*/
protected static function getDefaultConfig(): array
{
$config = parent::getDefaultConfig();
$config['ACL_full_control'] = false;
return $config;
}
/**
* Return the storage type
*
* @return int
*/
public static function getSType(): int
{
return 9;
}
/**
* Get storage location string
*
* @return string
*/
public function getLocationString(): string
{
return 'https://secure.backblaze.com/b2_buckets.htm';
}
/**
* Returns the storage location label.
*
* @return string The storage location label
*/
protected function getLocationLabel(): string
{
return __('Bucket List', 'duplicator-pro');
}
/**
* Returns the storage type name.
*
* @return string
*/
public static function getStypeName(): string
{
return __('Backblaze B2', 'duplicator-pro');
}
/**
* Get priority, used to sort storages.
* 100 is neutral value, 0 is the highest priority
*
* @return int
*/
public static function getPriority(): int
{
return 700;
}
/**
* Returns the storage type icon URL
*
* @return string Returns the storage icon URL
*/
public static function getStypeIconURL(): string
{
return DUPLICATOR_IMG_URL . '/backblaze.svg';
}
/**
* Get documentation links
*
* @return array<int,array<string,string>>
*/
protected static function getDocumentationLinks(): array
{
return [
[
'label' => __('Overview', 'duplicator-pro'),
'url' => 'https://www.backblaze.com/b2/docs/',
],
[
'label' => __('S3 Compatible API', 'duplicator-pro'),
'url' => 'https://www.backblze.com/b2/docs/s3_compatible_api.html',
],
];
}
/**
* Return the field label
*
* @param string $field Field name
*
* @return string
*/
public static function getFieldLabel(string $field): string
{
switch ($field) {
case 'accessKey':
return __('Key ID', 'duplicator-pro');
case 'secretKey':
return __('Application Key', 'duplicator-pro');
}
return parent::getFieldLabel($field);
}
/**
* Return true if ACL is supported
*
* @return bool
*/
protected function isACLSupported(): bool
{
return false;
}
/**
* Return true if the region is generated automatically
*
* @return bool
*/
public function isAutofillRegion(): bool
{
return true;
}
/**
* Register storage type
*
* @return void
*/
public static function registerType(): void
{
parent::registerType();
add_filter('duplicator_storage_type_class', function ($class, $type, $data) {
if ($type == AmazonS3Storage::getSType()) {
$isLegacy = (!isset($data['legacyEntity']) || $data['legacyEntity'] === true);
$provider = ($data['s3_provider'] ?? '');
if ($isLegacy && $provider == 'backblaze') {
$class = self::class;
}
}
return $class;
}, 10, 3);
}
}

View File

@@ -0,0 +1,91 @@
<?php
/**
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\AmazonS3Addon\Models;
class CloudflareStorage extends AmazonS3CompatibleStorage
{
/**
* Return the storage type
*
* @return int
*/
public static function getSType(): int
{
return 11;
}
/**
* Returns the storage type name.
*
* @return string
*/
public static function getStypeName(): string
{
return __('Cloudflare R2', 'duplicator-pro');
}
/**
* Get storage location string
*
* @return string
*/
public function getLocationString(): string
{
return 'https://dash.cloudflare.com/';
}
/**
* Returns the storage location label.
*
* @return string The storage location label
*/
protected function getLocationLabel(): string
{
return __('Dashboard', 'duplicator-pro');
}
/**
* Returns the storage type icon URL
*
* @return string Returns the storage icon URL
*/
public static function getStypeIconURL(): string
{
return DUPLICATOR_IMG_URL . '/cloudflare.svg';
}
/**
* Return true if the ACL is supported
*
* @return bool
*/
protected function isACLSupported(): bool
{
return false;
}
/**
* Get documentation links
*
* @return array<int,array<string,string>>
*/
protected static function getDocumentationLinks(): array
{
return [
[
'label' => __('Overview', 'duplicator-pro'),
'url' => 'https://developers.cloudflare.com/r2/',
],
[
'label' => __('S3 Compatible API', 'duplicator-pro'),
'url' => 'https://developers.cloudflare.com/r2/api/s3/api/',
],
];
}
}

View File

@@ -0,0 +1,91 @@
<?php
/**
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\AmazonS3Addon\Models;
class DigitalOceanStorage extends AmazonS3CompatibleStorage
{
/**
* Return the storage type
*
* @return int
*/
public static function getSType(): int
{
return 14;
}
/**
* Returns the storage type name.
*
* @return string
*/
public static function getStypeName(): string
{
return __('Digital Ocean Spaces', 'duplicator-pro');
}
/**
* Return true if the region is generated automatically
*
* @return bool
*/
public function isAutofillRegion(): bool
{
return true;
}
/**
* Return true if the ACL is supported
*
* @return bool
*/
protected function isACLSupported(): bool
{
return false;
}
/**
* Returns the storage type icon URL
*
* @return string Returns the storage icon URL
*/
public static function getStypeIconURL(): string
{
return DUPLICATOR_IMG_URL . '/digital-ocean.svg';
}
/**
* Get storage location string
*
* @return string
*/
public function getLocationString(): string
{
return 'https://cloud.digitalocean.com/spaces/' . $this->getBucketPath();
}
/**
* Get documentation links
*
* @return array<int,array<string,string>>
*/
protected static function getDocumentationLinks(): array
{
return [
[
'label' => __('Spaces Object Storage', 'duplicator-pro'),
'url' => 'https://docs.digitalocean.com/products/spaces/',
],
[
'label' => __('Spaces API', 'duplicator-pro'),
'url' => 'https://docs.digitalocean.com/reference/api/spaces-api/',
],
];
}
}

View File

@@ -0,0 +1,101 @@
<?php
/**
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\AmazonS3Addon\Models;
class DreamStorage extends AmazonS3CompatibleStorage
{
/**
* Return the storage type
*
* @return int
*/
public static function getSType(): int
{
return 13;
}
/**
* Returns the storage type name.
*
* @return string
*/
public static function getStypeName(): string
{
return __('Dream Objects', 'duplicator-pro');
}
/**
* Returns the storage type icon URL
*
* @return string Returns the storage icon URL
*/
public static function getStypeIconURL(): string
{
return DUPLICATOR_IMG_URL . '/dreamhost.svg';
}
/**
* Return true if the region is generated automatically
*
* @return bool
*/
public function isAutofillRegion(): bool
{
return true;
}
/**
* Return true if the ACL is supported
*
* @return bool
*/
protected function isACLSupported(): bool
{
return false;
}
/**
* Get storage location string
*
* @return string
*/
public function getLocationString(): string
{
return 'https://panel.dreamhost.com/index.cgi?tree=cloud.objects';
}
/**
* Returns the storage location label.
*
* @return string The storage location label
*/
protected function getLocationLabel(): string
{
return __('Bucket List', 'duplicator-pro');
}
/**
* Get documentation links
*
* @return array<int,array<string,string>>
*/
protected static function getDocumentationLinks(): array
{
return [
[
'label' => __('Overview', 'duplicator-pro'),
'url' => 'https://help.dreamhost.com/hc/en-us/articles/214823108-DreamObjects-overview',
],
[
'label' => __('S3 Compatible API', 'duplicator-pro'),
'url' => 'https://help.dreamhost.com/hc/en-us/articles/217590537-How-To-Use-DreamObjects-S3-compatible-API',
],
];
}
}

View File

@@ -0,0 +1,80 @@
<?php
/**
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\AmazonS3Addon\Models;
class GoogleCloudStorage extends AmazonS3CompatibleStorage
{
/**
* Return the storage type
*
* @return int
*/
public static function getSType(): int
{
return 16;
}
/**
* Returns the storage type name.
*
* @return string
*/
public static function getStypeName(): string
{
return __('Google Cloud Storage', 'duplicator-pro');
}
/**
* Get storage location string
*
* @return string
*/
public function getLocationString(): string
{
return 'https://console.cloud.google.com/storage/browser/' . $this->getBucketPath();
}
/**
* Returns the storage type icon URL
*
* @return string Returns the storage icon URL
*/
public static function getStypeIconURL(): string
{
return DUPLICATOR_IMG_URL . '/google-cloud.svg';
}
/**
* Get ACL description
*
* @return string
*/
protected function getACLDescription(): string
{
return __(
"Make sure to change the 'Access Control' to 'Fine Grained' for this setting to work.",
'duplicator-pro'
);
}
/**
* Get documentation links
*
* @return array<int,array<string,string>>
*/
protected static function getDocumentationLinks(): array
{
return [
[
'label' => __('Interoperability with S3 API', 'duplicator-pro'),
'url' => 'https://cloud.google.com/storage/docs/interoperability',
],
];
}
}

View File

@@ -0,0 +1,87 @@
<?php
/**
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\AmazonS3Addon\Models;
class VultrStorage extends AmazonS3CompatibleStorage
{
/**
* Return the storage type
*
* @return int
*/
public static function getSType(): int
{
return 12;
}
/**
* Returns the storage type name.
*
* @return string
*/
public static function getStypeName(): string
{
return __('Vultr', 'duplicator-pro');
}
/**
* Returns the storage type icon URL
*
* @return string Returns the storage icon URL
*/
public static function getStypeIconURL(): string
{
return DUPLICATOR_IMG_URL . '/vultr.svg';
}
/**
* Return true if the region is generated automatically
*
* @return bool
*/
public function isAutofillRegion(): bool
{
return true;
}
/**
* Get storage location string
*
* @return string
*/
public function getLocationString(): string
{
return 'https://my.vultr.com/objectstorage/';
}
/**
* Returns the storage location label.
*
* @return string The storage location label
*/
protected function getLocationLabel(): string
{
return __('Bucket List', 'duplicator-pro');
}
/**
* Get documentation links
*
* @return array<int,array<string,string>>
*/
protected static function getDocumentationLinks(): array
{
return [
[
'label' => __('Vultr Object Storage', 'duplicator-pro'),
'url' => 'https://www.vultr.com/docs/vultr-object-storage/',
],
];
}
}

View File

@@ -0,0 +1,91 @@
<?php
/**
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\AmazonS3Addon\Models;
class WasabiStorage extends AmazonS3CompatibleStorage
{
/**
* Return the storage type
*
* @return int
*/
public static function getSType(): int
{
return 10;
}
/**
* Returns the storage type name.
*
* @return string
*/
public static function getStypeName(): string
{
return __('Wasabi', 'duplicator-pro');
}
/**
* Returns the storage type icon URL
*
* @return string Returns the storage icon URL
*/
public static function getStypeIconURL(): string
{
return DUPLICATOR_IMG_URL . '/wasabi.svg';
}
/**
* Return true if the endpoint is generated automatically
*
* @return bool
*/
public function isAutofillEndpoint(): bool
{
return true;
}
/**
* Get storage location string
*
* @return string
*/
public function getLocationURL(): string
{
return 'https://console.wasabisys.com/file_manager/';
}
/**
* Returns the storage location label.
*
* @return string The storage location label
*/
protected function getLocationLabel(): string
{
return __('Bucket List', 'duplicator-pro');
}
/**
* Get documentation links
*
* @return array<int,array<string,string>>
*/
protected static function getDocumentationLinks(): array
{
return [
[
'label' => __('Wasabi Academy', 'duplicator-pro'),
'url' => 'https://docs.wasabi.com/',
],
[
'label' => __('S3 Compatible API', 'duplicator-pro'),
'url' => 'https://docs.wasabi.com/docs/wasabi-api',
],
];
}
}

View File

@@ -0,0 +1,85 @@
<?php
/**
* Auloader calsses
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\AmazonS3Addon\Utils;
use Duplicator\Addons\AmazonS3Addon\AmazonS3Addon;
use Duplicator\Utils\AbstractAutoloader;
/**
* Autoloader calss, dont user Duplicator library here
*/
final class Autoloader extends AbstractAutoloader
{
const VENDOR_PATH = AmazonS3Addon::ADDON_PATH . '/vendor-prefixed/';
/**
* Register autoloader function
*
* @return void
*/
public static function register(): void
{
spl_autoload_register([self::class, 'load']);
self::loadFiles();
}
/**
* Load class
*
* @param string $className class name
*
* @return void
*/
public static function load($className): void
{
foreach (self::getNamespacesVendorMapping() as $namespace => $mappedPath) {
if (strpos($className, (string) $namespace) !== 0) {
continue;
}
$filepath = self::getFilenameFromClass($className, $namespace, $mappedPath);
if (file_exists($filepath)) {
include $filepath;
return;
}
}
}
/**
* Load necessary files
*
* @return void
*/
private static function loadFiles(): void
{
$files = [
'/mtdowling/jmespath.php/src/JmesPath.php',
'/aws/aws-sdk-php/src/functions.php',
];
foreach ($files as $file) {
require_once self::VENDOR_PATH . $file;
}
}
/**
* Return namespace mapping
*
* @return string[]
*/
protected static function getNamespacesVendorMapping(): array
{
return [
self::ROOT_VENDOR . 'JmesPath' => AmazonS3Addon::getAddonPath() . '/vendor-prefixed/mtdowling/jmespath.php/src',
self::ROOT_VENDOR . 'Aws' => AmazonS3Addon::getAddonPath() . '/vendor-prefixed/aws/aws-sdk-php/src',
];
}
}

View File

@@ -0,0 +1,318 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Addons\AmazonS3Addon\Models\AmazonS3CompatibleStorage;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var AmazonS3CompatibleStorage $storage
*/
$storage = $tplData["storage"];
/** @var int */
$maxPackages = $tplData["maxPackages"];
/** @var string */
$storageFolder = $tplData["storageFolder"];
/** @var string */
$accessKey = $tplData["accessKey"];
/** @var string */
$bucket = $tplData["bucket"];
/** @var string */
$region = $tplData["region"];
/** @var string */
$secretKey = $tplData["secretKey"];
/** @var string */
$storageClass = $tplData["storageClass"];
/** @var string */
$endpoint = $tplData["endpoint"];
/** @var string */
$aclFullControl = $tplData["aclFullControl"];
/** @var bool */
$isAutofillEndpoint = $tplData["isAutofillEndpoint"];
/** @var bool */
$isAutofillRegion = $tplData["isAutofillRegion"];
/** @var bool */
$isAclSupported = $tplData["isAclSupported"];
/** @var string */
$aclDescription = $tplData["aclDescription"];
/** @var array<int,array<string,string>> */
$documentationLinks = $tplData["documentationLinks"];
$tplMng->render('admin_pages/storages/parts/provider_head');
?>
<tr>
<td colspan="2" style="padding-left:0">
<i><?php printf(
esc_html_x(
'S3 Setup Guide: %1$sStep-by-Step%2$s and %3$sUser Bucket Policy%4$s.',
'1%$s and %3$s are opening and %2$s and %4$s are closing <a> tags',
'duplicator-pro'
),
'<a target="_blank" href="' . esc_url(DUPLICATOR_DUPLICATOR_DOCS_URL . 'amazon-s3-step-by-step') . '">',
'</a>',
'<a href="' . esc_url(DUPLICATOR_DUPLICATOR_DOCS_URL . 'amazon-s3-policy-setup') . '" target="_blank">',
'</a>'
); ?>
</i>
<i>
<?php
if (count($documentationLinks) > 0) {
printf(
esc_html_x(
'Documentation for %s: ',
'%s is the provider name',
'duplicator-pro'
),
esc_html($storage->getStypeName())
);
foreach ($documentationLinks as $link) {
?>
<a target="_blank" href="<?php echo esc_url($link['url']) ?>"><?php echo esc_html($link['label']) ?></a>&nbsp;
<?php
}
}
?>
</i>
</td>
</tr>
<tr>
<th scope="row"><label for=""><?php esc_html_e("Authorization", 'duplicator-pro'); ?></label></th>
<td class="dup-s3-auth-account">
<h3>
<?php
if ($storage->getId() < 0) {
echo wp_kses(
$storage->getStypeIcon(),
[
'i' => [
'class' => [],
],
'img' => [
'src' => [],
'class' => [],
'alt' => [],
],
]
);
}
echo esc_html($storage->getStypeName()) . ' ' . esc_html__('Account', 'duplicator-pro');
?>
</h3>
<?php if ($storage->getSType() === AmazonS3CompatibleStorage::getSType()) {
$tplMng->render('amazons3addon/parts/s3_compatible_msg');
} ?>
<table class="dup-form-sub-area margin-top-1">
<tr>
<th scope="row">
<label for="s3_access_key_<?php echo (int) $storage->getSType(); ?>">
<?php echo esc_html($storage->getFieldLabel('accessKey')); ?>:
</label>
</th>
<td>
<input
id="s3_access_key_<?php echo (int) $storage->getSType(); ?>"
name="s3_access_key"
class="margin-0"
data-parsley-errors-container="#s3_access_key_<?php echo (int) $storage->getSType(); ?>_error_container"
type="text"
autocomplete="off"
value="<?php echo esc_attr($accessKey); ?>"
data-parsley-required="true"
>
<div id="s3_access_key_<?php echo (int) $storage->getSType(); ?>_error_container" class="duplicator-error-container"></div>
</td>
</tr>
<tr>
<th scope="row">
<label for="s3_secret_key_<?php echo (int) $storage->getSType(); ?>">
<?php echo esc_html($storage->getFieldLabel('secretKey')); ?>:
</label>
</th>
<td>
<input
id="s3_secret_key_<?php echo (int) $storage->getSType(); ?>"
name="s3_secret_key"
class="margin-0"
type="password"
placeholder="<?php echo esc_attr(str_repeat("*", strlen($secretKey))); ?>"
data-parsley-errors-container="#s3_secret_key_<?php echo (int) $storage->getSType(); ?>_error_container"
data-parsley-required="true"
autocomplete="off"
value=""
>
<div id="s3_secret_key_<?php echo (int) $storage->getSType(); ?>_error_container" class="duplicator-error-container"></div>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<th scope="row"></th>
<td>
<table class="dup-form-sub-area dup-s3-auth-provider">
<tr>
<th>
<label for="s3_endpoint_<?php echo (int) $storage->getSType(); ?>">
<?php echo esc_html($storage->getFieldLabel('endpoint')); ?>:
</label>
</th>
<td>
<input
type="text"
id="s3_endpoint_<?php echo (int) $storage->getSType(); ?>"
class="margin-0"
name="s3_endpoint"
value="<?php echo esc_attr($endpoint); ?>"
data-parsley-required="true"
>
<?php if ($isAutofillEndpoint) : ?>
<p class="description">
<i><?php esc_html_e('The endpoint URL will be autofilled based on the region.', 'duplicator-pro'); ?></i>
</p>
<?php endif; ?>
</td>
</tr>
<tr>
<th>
<label for="s3_region_<?php echo (int) $storage->getSType(); ?>">
<?php echo esc_html($storage->getFieldLabel('region')); ?>:
</label>
</th>
<td>
<input
type="text"
id="s3_region_<?php echo (int) $storage->getSType(); ?>"
name="s3_region"
class="margin-0"
value="<?php echo esc_attr($region); ?>"
data-parsley-required="true"
data-parsley-pattern="[0-9a-zA-Z-_]+"
>
<?php if ($isAutofillRegion) : ?>
<p class="description">
<i><?php esc_html_e('The region will be autodetected from the endpoint URL.', 'duplicator-pro'); ?></i>
</p>
<?php endif; ?>
</td>
</tr>
<tr class="invisible_out_of_screen">
<th>
<label for="s3_storage_class_<?php echo (int) $storage->getSType(); ?>">
<?php esc_html_e("Storage Class", 'duplicator-pro'); ?>:
</label>
</th>
<td>
<select id="s3_storage_class_<?php echo (int) $storage->getSType(); ?>" name="s3_storage_class">
<option <?php selected(true); ?> value="STANDARD"><?php esc_html_e("Standard", 'duplicator-pro'); ?></option>
</select>
</td>
</tr>
<tr>
<th scope="row">
<label for="s3_bucket_<?php echo (int) $storage->getSType(); ?>">
<?php echo esc_html($storage->getFieldLabel('bucket')); ?>
</label>
</th>
<td>
<input
id="s3_bucket_<?php echo (int) $storage->getSType(); ?>"
name="s3_bucket"
class="margin-0"
type="text"
value="<?php echo esc_attr($bucket); ?>"
data-parsley-required="true"
>
<p class="description">
<i><?php esc_html_e("S3 Bucket where you want to save the backups.", 'duplicator-pro'); ?></i>
</p>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<th><label for="_s3_storage_folder_<?php echo (int) $storage->getSType(); ?>"><?php esc_html_e("Storage Folder", 'duplicator-pro'); ?>:</label></th>
<td>
<div class="horizontal-input-row">
<input
id="_s3_storage_folder_<?php echo (int) $storage->getSType(); ?>"
name="_s3_storage_folder"
type="text"
value="<?php echo esc_attr($storageFolder); ?>"
>
</div>
<p class="description">
<i>
<?php
esc_html_e(
"Folder where backups will be stored. This should be unique for each web-site using Duplicator.",
'duplicator-pro'
);
?>
</i>
</p>
</td>
</tr>
<tr>
<th scope="row"><label for="s3_max_files_<?php echo (int) $storage->getSType(); ?>"><?php esc_html_e("Max Backups", 'duplicator-pro'); ?></label></th>
<td>
<div class="horizontal-input-row">
<input
id="s3_max_files_<?php echo (int) $storage->getSType(); ?>"
class="s3_max_files"
name="s3_max_files"
type="number"
value="<?php echo (int) $maxPackages; ?>"
min="0"
maxlength="4"
data-parsley-errors-container="#s3_max_files_<?php echo (int) $storage->getSType(); ?>_error_container"
data-parsley-required="true"
data-parsley-type="number"
data-parsley-min="0"
>
<label for="s3_max_files_<?php echo (int) $storage->getSType(); ?>">
<?php esc_html_e("Number of Backups to keep in folder.", 'duplicator-pro'); ?>
</label>
</div>
<?php $tplMng->render('admin_pages/storages/parts/max_backups_description'); ?>
<div id="s3_max_files_<?php echo (int) $storage->getSType(); ?>_error_container" class="duplicator-error-container"></div>
</td>
</tr>
<?php if ($isAclSupported) : ?>
<tr class="s3-acl-row" valign="top">
<th scope="row"><label><?php echo esc_html($storage->getFieldLabel('aclFullControl')); ?></label></th>
<td>
<div class="horizontal-input-row">
<input
type="checkbox"
name="s3_ACL_full_control"
id="s3_ACL_full_control_<?php echo (int) $storage->getSType(); ?>"
value="1"
<?php checked($aclFullControl, true); ?>
>
<label for="s3_ACL_full_control_<?php echo (int) $storage->getSType(); ?>">
<?php esc_html_e("Give bucket owner full control (ACL) to all files uploaded by Duplicator Pro.", 'duplicator-pro'); ?>
</label>
</div>
<p class="description">
<i>
<?php echo esc_html($aclDescription); ?>
</i>
</p>
</td>
</tr>
<?php endif; ?>
<?php $tplMng->render('admin_pages/storages/parts/provider_foot');

View File

@@ -0,0 +1,215 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Addons\AmazonS3Addon\Models\AmazonS3Storage;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var AmazonS3Storage $storage
*/
$storage = $tplData["storage"];
/** @var int */
$maxPackages = $tplData["maxPackages"];
/** @var string */
$storageFolder = $tplData["storageFolder"];
/** @var string */
$accessKey = $tplData["accessKey"];
/** @var string */
$bucket = $tplData["bucket"];
/** @var string */
$region = $tplData["region"];
/** @var string */
$secretKey = $tplData["secretKey"];
/** @var string */
$storageClass = $tplData["storageClass"];
/** @var string */
$endpoint = $tplData["endpoint"];
/** @var string */
$aclFullControl = $tplData["aclFullControl"];
/** @var array<string,string> */
$regionOptions = $tplData["regionOptions"];
$tplMng->render('admin_pages/storages/parts/provider_head');
?>
<tr>
<td colspan="2" style="padding-left:0">
<i>
<?php
printf(
esc_html_x(
'Amazon S3 Setup Guide: %1$sStep-by-Step%2$s and %3$sUser Bucket Policy%4$s.',
'1,3 represents <a> tag, 2,4 represents </a> tag',
'duplicator-pro'
),
'<a target="_blank" href="' . esc_url(DUPLICATOR_DUPLICATOR_DOCS_URL . 'amazon-s3-step-by-step') . '">',
'</a>',
'<a href="' . esc_url(DUPLICATOR_DUPLICATOR_DOCS_URL . 'amazon-s3-policy-setup') . '" target="_blank">',
'</a>'
);
?>
</i>
</td>
</tr>
<tr>
<th scope="row"><label for=""><?php esc_html_e("Authorization", 'duplicator-pro'); ?></label></th>
<td class="dup-s3-auth-account">
<h3>
<?php esc_html_e('Amazon Account', 'duplicator-pro'); ?><br/>
</h3>
<table class="dup-form-sub-area">
<tr>
<th scope="row"><label for="s3_access_key_amazon"><?php esc_html_e("Access Key", 'duplicator-pro'); ?>:</label></th>
<td>
<input
id="s3_access_key_amazon"
class="margin-0"
name="s3_access_key"
data-parsley-errors-container="#s3_access_key_amazon_error_container"
data-parsley-required="true"
type="text"
autocomplete="off"
value="<?php echo esc_attr($accessKey); ?>"
>
<div id="s3_access_key_amazon_error_container" class="duplicator-error-container"></div>
</td>
</tr>
<tr>
<th scope="row">
<label for="s3_secret_key_amazon"><?php esc_html_e("Secret Key", 'duplicator-pro'); ?>:</label>
</th>
<td>
<input
id="s3_secret_key_amazon"
name="s3_secret_key"
class="margin-0"
type="password"
placeholder="<?php echo esc_attr(str_repeat("*", strlen($secretKey))); ?>"
data-parsley-errors-container="#s3_secret_key_amazon_error_container"
autocomplete="off"
value=""
>
<div id="s3_secret_key_amazon_error_container" class="duplicator-error-container"></div>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<th scope="row"></th>
<td>
<table class="dup-form-sub-area dup-s3-auth-provider">
<tr>
<th><label for="s3_region_amazon"><?php esc_html_e("Region", 'duplicator-pro'); ?>:</label></th>
<td>
<select id="s3_region_amazon" name="s3_region" class="margin-0 width-large">
<?php
foreach ($regionOptions as $value => $label) {
?>
<option
<?php selected($region, $value); ?>
value="<?php echo esc_attr($value); ?>"
>
<?php echo esc_html($label . " - '" . $value . "'"); ?>
</option>
<?php
}
?>
</select>
</td>
</tr>
<tr>
<th><label for="s3_storage_class_amazon"><?php esc_html_e("Storage Class", 'duplicator-pro'); ?>:</label></th>
<td>
<select id="s3_storage_class_amazon" name="s3_storage_class" class="margin-0 width-large">
<option <?php selected($storageClass == 'REDUCED_REDUNDANCY'); ?> value="REDUCED_REDUNDANCY">
<?php esc_html_e("Reduced Redundancy", 'duplicator-pro'); ?>
</option>
<option <?php selected($storageClass == 'STANDARD'); ?> value="STANDARD">
<?php esc_html_e("Standard", 'duplicator-pro'); ?>
</option>
<option <?php selected($storageClass == 'STANDARD_IA'); ?> value="STANDARD_IA">
<?php esc_html_e("Standard IA", 'duplicator-pro'); ?>
</option>
</select>
</td>
</tr>
<tr>
<th><label for="_s3_storage_folder_amazon"><?php esc_html_e("Storage Folder", 'duplicator-pro'); ?>:</label></th>
<td>
<input
id="_s3_storage_folder_amazon"
class="margin-0"
name="_s3_storage_folder"
type="text"
value="<?php echo esc_attr($storageFolder); ?>"
>
<p>
<i>
<?php esc_html_e(
"Folder where backups will be stored. This should be unique for each web-site using Duplicator.",
'duplicator-pro'
); ?>
</i>
</p>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<th scope="row"><label for="s3_bucket_amazon"><?php esc_html_e("Bucket", 'duplicator-pro'); ?></label></th>
<td>
<div class="horizontal-input-row">
<input
id="s3_bucket_amazon"
name="s3_bucket"
type="text"
value="<?php echo esc_attr($bucket); ?>"
data-parsley-errors-container="#s3_bucket_amazon_error_container"
data-parsley-required="true"
>
</div>
<p><i><?php esc_html_e("S3 Bucket where you want to save the backups.", 'duplicator-pro'); ?></i></p>
<div id="s3_bucket_amazon_error_container" class="duplicator-error-container"></div>
</td>
</tr>
<tr>
<th scope="row"><label for="s3_max_files_amazon"><?php esc_html_e("Max Backups", 'duplicator-pro'); ?></label></th>
<td>
<div class="horizontal-input-row">
<input
id="s3_max_files_amazon"
class="s3_max_files margin-0"
name="s3_max_files"
type="number"
value="<?php echo (int) $maxPackages; ?>"
min="0"
maxlength="4"
data-parsley-errors-container="#s3_max_files_amazon_error_container"
data-parsley-required="true"
data-parsley-type="number"
data-parsley-min="0"
>
<label for="s3_max_files_amazon">
<?php esc_html_e("Number of Backups to keep in folder.", 'duplicator-pro'); ?><br/>
</label>
</div>
<?php $tplMng->render('admin_pages/storages/parts/max_backups_description'); ?>
<div id="s3_max_files_amazon_error_container" class="duplicator-error-container"></div>
</td>
</tr>
<?php $tplMng->render('admin_pages/storages/parts/provider_foot'); ?>

View File

@@ -0,0 +1,73 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Addons\AmazonS3Addon\Models\AmazonS3Storage;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
*/
?>
<div class="dup-accordion-wrapper display-separators close" >
<div class="accordion-header" >
<h3 class="title"><?php echo esc_html(AmazonS3Storage::getStypeName()); ?></h3>
</div>
<div class="accordion-content">
<label class="lbl-larger" >
<?php esc_html_e("Upload Chunk Size", 'duplicator-pro'); ?>
</label>
<div class="margin-bottom-1" >
<input
class="text-right inline-display width-small margin-bottom-0"
name="s3_upload_part_size_in_kb"
id="s3_upload_part_size_in_kb"
type="number"
min="<?php echo (int) AmazonS3Storage::UPLOAD_CHUNK_MIN_SIZE_IN_KB; ?>"
max="<?php echo (int) AmazonS3Storage::UPLOAD_CHUNK_MAX_SIZE_IN_KB; ?>"
data-parsley-required
data-parsley-type="number"
data-parsley-errors-container="#s3_upload_chunksize_in_kb_error_container"
value="<?php echo (int) $tplData['uploadPartSizeInKb']; ?>"
>&nbsp;<b>KB</b>
<div id="s3_upload_chunksize_in_kb_error_container" class="duplicator-error-container"></div>
<p class="description">
<?php esc_html_e('How much should be uploaded to Amazon S3 per attempt. Higher=faster but less reliable.', 'duplicator-pro'); ?>
<?php echo esc_html(sprintf(__('Min size %skb.', 'duplicator-pro'), AmazonS3Storage::UPLOAD_CHUNK_MIN_SIZE_IN_KB)); ?>
</p>
</div>
<label class="lbl-larger" >
<?php esc_html_e("Download Chunk Size", 'duplicator-pro'); ?>
</label>
<div class="margin-bottom-1" >
<input
class="text-right inline-display width-small margin-bottom-0"
name="s3_download_part_size_in_kb"
id="s3_download_part_size_in_kb"
type="number"
min="<?php echo (int) AmazonS3Storage::DOWNLOAD_CHUNK_MIN_SIZE_IN_KB; ?>"
max="<?php echo (int) AmazonS3Storage::DOWNLOAD_CHUNK_MAX_SIZE_IN_KB; ?>"
data-parsley-required
data-parsley-type="number"
data-parsley-errors-container="#s3_download_chunksize_in_kb_error_container"
value="<?php echo (int) $tplData['downloadPartSizeInKb']; ?>"
>&nbsp;<b>KB</b>
<div id="s3_download_chunksize_in_kb_error_container" class="duplicator-error-container"></div>
<p class="description">
<?php esc_html_e('How much should be downloaded from Amazon S3 per attempt. Higher=faster but less reliable.', 'duplicator-pro'); ?>
<?php echo esc_html(sprintf(__('Min size %skb.', 'duplicator-pro'), AmazonS3Storage::DOWNLOAD_CHUNK_MIN_SIZE_IN_KB)); ?>
</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,43 @@
<?php
/**
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Models\Storages\AbstractStorageEntity;
use Duplicator\Addons\AmazonS3Addon\Models\AmazonS3CompatibleStorage;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var AbstractStorageEntity $storage
*/
$storage = $tplData["storage"];
?>
<p>
<?php
esc_html_e(
'The Amazon S3 compatible storage option allows you to connect to any object storage that is compatible with the S3 API.',
'duplicator-pro'
);
?>
</p>
<p>
<?php
printf(
esc_attr_x(
'Examples of compatible providers are %s.',
'%s is a comma seperated list of providers',
'duplicator-pro'
),
'<b>' . esc_html(implode(', ', AmazonS3CompatibleStorage::getCompatibleProviders())) . '</b>'
);
?>
</p>