Linux puskom-ProLiant-DL385-Gen10 5.4.0-150-generic #167~18.04.1-Ubuntu SMP Wed May 24 00:51:42 UTC 2023 x86_64
/
home
/
puskom
/
mastur
/
backwpup
/
inc
/
//home/puskom/mastur/backwpup/inc/class-destination-s3.php
<?php // Amazon S3 SDK v3.93.7 // http://aws.amazon.com/de/sdkforphp2/ // https://github.com/aws/aws-sdk-php // http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region use Aws\Exception\AwsException; use Aws\S3\Exception\S3Exception; use Inpsyde\BackWPupShared\File\MimeTypeExtractor; /** * Documentation: http://docs.amazonwebservices.com/aws-sdk-php-2/latest/class-Aws.S3.S3Client.html. */ class BackWPup_Destination_S3 extends BackWPup_Destinations { public function option_defaults(): array { return [ 's3base_url' => '', 's3base_multipart' => true, 's3base_pathstylebucket' => false, 's3base_version' => 'latest', 's3base_signature' => 'v4', 's3accesskey' => '', 's3secretkey' => '', 's3bucket' => '', 's3region' => 'us-east-1', 's3ssencrypt' => '', 's3storageclass' => '', 's3dir' => trailingslashit(sanitize_file_name(get_bloginfo('name'))), 's3maxbackups' => 15, 's3syncnodelete' => true, ]; } public function edit_tab(int $jobid): void { ?> <h3 class="title"> <?php esc_html_e('S3 Service', 'backwpup'); ?> </h3> <table class="form-table"> <tr> <th scope="row"> <label for="s3region"> <?php esc_html_e('Select a S3 service', 'backwpup'); ?> </label> </th> <td> <select name="s3region" id="s3region" title="<?php esc_attr_e('S3 Region', 'backwpup'); ?>"> <?php foreach (BackWPup_S3_Destination::options() as $id => $option) { ?> <option value="<?php echo esc_attr($id); ?>" <?php selected($id, BackWPup_Option::get($jobid, 's3region')); ?> > <?php echo esc_html($option['label']); ?> </option> <?php } ?> </select> </td> </tr> <tr> <th scope="row"> <label for="s3base_url"> <?php esc_html_e('Or a S3 Server URL', 'backwpup'); ?> </label> </th> <td> <div class="card" style="margin-top:0;padding:10px"> <table class="form-table"> <tbody> <tr> <th scope="row"> <label for="s3base_url-s3"><?php esc_html_e('Endpoint', 'backwpup'); ?><span style="color:red">*</span></label> </th> <td> <input id="s3base_url" name="s3base_url" type="text" value="<?php echo esc_attr( BackWPup_Option::get($jobid, 's3base_url') ); ?>" class="regular-text" autocomplete="off" /> <p class="description"><?php esc_html_e( 'Leave it empty to use a destination from S3 service list', 'backwpup' ); ?></p> </td> </tr> <tr> <th scope="row"> <label for="s3base_region"><?php esc_html_e( 'Region', 'backwpup' ); ?><span style="color:red">*</span></label> </th> <td> <input type="text" name="s3base_region" value="<?php echo esc_attr( BackWPup_Option::get($jobid, 's3base_region') ); ?>" class="regular-text" autocomplete="off"> <p class="description"><?php esc_html_e( 'Specify S3 region like "us-west-1"', 'backwpup' ); ?></p> </td> </tr> </tbody> <tbody class="custom_s3_advanced"> <tr> <th scope="row"><?php esc_html_e('Multipart', 'backwpup'); ?></th> <td> <fieldset> <legend class="screen-reader-text"> <span><?php esc_html_e( 'Multipart', 'backwpup' ); ?></span> </legend> <label for="s3base_multipart"> <input name="s3base_multipart" type="checkbox" value="1"<?php echo checked( BackWPup_Option::get( $jobid, 's3base_multipart' ), true ); ?>> <?php esc_html_e( 'Destination supports multipart', 'backwpup' ); ?> </label> </fieldset> </td> </tr> <tr> <th scope="row"><?php esc_html_e( 'Pathstyle-Only Bucket', 'backwpup' ); ?></th> <td> <fieldset> <legend class="screen-reader-text"> <span><?php esc_html_e( 'Pathstyle-Only Bucket', 'backwpup' ); ?></span> </legend> <label for="s3base_pathstylebucket"> <input name="s3base_pathstylebucket" type="checkbox" value="1"<?php echo checked( BackWPup_Option::get( $jobid, 's3base_pathstylebucket' ), true ); ?>> <?php esc_html_e( 'Destination provides only Pathstyle buckets', 'backwpup' ); ?> </label> <p class="description"><?php esc_html_e( 'Example: http://s3.example.com/bucket-name', 'backwpup' ); ?></p> </fieldset> </td> </tr> <tr> <th scope="row"> <label for="s3base_version">Version</label> </th> <td> <input type="text" name="s3base_version" value="<?php echo !empty( BackWPup_Option::get( $jobid, 's3base_version' ) ) ? esc_attr( BackWPup_Option::get($jobid, 's3base_version') ) : 'latest'; ?>" placeholder="latest"> <p class="description"><?php esc_html_e( 'The S3 version for the API like "2006-03-01", default "latest"', 'backwpup' ); ?></p> </td> </tr> <tr> <th scope="row"> <label for="s3base_signature"><?php esc_html_e( 'Signature', 'backwpup' ); ?></label> </th> <td> <input type="text" name="s3base_signature" value="<?php echo !empty( BackWPup_Option::get( $jobid, 's3base_signature' ) ) ? esc_attr( BackWPup_Option::get($jobid, 's3base_signature') ) : 'v4'; ?>" placeholder="v4"> <p class="description"><?php esc_html_e( 'The signature for the API like "v4"', 'backwpup' ); ?></p> </td> </tr> </tbody><!-- advanced section--> </table> </div> </td><!-- custom s3 section--> </tr> </table> <h3 class="title"> <?php esc_html_e('S3 Access Keys', 'backwpup'); ?> </h3> <table class="form-table"> <tr> <th scope="row"> <label for="s3accesskey"> <?php esc_html_e('Access Key', 'backwpup'); ?> </label> </th> <td> <input id="s3accesskey" name="s3accesskey" type="text" value="<?php echo esc_attr(BackWPup_Option::get($jobid, 's3accesskey')); ?>" class="regular-text" autocomplete="off" /> </td> </tr> <tr> <th scope="row"><label for="s3secretkey"><?php esc_html_e('Secret Key', 'backwpup'); ?></label></th> <td> <input id="s3secretkey" name="s3secretkey" type="password" value="<?php echo esc_attr(BackWPup_Encryption::decrypt(BackWPup_Option::get( $jobid, 's3secretkey' ))); ?>" class="regular-text" autocomplete="off"/> </td> </tr> </table> <h3 class="title"> <?php esc_html_e('S3 Bucket', 'backwpup'); ?> </h3> <table class="form-table"> <tr> <th scope="row"> <label for="s3bucketselected"> <?php esc_html_e('Bucket selection', 'backwpup'); ?> </label> </th> <td> <input id="s3bucketselected" name="s3bucketselected" type="hidden" value="<?php echo esc_attr(BackWPup_Option::get($jobid, 's3bucket')); ?>" /> <?php if (BackWPup_Option::get($jobid, 's3accesskey') && BackWPup_Option::get($jobid, 's3secretkey') ) { $this->edit_ajax( [ 's3accesskey' => BackWPup_Option::get($jobid, 's3accesskey'), 's3secretkey' => BackWPup_Option::get($jobid, 's3secretkey'), 's3bucketselected' => BackWPup_Option::get($jobid, 's3bucket'), 's3region' => BackWPup_Option::get($jobid, 's3region'), 's3base_url' => BackWPup_Option::get($jobid, 's3base_url'), 's3base_region' => BackWPup_Option::get($jobid, 's3base_region'), 's3base_multipart' => BackWPup_Option::get( $jobid, 's3base_multipart' ), 's3base_pathstylebucket' => BackWPup_Option::get( $jobid, 's3base_pathstylebucket' ), 's3base_version' => BackWPup_Option::get($jobid, 's3base_version'), 's3base_signature' => BackWPup_Option::get( $jobid, 's3base_signature' ), ] ); } ?> </td> </tr> <tr> <th scope="row"> <label for="s3newbucket"> <?php esc_html_e('Create a new bucket', 'backwpup'); ?> </label> </th> <td> <input id="s3newbucket" name="s3newbucket" type="text" value="" size="63" class="regular-text" autocomplete="off" /> </td> </tr> </table> <h3 class="title"> <?php esc_html_e('S3 Backup settings', 'backwpup'); ?> </h3> <table class="form-table"> <tr> <th scope="row"> <label for="ids3dir"> <?php esc_html_e('Folder in bucket', 'backwpup'); ?> </label> </th> <td> <input id="ids3dir" name="s3dir" type="text" value="<?php echo esc_attr(BackWPup_Option::get($jobid, 's3dir')); ?>" class="regular-text" /> </td> </tr> <tr> <th scope="row"><?php esc_html_e('File deletion', 'backwpup'); ?></th> <td> <?php if (BackWPup_Option::get($jobid, 'backuptype') === 'archive') { ?> <label for="ids3maxbackups"> <input id="ids3maxbackups" name="s3maxbackups" type="number" min="0" step="1" value="<?php echo esc_attr(BackWPup_Option::get($jobid, 's3maxbackups')); ?>" class="small-text" /> <?php esc_html_e('Number of files to keep in folder.', 'backwpup'); ?> </label> <p> <?php _e( '<strong>Warning</strong>: Files belonging to this job are now tracked. Old backup archives which are untracked will not be automatically deleted.', 'backwpup' ); ?> </p> <?php } else { ?> <label for="ids3syncnodelete"> <input class="checkbox" value="1" type="checkbox" <?php checked(BackWPup_Option::get($jobid, 's3syncnodelete'), true); ?> name="s3syncnodelete" id="ids3syncnodelete" /> <?php esc_html_e('Do not delete files while syncing to destination!', 'backwpup'); ?> </label> <?php } ?> </td> </tr> </table> <h3 class="title"><?php esc_html_e('Amazon specific settings', 'backwpup'); ?></h3> <table class="form-table"> <tr> <th scope="row"> <label for="ids3storageclass"> <?php esc_html_e('Amazon: Storage Class', 'backwpup'); ?> </label> </th> <td> <?php $storageClass = BackWPup_Option::get($jobid, 's3storageclass'); ?> <select name="s3storageclass" id="ids3storageclass" title="<?php esc_html_e('Amazon: Storage Class', 'backwpup'); ?>"> <option value="" <?php selected('', $storageClass, true); ?>> <?php esc_html_e('Standard', 'backwpup'); ?> </option> <option value="STANDARD_IA" <?php selected('STANDARD_IA', $storageClass, true); ?>> <?php esc_html_e('Standard-Infrequent Access', 'backwpup'); ?> </option> <option value="ONEZONE_IA" <?php selected('ONEZONE_IA', $storageClass, true); ?>> <?php esc_html_e('One Zone-Infrequent Access', 'backwpup'); ?> </option> <option value="REDUCED_REDUNDANCY" <?php selected('REDUCED_REDUNDANCY', $storageClass, true); ?>> <?php esc_html_e('Reduced Redundancy', 'backwpup'); ?> </option> <option value="INTELLIGENT_TIERING" <?php selected('INTELLIGENT_TIERING', $storageClass, true); ?>> <?php esc_html_e('Intelligent-Tiering', 'backwpup'); ?> </option> <option value="GLACIER_IR" <?php selected('GLACIER_IR', $storageClass, true); ?>> <?php esc_html_e('Glacier Instant Retrieval', 'backwpup'); ?> </option> </select> </td> </tr> <tr> <th scope="row"> <label for="ids3ssencrypt"> <?php esc_html_e('Server side encryption', 'backwpup'); ?> </label> </th> <td> <input class="checkbox" value="AES256" type="checkbox" <?php checked(BackWPup_Option::get($jobid, 's3ssencrypt'), 'AES256'); ?> name="s3ssencrypt" id="ids3ssencrypt" /> <?php esc_html_e('Save files encrypted (AES256) on server.', 'backwpup'); ?> </td> </tr> </table> <?php } public function edit_ajax(array $args = []): void { $vaults = []; $buckets = []; $error = ''; $buckets_list = []; $ajax = false; if (!$args) { if (!current_user_can('backwpup_jobs_edit')) { wp_die(-1); } check_ajax_referer('backwpup_ajax_nonce'); $args = []; $args['s3accesskey'] = sanitize_text_field($_POST['s3accesskey']); $args['s3secretkey'] = sanitize_text_field($_POST['s3secretkey']); $args['s3bucketselected'] = sanitize_text_field($_POST['s3bucketselected']); $args['s3region'] = sanitize_text_field($_POST['s3region']); $args['s3base_url'] = backwpup_esc_url_default_secure($_POST['s3base_url'], ['http', 'https']); $args['s3base_region'] = sanitize_text_field($_POST['s3base_region']); $args['s3base_multipart'] = sanitize_text_field($_POST['s3base_multipart']); $args['s3base_pathstylebucket'] = sanitize_text_field($_POST['s3base_pathstylebucket']); $args['s3base_version'] = sanitize_text_field($_POST['s3base_version']); $args['s3base_signature'] = sanitize_text_field($_POST['s3base_signature']); $ajax = true; } if ($args['s3base_url']) { $args['s3region'] = $args['s3base_url']; } echo '<span id="s3bucketerror" class="bwu-message-error">'; if (!empty($args['s3accesskey']) && !empty($args['s3secretkey'])) { if (empty($args['s3base_url'])) { $aws_destination = BackWPup_S3_Destination::fromOption($args['s3region']); } else { $options = [ 'label' => __('Custom S3 destination', 'backwpup'), 'endpoint' => $args['s3base_url'], 'region' => $args['s3base_region'], 'multipart' => !empty($args['s3base_multipart']) ? true : false, 'only_path_style_bucket' => !empty($args['s3base_pathstylebucket']) ? true : false, 'version' => $args['s3base_version'], 'signature' => $args['s3base_signature'], ]; $aws_destination = BackWPup_S3_Destination::fromOptionArray($options); } try { $s3 = $aws_destination->client($args['s3accesskey'], $args['s3secretkey']); $buckets = $s3->listBuckets(); if (!empty($buckets['Buckets'])) { $buckets_list = $buckets['Buckets']; } while (!empty($vaults['Marker'])) { $buckets = $s3->listBuckets(['marker' => $buckets['Marker']]); if (!empty($buckets['Buckets'])) { $buckets_list = array_merge($buckets_list, $buckets['Buckets']); } } } catch (Exception $e) { $error = $e->getMessage(); if ($e instanceof AwsException) { $error = $e->getAwsErrorMessage(); } } } if (empty($args['s3accesskey'])) { esc_html_e('Missing access key!', 'backwpup'); } elseif (empty($args['s3secretkey'])) { esc_html_e('Missing secret access key!', 'backwpup'); } elseif (!empty($error) && $error === 'Access Denied') { echo '<input type="text" name="s3bucket" id="s3bucket" value="' . esc_attr($args['s3bucketselected']) . '" >'; } elseif (!empty($error)) { echo esc_html($error); } elseif (empty($buckets) || count($buckets['Buckets']) < 1) { esc_html_e('No bucket found!', 'backwpup'); } echo '</span>'; if (!empty($buckets_list)) { echo '<select name="s3bucket" id="s3bucket">'; foreach ($buckets_list as $bucket) { echo '<option ' . selected($args['s3bucketselected'], esc_attr($bucket['Name']), false) . '>' . esc_attr($bucket['Name']) . '</option>'; } echo '</select>'; } if ($ajax) { exit(); } } public function edit_form_post_save(int $jobid): void { BackWPup_Option::update($jobid, 's3accesskey', sanitize_text_field($_POST['s3accesskey'])); BackWPup_Option::update( $jobid, 's3secretkey', isset($_POST['s3secretkey']) ? BackWPup_Encryption::encrypt($_POST['s3secretkey']) : '' ); BackWPup_Option::update( $jobid, 's3base_url', isset($_POST['s3base_url']) ? backwpup_esc_url_default_secure($_POST['s3base_url'], ['http', 'https']) : '' ); BackWPup_Option::update( $jobid, 's3base_region', isset($_POST['s3base_region']) ? sanitize_text_field($_POST['s3base_region']) : '' ); BackWPup_Option::update( $jobid, 's3base_multipart', isset($_POST['s3base_multipart']) ? '1' : '' ); BackWPup_Option::update( $jobid, 's3base_pathstylebucket', isset($_POST['s3base_pathstylebucket']) ? '1' : '' ); BackWPup_Option::update( $jobid, 's3base_version', isset($_POST['s3base_version']) ? sanitize_text_field( $_POST['s3base_version'] ) : 'latest' ); BackWPup_Option::update( $jobid, 's3base_signature', isset($_POST['s3base_signature']) ? sanitize_text_field( $_POST['s3base_signature'] ) : 'v4' ); BackWPup_Option::update($jobid, 's3region', sanitize_text_field($_POST['s3region'])); BackWPup_Option::update($jobid, 's3storageclass', sanitize_text_field($_POST['s3storageclass'])); BackWPup_Option::update( $jobid, 's3ssencrypt', (isset($_POST['s3ssencrypt']) && $_POST['s3ssencrypt'] === 'AES256') ? 'AES256' : '' ); BackWPup_Option::update( $jobid, 's3bucket', isset($_POST['s3bucket']) ? sanitize_text_field($_POST['s3bucket']) : '' ); $_POST['s3dir'] = trailingslashit(str_replace( '//', '/', str_replace('\\', '/', trim(sanitize_text_field($_POST['s3dir']))) )); if (strpos($_POST['s3dir'], '/') === 0) { $_POST['s3dir'] = substr($_POST['s3dir'], 1); } if ($_POST['s3dir'] === '/') { $_POST['s3dir'] = ''; } BackWPup_Option::update($jobid, 's3dir', $_POST['s3dir']); BackWPup_Option::update( $jobid, 's3maxbackups', !empty($_POST['s3maxbackups']) ? absint($_POST['s3maxbackups']) : 0 ); BackWPup_Option::update($jobid, 's3syncnodelete', !empty($_POST['s3syncnodelete'])); //create new bucket if (!empty($_POST['s3newbucket'])) { try { $region = BackWPup_Option::get($jobid, 's3base_url'); if (empty($region)) { $region = BackWPup_Option::get($jobid, 's3region'); $aws_destination = BackWPup_S3_Destination::fromOption($region); } else { $aws_destination = BackWPup_S3_Destination::fromJobId($jobid); } $s3 = $aws_destination->client( BackWPup_Option::get($jobid, 's3accesskey'), BackWPup_Option::get($jobid, 's3secretkey') ); $s3->createBucket( [ 'Bucket' => sanitize_text_field($_POST['s3newbucket']), 'PathStyle' => $aws_destination->onlyPathStyleBucket(), 'LocationConstraint' => $aws_destination->region(), ] ); BackWPup_Admin::message( sprintf( __('Bucket %1$s created.', 'backwpup'), sanitize_text_field($_POST['s3newbucket']) ) ); } catch (S3Exception $e) { BackWPup_Admin::message($e->getMessage(), true); } BackWPup_Option::update($jobid, 's3bucket', sanitize_text_field($_POST['s3newbucket'])); } } public function file_delete(string $jobdest, string $backupfile): void { $files = get_site_transient('backwpup_' . strtolower($jobdest)); [$jobid, $dest] = explode('_', $jobdest); if (BackWPup_Option::get($jobid, 's3accesskey') && BackWPup_Option::get( $jobid, 's3secretkey' ) && BackWPup_Option::get($jobid, 's3bucket')) { try { $region = BackWPup_Option::get($jobid, 's3base_url'); if (empty($region)) { $region = BackWPup_Option::get($jobid, 's3region'); $aws_destination = BackWPup_S3_Destination::fromOption($region); } else { $aws_destination = BackWPup_S3_Destination::fromJobId($jobid); } $s3 = $aws_destination->client( BackWPup_Option::get($jobid, 's3accesskey'), BackWPup_Option::get($jobid, 's3secretkey') ); $s3->deleteObject([ 'Bucket' => BackWPup_Option::get($jobid, 's3bucket'), 'Key' => $backupfile, ]); //update file list foreach ((array) $files as $key => $file) { if (is_array($file) && $file['file'] === $backupfile) { unset($files[$key]); } } unset($s3); } catch (Exception $e) { $errorMessage = $e->getMessage(); if ($e instanceof AwsException) { $errorMessage = $e->getAwsErrorMessage(); } BackWPup_Admin::message(sprintf(__('S3 Service API: %s', 'backwpup'), $errorMessage), true); } } set_site_transient('backwpup_' . strtolower($jobdest), $files, YEAR_IN_SECONDS); } /** * {@inheritdoc} */ public function file_get_list(string $jobdest): array { $list = (array) get_site_transient('backwpup_' . strtolower($jobdest)); return array_filter($list); } /** * File Update List. * * Update the list of files in the transient. * * @param BackWPup_Job|int $job Either the job object or job ID * @param bool $delete whether to delete old backups */ public function file_update_list($job, bool $delete = false): void { if ($job instanceof BackWPup_Job) { $job_object = $job; $jobid = $job->job['jobid']; } else { $job_object = null; $jobid = $job; } if (empty($job_object->job['s3base_url'])) { $aws_destination = BackWPup_S3_Destination::fromOption($job_object->job['s3region']); } else { $aws_destination = BackWPup_S3_Destination::fromJobId($job_object->job['jobid']); } $s3 = $aws_destination->client( BackWPup_Option::get($jobid, 's3accesskey'), BackWPup_Option::get($jobid, 's3secretkey') ); $backupfilelist = []; $filecounter = 0; $files = []; $args = [ 'Bucket' => BackWPup_Option::get($jobid, 's3bucket'), 'Prefix' => BackWPup_Option::get($jobid, 's3dir'), ]; $objects = $s3->getIterator('ListObjects', $args); if (is_object($objects)) { foreach ($objects as $object) { $file = basename($object['Key']); $changetime = strtotime($object['LastModified']) + (get_option('gmt_offset') * 3600); if ($this->is_backup_archive($file) && $this->is_backup_owned_by_job($file, $jobid)) { $backupfilelist[$changetime] = $file; } $files[$filecounter]['folder'] = $s3->getObjectUrl(BackWPup_Option::get($jobid, 's3bucket'), dirname($object['Key'])); $files[$filecounter]['file'] = $object['Key']; $files[$filecounter]['filename'] = basename($object['Key']); if (!empty($object['StorageClass'])) { $files[$filecounter]['info'] = sprintf( __('Storage Class: %s', 'backwpup'), $object['StorageClass'] ); } $files[$filecounter]['downloadurl'] = network_admin_url('admin.php') . '?page=backwpupbackups&action=downloads3&file=' . $object['Key'] . '&local_file=' . basename($object['Key']) . '&jobid=' . $jobid; $files[$filecounter]['filesize'] = (int) $object['Size']; $files[$filecounter]['time'] = $changetime; ++$filecounter; } } if ($delete && $job_object && $job_object->job['s3maxbackups'] > 0 && is_object($s3)) { //Delete old backups if (count($backupfilelist) > $job_object->job['s3maxbackups']) { ksort($backupfilelist); $numdeltefiles = 0; while ($file = array_shift($backupfilelist)) { if (count($backupfilelist) < $job_object->job['s3maxbackups']) { break; } //delete files on S3 $args = [ 'Bucket' => $job_object->job['s3bucket'], 'Key' => $job_object->job['s3dir'] . $file, ]; if ($s3->deleteObject($args)) { foreach ($files as $key => $filedata) { if ($filedata['file'] == $job_object->job['s3dir'] . $file) { unset($files[$key]); } } ++$numdeltefiles; } else { $job_object->log( sprintf( __('Cannot delete backup from %s.', 'backwpup'), $s3->getObjectUrl($job_object->job['s3bucket'], $job_object->job['s3dir'] . $file) ), E_USER_ERROR ); } } if ($numdeltefiles > 0) { $job_object->log(sprintf( _n( 'One file deleted on S3 Bucket.', '%d files deleted on S3 Bucket', $numdeltefiles, 'backwpup' ), $numdeltefiles )); } } } set_site_transient('backwpup_' . $jobid . '_s3', $files, YEAR_IN_SECONDS); } public function job_run_archive(BackWPup_Job $job_object): bool { $job_object->substeps_todo = 2 + $job_object->backup_filesize; if ($job_object->steps_data[$job_object->step_working]['SAVE_STEP_TRY'] != $job_object->steps_data[$job_object->step_working]['STEP_TRY']) { $job_object->log( sprintf( __('%d. Trying to send backup file to S3 Service …', 'backwpup'), $job_object->steps_data[$job_object->step_working]['STEP_TRY'] ) ); } try { if (empty($job_object->job['s3base_url'])) { $aws_destination = BackWPup_S3_Destination::fromOption($job_object->job['s3region']); } else { $aws_destination = BackWPup_S3_Destination::fromJobId($job_object->job['jobid']); } $s3 = $aws_destination->client( $job_object->job['s3accesskey'], $job_object->job['s3secretkey'] ); if ($job_object->steps_data[$job_object->step_working]['SAVE_STEP_TRY'] != $job_object->steps_data[$job_object->step_working]['STEP_TRY'] && $job_object->substeps_done < $job_object->backup_filesize) { if ($s3->doesBucketExist($job_object->job['s3bucket'])) { $bucketregion = $s3->getBucketLocation(['Bucket' => $job_object->job['s3bucket']]); $job_object->log( sprintf( __('Connected to S3 Bucket "%1$s" in %2$s', 'backwpup'), $job_object->job['s3bucket'], $bucketregion->get('LocationConstraint') ) ); } else { $job_object->log(sprintf( __('S3 Bucket "%s" does not exist!', 'backwpup'), $job_object->job['s3bucket'] ), E_USER_ERROR); return true; } if ($aws_destination->supportsMultipart() && empty($job_object->steps_data[$job_object->step_working]['UploadId'])) { //Check for aborted Multipart Uploads $job_object->log(__('Checking for not aborted multipart Uploads …', 'backwpup')); $multipart_uploads = $s3->listMultipartUploads([ 'Bucket' => $job_object->job['s3bucket'], 'Prefix' => (string) $job_object->job['s3dir'], ]); $uploads = $multipart_uploads->get('Uploads'); if (!empty($uploads)) { foreach ($uploads as $upload) { $s3->abortMultipartUpload([ 'Bucket' => $job_object->job['s3bucket'], 'Key' => $upload['Key'], 'UploadId' => $upload['UploadId'], ]); $job_object->log(sprintf(__('Upload for %s aborted.', 'backwpup'), $upload['Key'])); } } } //transfer file to S3 $job_object->log(__('Starting upload to S3 Service …', 'backwpup')); } if (!$aws_destination->supportsMultipart() || $job_object->backup_filesize < 1048576 * 6) { // Prepare Upload if (!$up_file_handle = fopen($job_object->backup_folder . $job_object->backup_file, 'rb')) { $job_object->log(__('Can not open source file for transfer.', 'backwpup'), E_USER_ERROR); return false; } $create_args = []; $create_args['Bucket'] = $job_object->job['s3bucket']; $create_args['ACL'] = 'private'; // Encryption if (!empty($job_object->job['s3ssencrypt'])) { $create_args['ServerSideEncryption'] = $job_object->job['s3ssencrypt']; } // Storage Class if (!empty($job_object->job['s3storageclass'])) { $create_args['StorageClass'] = $job_object->job['s3storageclass']; } $create_args['Metadata'] = ['BackupTime' => date('Y-m-d H:i:s', $job_object->start_time)]; $create_args['Body'] = $up_file_handle; $create_args['Key'] = $job_object->job['s3dir'] . $job_object->backup_file; $create_args['ContentType'] = MimeTypeExtractor::fromFilePath($job_object->backup_folder . $job_object->backup_file); $create_args['ContentMD5'] = base64_encode(md5_file($job_object->backup_folder . $job_object->backup_file, true)); try { $s3->putObject($create_args); } catch (Exception $e) { $errorMessage = $e->getMessage(); if ($e instanceof AwsException) { $errorMessage = $e->getAwsErrorMessage(); } $job_object->log( E_USER_ERROR, sprintf(__('S3 Service API: %s', 'backwpup'), $errorMessage), $e->getFile(), $e->getLine() ); return false; } } else { // Prepare Upload if (!($file_handle = fopen( $job_object->backup_folder . $job_object->backup_file, 'rb' ))) { $job_object->log( __('Can not open source file for transfer.', 'backwpup'), E_USER_ERROR ); return false; } fseek($file_handle, $job_object->substeps_done); try { if (empty($job_object->steps_data[$job_object->step_working]['UploadId'])) { $args = [ 'ACL' => 'private', 'Bucket' => $job_object->job['s3bucket'], 'ContentType' => MimeTypeExtractor::fromFilePath( $job_object->backup_folder . $job_object->backup_file ), 'Key' => $job_object->job['s3dir'] . $job_object->backup_file, ]; if (!empty($job_object->job['s3ssencrypt'])) { $args['ServerSideEncryption'] = $job_object->job['s3ssencrypt']; } if (!empty($job_object->job['s3storageclass'])) { $args['StorageClass'] = empty($job_object->job['s3storageclass']) ? '' : $job_object->job['s3storageclass']; } $upload = $s3->createMultipartUpload($args); $job_object->steps_data[$job_object->step_working]['UploadId'] = $upload->get( 'UploadId' ); $job_object->steps_data[$job_object->step_working]['Parts'] = []; $job_object->steps_data[$job_object->step_working]['Part'] = 1; } while (!feof($file_handle)) { $chunk_upload_start = microtime(true); $part_data = fread($file_handle, 1048576 * 5); //5MB Minimum part size $part = $s3->uploadPart([ 'Bucket' => $job_object->job['s3bucket'], 'UploadId' => $job_object->steps_data[$job_object->step_working]['UploadId'], 'Key' => $job_object->job['s3dir'] . $job_object->backup_file, 'PartNumber' => $job_object->steps_data[$job_object->step_working]['Part'], 'Body' => $part_data, ]); $chunk_upload_time = microtime(true) - $chunk_upload_start; $job_object->substeps_done = $job_object->substeps_done + strlen( $part_data ); $job_object->steps_data[$job_object->step_working]['Parts'][] = [ 'ETag' => $part->get('ETag'), 'PartNumber' => $job_object->steps_data[$job_object->step_working]['Part'], ]; ++$job_object->steps_data[$job_object->step_working]['Part']; $time_remaining = $job_object->do_restart_time(); if ($time_remaining < $chunk_upload_time) { $job_object->do_restart_time(true); } $job_object->update_working_data(); gc_collect_cycles(); } $parts = $s3->listParts([ 'Bucket' => $job_object->job['s3bucket'], 'Key' => $job_object->job['s3dir'] . $job_object->backup_file, 'UploadId' => $job_object->steps_data[$job_object->step_working]['UploadId'], ]); $s3->completeMultipartUpload([ 'Bucket' => $job_object->job['s3bucket'], 'UploadId' => $job_object->steps_data[$job_object->step_working]['UploadId'], 'MultipartUpload' => [ 'Parts' => $parts['Parts'], ], 'Key' => $job_object->job['s3dir'] . $job_object->backup_file, ]); } catch (Exception $e) { $errorMessage = $e->getMessage(); if ($e instanceof AwsException) { $errorMessage = $e->getAwsErrorMessage(); } $job_object->log( E_USER_ERROR, sprintf(__('S3 Service API: %s', 'backwpup'), $errorMessage), $e->getFile(), $e->getLine() ); if (!empty($job_object->steps_data[$job_object->step_working]['uploadId'])) { $s3->abortMultipartUpload([ 'Bucket' => $job_object->job['s3bucket'], 'UploadId' => $job_object->steps_data[$job_object->step_working]['uploadId'], 'Key' => $job_object->job['s3dir'] . $job_object->backup_file, ]); } unset($job_object->steps_data[$job_object->step_working]['UploadId'], $job_object->steps_data[$job_object->step_working]['Parts'], $job_object->steps_data[$job_object->step_working]['Part']); $job_object->substeps_done = 0; if (is_resource($file_handle)) { fclose($file_handle); } return false; } fclose($file_handle); } $result = $s3->headObject([ 'Bucket' => $job_object->job['s3bucket'], 'Key' => $job_object->job['s3dir'] . $job_object->backup_file, ]); if ($result->get('ContentLength') == filesize($job_object->backup_folder . $job_object->backup_file)) { $job_object->substeps_done = 1 + $job_object->backup_filesize; $job_object->log( sprintf( __('Backup transferred to %s.', 'backwpup'), $s3->getObjectUrl($job_object->job['s3bucket'], $job_object->job['s3dir'] . $job_object->backup_file) ) ); if (!empty($job_object->job['jobid'])) { BackWPup_Option::update( $job_object->job['jobid'], 'lastbackupdownloadurl', network_admin_url('admin.php') . '?page=backwpupbackups&action=downloads3&file=' . $job_object->job['s3dir'] . $job_object->backup_file . '&jobid=' . $job_object->job['jobid'] ); } } else { $job_object->log( sprintf( __('Cannot transfer backup to S3! (%1$d) %2$s', 'backwpup'), $result->get('status'), $result->get('Message') ), E_USER_ERROR ); } } catch (Exception $e) { $errorMessage = $e->getMessage(); if ($e instanceof AwsException) { $errorMessage = $e->getAwsErrorMessage(); } $job_object->log( E_USER_ERROR, sprintf(__('S3 Service API: %s', 'backwpup'), $errorMessage), $e->getFile(), $e->getLine() ); return false; } try { $this->file_update_list($job_object, true); } catch (Exception $e) { $errorMessage = $e->getMessage(); if ($e instanceof AwsException) { $errorMessage = $e->getAwsErrorMessage(); } $job_object->log( E_USER_ERROR, sprintf(__('S3 Service API: %s', 'backwpup'), $errorMessage), $e->getFile(), $e->getLine() ); return false; } $job_object->substeps_done = 2 + $job_object->backup_filesize; return true; } public function can_run(array $job_settings): bool { if (empty($job_settings['s3accesskey'])) { return false; } return !(empty($job_settings['s3secretkey'])); } public function edit_inline_js(): void { ?> <script type="text/javascript"> jQuery( document ).ready( function ( $ ) { function awsgetbucket() { var data = { action : 'backwpup_dest_s3', s3accesskey : $( 'input[name="s3accesskey"]' ).val(), s3secretkey : $( 'input[name="s3secretkey"]' ).val(), s3bucketselected: $( 'input[name="s3bucketselected"]' ).val(), s3base_url : $( 'input[name="s3base_url"]' ).val(), s3region : $( '#s3region' ).val(), s3base_region : $( 'input[name="s3base_region"]' ).val(), s3base_version : $( 'input[name="s3base_version"]' ).val(), s3base_signature : $( 'input[name="s3base_signature"]' ).val(), s3base_multipart : $( 'input[name="s3base_multipart"]' ).is(':checked'), s3base_pathstylebucket : $( 'input[name="s3base_pathstylebucket"]' ).is(':checked'), _ajax_nonce : $( '#backwpupajaxnonce' ).val() }; $.post( ajaxurl, data, function ( response ) { $( '#s3bucketerror' ).remove(); $( '#s3bucket' ).remove(); $( '#s3bucketselected' ).after( response ); } ); } $( 'select[name="s3region"]' ).change( function () { awsgetbucket(); } ); $( 'input[name="s3accesskey"], input[name="s3secretkey"], input[name="s3base_url"]' ).backwpupDelayKeyup( function () { awsgetbucket(); } ); } ); </script> <?php } }