?AlkantarClanX12
| Current Path : /home/rankinh/mariage-reunion-refonte/wp-content/plugins/backwpup/inc/ |
| Current File : /home/rankinh/mariage-reunion-refonte/wp-content/plugins/backwpup/inc/class-destination-rsc.php |
<?php
declare(strict_types=1);
use BackWPup\Utils\BackWPupHelpers;
use WPMedia\BackWPup\StorageProviders\Rackspace\RackspaceProvider as Rackspace;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class BackWPup_Destination_RSC extends BackWPup_Destinations {
/**
* Service name
*
* @var string
*/
private const SERVICE_NAME = 'RSC';
/**
* Rackspace US
*
* @var string
*/
private string $rackspace_us = 'https://identity.api.rackspacecloud.com/v2.0/';
/**
* Rackspace UK
*
* @var string
*/
private string $rackspace_uk = 'https://lon.identity.api.rackspacecloud.com/v2.0/';
/**
* Default options
*
* @return array
*/
public function option_defaults(): array {
return [
'rscusername' => '',
'rscapikey' => '',
'rsccontainer' => '',
'rscregion' => 'DFW',
'rscdir' => trailingslashit( sanitize_file_name( get_bloginfo( 'name' ) ) ),
'rscmaxbackups' => 15,
'rscsyncnodelete' => true,
];
}
/**
* Get Auth url by region code.
*
* @param string $region Region code.
*/
public function get_auth_url_by_region( string $region ): string {
$region = strtoupper( $region );
if ( 'LON' === $region ) {
return $this->rackspace_uk;
}
return $this->rackspace_us;
}
/**
* {@inheritdoc}
*
* @param int|array $id Job ID.
* @return void
* @throws Exception When the Rackspace Cloud API throws an exception.
*
* @phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
*/
public function edit_form_post_save( $id ): void {
$_POST['rscdir'] = trailingslashit( str_replace( '//', '/', str_replace( '\\', '/', trim( sanitize_text_field( $_POST['rscdir'] ) ) ) ) );
if ( substr( $_POST['rscdir'], 0, 1 ) === '/' ) {
$_POST['rscdir'] = substr( $_POST['rscdir'], 1 );
}
if ( '/' === $_POST['rscdir'] ) {
$_POST['rscdir'] = '';
}
$newrsccontainer = '';
if ( ! empty( $_POST['rscusername'] ) && ! empty( $_POST['rscapikey'] ) && ! empty( $_POST['newrsccontainer'] ) ) {
try {
$storage_provider = $this->get_rackspace_client(
[
'region' => $_POST['rscregion'],
'username' => $_POST['rscusername'],
'api_key' => $_POST['rscapikey'],
'container_name' => $_POST['rsccontainer'],
]
);
$storage_provider->create_container( $_POST['newrsccontainer'] );
$newrsccontainer = sanitize_text_field( $_POST['newrsccontainer'] );
// translators: %s: container name.
BackWPup_Admin::message( sprintf( __( 'Rackspace Cloud container "%s" created.', 'backwpup' ), esc_html( sanitize_text_field( $_POST['newrsccontainer'] ) ) ) );
} catch ( Exception $e ) {
// translators: %s: error message.
BackWPup_Admin::message( sprintf( __( 'Rackspace Cloud API: %s', 'backwpup' ), $e->getMessage() ), true );
}
}
$jobids = (array) $id;
foreach ( $jobids as $id ) {
BackWPup_Option::update( $id, 'rscusername', sanitize_text_field( $_POST['rscusername'] ) );
BackWPup_Option::update( $id, 'rscapikey', sanitize_text_field( $_POST['rscapikey'] ) );
BackWPup_Option::update( $id, 'rsccontainer', isset( $_POST['rsccontainer'] ) ? sanitize_text_field( $_POST['rsccontainer'] ) : '' );
BackWPup_Option::update( $id, 'rscregion', ! empty( $_POST['rscregion'] ) ? sanitize_text_field( $_POST['rscregion'] ) : 'DFW' );
BackWPup_Option::update( $id, 'rscdir', $_POST['rscdir'] );
BackWPup_Option::update( $id, 'rscmaxbackups', isset( $_POST['rscmaxbackups'] ) && is_numeric( $_POST['rscmaxbackups'] ) ? absint( $_POST['rscmaxbackups'] ) : $this->option_defaults()['rscmaxbackups'] );
BackWPup_Option::update( $id, 'rscsyncnodelete', ! empty( $_POST['rscsyncnodelete'] ) );
if ( ! empty( $newrsccontainer ) ) {
BackWPup_Option::update( $id, 'rsccontainer', $newrsccontainer );
}
}
}
// phpcs:enable
/**
* Delete file
*
* @param string $jobdest Job destination.
* @param string $backupfile File to be deleted.
*
* @return void
*/
public function file_delete( string $jobdest, string $backupfile ): void {
$files = get_site_transient( 'backwpup_' . strtolower( $jobdest ) );
[$jobid, $dest] = explode( '_', $jobdest );
$storage_provider = $this->get_rackspace_client(
[
'region' => BackWPup_Option::get( $jobid, 'rscregion' ),
'username' => BackWPup_Option::get( $jobid, 'rscusername' ),
'api_key' => BackWPup_Option::get( $jobid, 'rscapikey' ) ,
'container_name' => BackWPup_Option::get( $jobid, 'rsccontainer' ),
]
);
$delete = $storage_provider->delete_object( $backupfile, $jobid );
if ( $delete ) {
foreach ( $files as $key => $file ) {
if ( is_array( $file ) && $file['file'] === $backupfile ) {
unset( $files[ $key ] );
}
}
}
$key = 'backwpup_' . strtolower( $jobdest );
/**
* Fires after jobs is updated.
*
* @since 5.2.1
*
* @param string $key The newly backup reference key.
* @param array $files An array of files data.
*/
do_action( 'backwpup_update_backup_history', $key, $files );
}
/**
* Get Rackspace client.
*
* @param array $data Rackspace data.
*
* @return Rackspace
*/
private function get_rackspace_client( array $data ) {
$rackspace_client = new Rackspace(
[
'username' => $data['username'],
'api_key' => BackWPup_Encryption::decrypt( $data['api_key'] ),
'container_name' => $data['container_name'],
'region' => $data['region'],
],
);
$rackspace_client->initialise();
return $rackspace_client;
}
/**
* Upload backup to cloud storage.
*
* @param BackWPup_Job $job_object Job Object.
* @param Rackspace $storage_provider Storage provider.
*
* @return bool
*/
public function upload_backup( BackWPup_Job $job_object, Rackspace $storage_provider ): bool {
try {
// translators: %s: container name.
$job_object->log( sprintf( __( 'Connected to Rackspace cloud files container %s', 'backwpup' ), $job_object->job['rsccontainer'] ) );
$job_object->log( __( 'Upload to Rackspace cloud started …', 'backwpup' ), E_USER_NOTICE );
$upload = $storage_provider->upload_object(
$job_object->job['rscdir'] . $job_object->backup_file,
$job_object->backup_folder . $job_object->backup_file
);
if ( ! $upload ) {
$job_object->log( __( 'Cannot transfer backup to Rackspace cloud.', 'backwpup' ), E_USER_ERROR );
return false;
}
$modified_backup_name = $job_object->job['rscdir'] . $job_object->backup_file;
$job_object->log( __( 'Backup File transferred to RSC://', 'backwpup' ) . $job_object->job['rsccontainer'] . '/' . $modified_backup_name, E_USER_NOTICE );
$job_object->substeps_done = 1 + $job_object->backup_filesize;
if ( ! empty( $job_object->job['jobid'] ) ) {
BackWPup_Option::update(
$job_object->job['jobid'],
'lastbackupdownloadurl',
network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloadrsc&file=' . $modified_backup_name . '&jobid=' . $job_object->job['jobid']
);
}
} catch ( Exception $e ) {
$context = $this->error_context( $e->getMessage() );
$job_object->log(
/* translators: %s: Error message. */
sprintf( __( 'Rackspace Cloud API: %s', 'backwpup' ), $e->getMessage() ),
E_USER_ERROR,
$e->getFile(),
$e->getLine(),
$context
);
return false;
}
return true;
}
/**
* Handle cleanup, deletion after backup is uploaded to cloud storage.
*
* @param BackWPup_Job $job_object Job Object.
* @param Rackspace $storage_provider Storage provider.
*
* @return bool
*/
public function cleanup_after_backup_upload( BackWPup_Job $job_object, Rackspace $storage_provider ): bool {
try {
$backupfilelist = [];
$filecounter = 0;
$files = [];
$object_list = $storage_provider->object_list(
[
'prefix' => $job_object->job['rscdir'],
'delimiter' => '/',
]
);
foreach ( $object_list as $object ) {
if ( isset( $object['subdir'] ) ) {
continue;
}
$file = basename( (string) $object['name'] );
if ( $job_object->job['rscdir'] . $file === $object['name'] ) { // only in the folder and not in complete bucket.
if ( $this->is_backup_archive( $file ) && $this->is_backup_owned_by_job( $file, $job_object->job['jobid'] ) === true ) {
$backupfilelist[ strtotime( (string) $object['last_modified'] ) ] = $object;
}
}
$files[ $filecounter ]['folder'] = 'RSC://' . $job_object->job['rsccontainer'] . '/' . dirname( (string) $object['name'] ) . '/';
$files[ $filecounter ]['file'] = $object['name'];
$files[ $filecounter ]['filename'] = basename( (string) $object['name'] );
$files[ $filecounter ]['downloadurl'] = network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloadrsc&file=' . $object['name'] . '&jobid=' . $job_object->job['jobid'];
$files[ $filecounter ]['filesize'] = $object['bytes'];
$files[ $filecounter ]['time'] = strtotime( (string) $object['last_modified'] );
++$filecounter;
}
if ( ! empty( $job_object->job['rscmaxbackups'] ) && $job_object->job['rscmaxbackups'] > 0 ) { // Delete old backups.
if ( count( $backupfilelist ) > $job_object->job['rscmaxbackups'] ) {
ksort( $backupfilelist );
$numdeltefiles = 0;
$deleted_files = [];
while ( ! empty( $backupfilelist ) ) {
$file = array_shift( $backupfilelist );
if ( count( $backupfilelist ) < $job_object->job['rscmaxbackups'] ) {
break;
}
foreach ( $files as $key => $filedata ) {
if ( $filedata['file'] === $file['name'] ) {
$deleted_files[] = $filedata['filename'];
unset( $files[ $key ] );
}
}
$storage_provider->delete_object( $file['name'], (string) $job_object->job['jobid'] );
++$numdeltefiles;
}
if ( $numdeltefiles > 0 ) {
$job_object->log(
sprintf(
// Translators: %d is the number of files deleted from the Rackspace cloud container.
_n(
'%d file deleted on Rackspace cloud container.',
'%d files deleted on Rackspace cloud container.',
$numdeltefiles,
'backwpup'
),
$numdeltefiles
),
E_USER_NOTICE
);
}
parent::remove_file_history_from_database( $deleted_files, 'RSC' );
}
}
set_site_transient( 'backwpup_' . $job_object->job['jobid'] . '_rsc', $files, YEAR_IN_SECONDS );
} catch ( Exception $e ) {
$context = $this->error_context( $e->getMessage() );
$job_object->log(
/* translators: %s: Error message. */
sprintf( __( 'Rackspace Cloud API: %s', 'backwpup' ), $e->getMessage() ),
E_USER_ERROR,
$e->getFile(),
$e->getLine(),
$context
);
return false;
}
return true;
}
/**
* Upload the backup archive to Rackspace.
*
* @param BackWPup_Job $job_object Job object.
*
* @return bool True on success, false on failure.
*/
public function job_run_archive( BackWPup_Job $job_object ): bool {
$job_object->substeps_todo = 2 + $job_object->backup_filesize;
$job_object->substeps_done = 0;
$job_object->log(
sprintf(
/* translators: %d: attempt number. */
__( '%d. Trying to send backup file to Rackspace cloud …', 'backwpup' ),
$job_object->steps_data[ $job_object->step_working ]['STEP_TRY']
),
E_USER_NOTICE
);
$storage_provider = $this->get_rackspace_client(
[
'region' => $job_object->job['rscregion'],
'username' => $job_object->job['rscusername'],
'api_key' => $job_object->job['rscapikey'],
'container_name' => $job_object->job['rsccontainer'],
]
);
if ( ! $this->upload_backup( $job_object, $storage_provider ) ) {
return false;
}
if ( ! $this->cleanup_after_backup_upload( $job_object, $storage_provider ) ) {
return false;
}
++$job_object->substeps_done;
return true;
}
/**
* Determines whether the destination can run with the provided settings.
*
* @param array $job_settings
* @param bool $test_connection Job settings.
*/
public function can_run( array $job_settings, bool $test_connection = true ): bool {
if ( empty( $job_settings['rscusername'] ) ) {
return false;
}
if ( empty( $job_settings['rscapikey'] ) ) {
return false;
}
return ! ( empty( $job_settings['rsccontainer'] ) );
}
/**
* Outputs inline JS for the Rackspace container selector.
*
* @return void
*/
public function edit_inline_js(): void {
?>
<script type="text/javascript">
jQuery(document).ready(function ($) {
function rscgetcontainer() {
var data = {
action: 'backwpup_dest_rsc',
rscusername: $('#rscusername').val(),
rscapikey: $('#rscapikey').val(),
rscregion: $('#rscregion').val(),
rscselected: $('#rsccontainer').val(),
_ajax_nonce: $('input[name="backwpupajaxnonce"]').val()
};
$.post(ajaxurl, data, function (response) {
$('#rscbucketContainer').html(response);
});
}
$('#rscregion').on('change', function () {
rscgetcontainer();
});
$('#rscusername').backwpupDelayKeyup(function () {
rscgetcontainer();
});
$('#rscapikey').backwpupDelayKeyup(function () {
rscgetcontainer();
});
});
</script>
<?php
}
/**
* Edit ajax
*
* @param array $args Storage data like username, containers, region etc.
*
* @return void
*/
public function edit_ajax( array $args = [] ): void {
$error = '';
$ajax = false;
if ( isset( $_POST['rscusername'] ) || isset( $_POST['rscapikey'] ) ) {
if ( ! current_user_can( 'backwpup_jobs_edit' ) ) {
wp_die( -1 );
}
check_ajax_referer( 'backwpup_ajax_nonce' );
$post = wp_unslash( $_POST );
$args['rscusername'] = isset( $post['rscusername'] ) ? sanitize_text_field( $post['rscusername'] ) : '';
$args['rscapikey'] = isset( $post['rscapikey'] ) ? sanitize_text_field( $post['rscapikey'] ) : '';
$args['rscselected'] = isset( $post['rscselected'] ) ? sanitize_text_field( $post['rscselected'] ) : '';
$args['rscregion'] = isset( $post['rscregion'] ) ? sanitize_text_field( $post['rscregion'] ) : '';
$ajax = true;
}
echo '<span id="rsccontainererror" class="bwu-message-error">';
$container_list = [];
if ( ! empty( $args['rscusername'] ) && ! empty( $args['rscapikey'] ) && ! empty( $args['rscregion'] ) ) {
try {
$storage_provider = $this->get_rackspace_client(
[
'region' => $args['rscregion'],
'username' => $args['rscusername'],
'api_key' => $args['rscapikey'],
'container_name' => '', // No container yet, so this will be blank.
]
);
$containers = $storage_provider->get_containers();
if ( ! empty( $containers ) ) {
foreach ( $containers as $container ) {
$container_list[] = $container['name'];
}
}
} catch ( Exception $e ) {
$error = $e->getMessage();
}
}
if ( empty( $args['rscusername'] ) ) {
esc_html_e( 'Missing username!', 'backwpup' );
} elseif ( empty( $args['rscapikey'] ) ) {
esc_html_e( 'Missing API Key!', 'backwpup' );
} elseif ( ! empty( $error ) ) {
echo esc_html( $error );
} elseif ( empty( $container_list ) ) {
esc_html_e( 'A container could not be found!', 'backwpup' );
}
echo '</span>';
if ( ! empty( $container_list ) ) {
$mapped_containers = array_combine( $container_list, $container_list );
echo BackWPupHelpers::component( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'form/select',
[
'name' => 'rsccontainer',
'identifier' => 'rsccontainer',
'label' => esc_html__( 'Container selection', 'backwpup' ),
'withEmpty' => false,
'value' => $args['rscselected'], // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'options' => $mapped_containers, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
]
);
}
if ( $ajax ) {
wp_die();
}
}
/**
* Get service name
*/
public function get_service_name(): string {
return self::SERVICE_NAME;
}
/**
* Build error context for Rackspace errors.
*
* @param string $message Error message.
* @return array
*/
private function error_context( string $message ): array {
$normalized = strtolower( $message );
if (
false !== strpos( $normalized, 'authentication' )
|| false !== strpos( $normalized, 'unauthorized' )
|| false !== strpos( $normalized, 'forbidden' )
) {
return [
'reason_code' => \WPMedia\BackWPup\Backup\ReasonCode::REASON_INCORRECT_LOGIN,
'destination' => 'RSC',
'provider_code' => 'auth_failed',
];
}
if (
false !== strpos( $normalized, 'quota' )
|| false !== strpos( $normalized, 'insufficient' )
|| false !== strpos( $normalized, 'not enough' )
) {
return [
'reason_code' => \WPMedia\BackWPup\Backup\ReasonCode::REASON_NOT_ENOUGH_STORAGE,
'destination' => 'RSC',
'provider_code' => 'quota_exceeded',
];
}
return [];
}
}