Esempio n. 1
0
 function send_remote_destination($destination_id, $delete_after = false)
 {
     pb_backupbuddy::status('details', 'Sending file to remote destination ID: `' . $destination_id . '`. Delete after: `' . $delete_after . '`.');
     $response = backupbuddy_core::send_remote_destination($destination_id, $this->_backup['archive_file'], '', false, $delete_after);
     if (false === $response) {
         // Send failure.
         $error_message = 'BackupBuddy failed sending a backup to the remote destination "' . pb_backupbuddy::$options['remote_destinations'][$destination_id]['title'] . '" (id: ' . $destination_id . '). Please verify and test destination settings and permissions. Check the error log for further details.';
         pb_backupbuddy::status('error', 'Failure sending to remote destination. Details: ' . $error_message);
         backupbuddy_core::mail_error($error_message);
     }
 }
Esempio n. 2
0
 public static function archiveLimit($settings, $backup_type)
 {
     if ($backup_type == 'full') {
         $limit = $settings['full_archive_limit'];
         pb_backupbuddy::status('details', 'Full backup archive limit of `' . $limit . '` of type `full` based on destination settings.');
     } elseif ($backup_type == 'db') {
         $limit = $settings['db_archive_limit'];
         pb_backupbuddy::status('details', 'Database backup archive limit of `' . $limit . '` of type `db` based on destination settings.');
     } elseif ($backup_type == 'files') {
         $limit = $settings['files_archive_limit'];
         pb_backupbuddy::status('details', 'Database backup archive limit of `' . $limit . '` of type `files` based on destination settings.');
     } else {
         $limit = 0;
         pb_backupbuddy::status('warning', 'Warning #237332. Unable to determine backup type (reported: `' . $backup_type . '`) so archive limits NOT enforced for this backup.');
     }
     if ($limit > 0) {
         pb_backupbuddy::status('details', 'Archive limit enforcement beginning.');
         // Get file listing.
         try {
             $response_manage = self::$_client->listObjects(array('Bucket' => $settings['bucket'], 'Prefix' => $settings['directory'] . 'backup-' . backupbuddy_core::backup_prefix()));
             // List all users files in this directory that are a backup for this site (limited by prefix).
         } catch (Exception $e) {
             return self::_error('Error #9338292: Unable to list files for archive limiting. Details: `' . $e->getMessage() . '`.');
         }
         if (!is_array($response_manage['Contents'])) {
             $response_manage['Contents'] = array();
         }
         // List backups associated with this site by date.
         $backups = array();
         foreach ($response_manage['Contents'] as $object) {
             $file = str_replace($settings['directory'], '', $object['Key']);
             if ($backup_type != backupbuddy_core::getBackupTypeFromFile($file, $quiet = true)) {
                 continue;
                 // Not of the same backup type.
             }
             $backups[$file] = strtotime($object['LastModified']);
         }
         arsort($backups);
         pb_backupbuddy::status('details', 'Found `' . count($backups) . '` backups of this type when checking archive limits out of `' . count($response_manage['Contents']) . '` total files in this location.');
         if (count($backups) > $limit) {
             pb_backupbuddy::status('details', 'More archives (' . count($backups) . ') than limit (' . $limit . ') allows. Trimming...');
             $i = 0;
             $delete_fail_count = 0;
             foreach ($backups as $buname => $butime) {
                 $i++;
                 if ($i > $limit) {
                     pb_backupbuddy::status('details', 'Trimming excess file `' . $buname . '`...');
                     try {
                         $response = self::$_client->deleteObject(array('Bucket' => $settings['bucket'], 'Key' => $settings['directory'] . $buname));
                     } catch (Exception $e) {
                         self::_error('Unable to delete excess Stash file `' . $buname . '`. Details: `' . $e->getMessage() . '`.');
                         $delete_fail_count++;
                     }
                 }
             }
             // end foreach.
             pb_backupbuddy::status('details', 'Finished trimming excess backups.');
             if ($delete_fail_count !== 0) {
                 $error_message = 'Stash remote limit could not delete ' . $delete_fail_count . ' backups.';
                 pb_backupbuddy::status('error', $error_message);
                 backupbuddy_core::mail_error($error_message);
             }
         }
         pb_backupbuddy::status('details', 'Stash completed archive limiting.');
     } else {
         pb_backupbuddy::status('details', 'No Stash archive file limit to enforce.');
     }
     // End remote backup limit
     return true;
 }
$temp_directory = backupbuddy_core::getBackupDirectory() . 'temp_zip_*';
$files = glob($temp_directory . '*');
if (is_array($files) && !empty($files)) {
    // For robustness. Without open_basedir the glob() function returns an empty array for no match. With open_basedir in effect the glob() function returns a boolean false for no match.
    foreach ($files as $file) {
        if (strpos($file, 'index.') !== false || strpos($file, '.htaccess') !== false) {
            // Index file or htaccess dont get deleted so go to next file.
            continue;
        }
        $file_stats = stat($file);
        if (time() - $file_stats['mtime'] > $backup_age_limit) {
            // If older than 12 hours, delete the log.
            if (@pb_backupbuddy::$filesystem->unlink_recursive($file) === false) {
                $message = 'BackupBuddy was unable to clean up (delete) temporary directory/file: `' . $file . '`. You should manually delete it and/or verify proper file permissions to allow BackupBuddy to clean up for you.';
                pb_backupbuddy::status('error', $message);
                backupbuddy_core::mail_error($message);
            }
        }
    }
}
// Cleanup remote S3 multipart chunking.
foreach (pb_backupbuddy::$options['remote_destinations'] as $destination) {
    if ($destination['type'] != 's3') {
        continue;
    }
    if (isset($destination['max_chunk_size']) && $destination['max_chunk_size'] == '0') {
        continue;
    }
    pb_backupbuddy::status('details', 'Found S3 Multipart Chunking Destinations to cleanup.');
    require_once pb_backupbuddy::plugin_path() . '/destinations/bootstrap.php';
    $cleanup_result = pb_backupbuddy_destinations::multipart_cleanup($destination);
Esempio n. 4
0
 public static function remove_temp_zip_dirs($backup_age_limit = 172800)
 {
     // Remove any old temporary zip directories: wp-content/uploads/backupbuddy_backups/temp_zip_XXXX/. Logs any directories it cannot delete.
     pb_backupbuddy::status('details', 'Cleaning up any old temporary zip directories in backup directory temp location `' . backupbuddy_core::getBackupDirectory() . 'temp_zip_XXXX/`.');
     $temp_directory = backupbuddy_core::getBackupDirectory() . 'temp_zip_*';
     $files = glob($temp_directory . '*');
     if (is_array($files) && !empty($files)) {
         // For robustness. Without open_basedir the glob() function returns an empty array for no match. With open_basedir in effect the glob() function returns a boolean false for no match.
         foreach ($files as $file) {
             if (strpos($file, 'index.') !== false || strpos($file, '.htaccess') !== false) {
                 // Index file or htaccess dont get deleted so go to next file.
                 continue;
             }
             $file_stats = stat($file);
             if (time() - $file_stats['mtime'] > $backup_age_limit) {
                 // If older than 12 hours, delete the log.
                 if (@pb_backupbuddy::$filesystem->unlink_recursive($file) === false) {
                     $message = 'BackupBuddy was unable to clean up (delete) temporary directory/file: `' . $file . '`. You should manually delete it and/or verify proper file permissions to allow BackupBuddy to clean up for you.';
                     pb_backupbuddy::status('error', $message);
                     backupbuddy_core::mail_error($message);
                 }
             }
         }
     }
 }
Esempio n. 5
0
 function email_error_test()
 {
     $email = pb_backupbuddy::_POST('email');
     if ($email == '') {
         die('You must supply an Error email address to send test message to.');
     }
     backupbuddy_core::mail_error('THIS IS ONLY A TEST. This is a test of the Error Notification email.', $email);
     die('1');
 }
Esempio n. 6
0
 function process_dropbox_copy($destination_id, $file)
 {
     pb_backupbuddy::set_greedy_script_limits();
     if (!class_exists('backupbuddy_core')) {
         require_once pb_backupbuddy::plugin_path() . '/classes/core.php';
     }
     require_once pb_backupbuddy::plugin_path() . '/destinations/dropbox/lib/dropbuddy/dropbuddy.php';
     $dropbuddy = new pb_backupbuddy_dropbuddy(pb_backupbuddy::$options['remote_destinations'][$destination_id]['token']);
     if ($dropbuddy->authenticate() !== true) {
         if (!class_exists('backupbuddy_core')) {
             require_once pb_backupbuddy::plugin_path() . '/classes/core.php';
         }
         backupbuddy_core::mail_error('Dropbox authentication failed in cron_process_dropbox_copy.');
         return false;
     }
     $destination_file = backupbuddy_core::getBackupDirectory() . basename($file);
     if (file_exists($destination_file)) {
         $destination_file = str_replace('backup-', 'backup_copy_' . pb_backupbuddy::random_string(5) . '-', $destination_file);
     }
     pb_backupbuddy::status('error', 'About to get file `' . $file . '` from Dropbox and save to `' . $destination_file . '`.');
     file_put_contents($destination_file, $dropbuddy->get_file($file));
     pb_backupbuddy::status('error', 'Got object from Dropbox cron.');
 }
Esempio n. 7
0
 public static function send($settings = array(), $files = array(), $send_id = '')
 {
     $limit = $settings['archive_limit'];
     $path = $settings['path'];
     if (!file_exists($settings['path'])) {
         pb_backupbuddy::$filesystem->mkdir($settings['path']);
     }
     $total_transfer_time = 0;
     $total_transfer_size = 0;
     foreach ($files as $file) {
         pb_backupbuddy::status('details', 'Starting send to `' . $path . '`.');
         $filesize = filesize($file);
         $total_transfer_size += $filesize;
         $send_time = -microtime(true);
         if (true !== @copy($file, $path . '/' . basename($file))) {
             pb_backupbuddy::status('error', 'Unable to copy file `' . $file . '` of size `' . pb_backupbuddy::$format->file_size($filesize) . '` to local path `' . $path . '`. Please verify the directory exists and permissions permit writing.');
             backupbuddy_core::mail_error($error_message);
             return false;
         } else {
             pb_backupbuddy::status('details', 'Send success.');
         }
         $send_time += microtime(true);
         $total_transfer_time += $send_time;
         // Start remote backup limit
         if ($limit > 0) {
             pb_backupbuddy::status('details', 'Archive limit of `' . $limit . '` in settings.');
             pb_backupbuddy::status('details', 'path: ' . $path . '*.zip');
             $remote_files = glob($path . '/*.zip');
             if (!is_array($remote_files)) {
                 $remote_files = array();
             }
             usort($remote_files, create_function('$a,$b', 'return filemtime($a) - filemtime($b);'));
             pb_backupbuddy::status('details', 'Found `' . count($remote_files) . '` backups.');
             // Create array of backups and organize by date
             $bkupprefix = backupbuddy_core::backup_prefix();
             foreach ($remote_files as $file_key => $remote_file) {
                 if (false === stripos($remote_file, 'backup-' . $bkupprefix . '-')) {
                     pb_backupbuddy::status('details', 'backup-' . $bkupprefix . '-' . 'not in file: ' . $remote_file);
                     unset($backups[$file_key]);
                 }
             }
             arsort($remote_files);
             pb_backupbuddy::status('details', 'Found `' . count($remote_files) . '` backups.');
             if (count($remote_files) > $limit) {
                 pb_backupbuddy::status('details', 'More archives (' . count($remote_files) . ') than limit (' . $limit . ') allows. Trimming...');
                 $i = 0;
                 $delete_fail_count = 0;
                 foreach ($remote_files as $remote_file) {
                     $i++;
                     if ($i > $limit) {
                         pb_backupbuddy::status('details', 'Trimming excess file `' . $remote_file . '`...');
                         if (!unlink($remote_file)) {
                             pb_backupbuddy::status('details', 'Unable to delete excess local file `' . $remote_file . '`.');
                             $delete_fail_count++;
                         }
                     }
                 }
                 pb_backupbuddy::status('details', 'Finished trimming excess backups.');
                 if ($delete_fail_count !== 0) {
                     $error_message = 'Local remote limit could not delete ' . $delete_fail_count . ' backups.';
                     pb_backupbuddy::status('error', $error_message);
                     backupbuddy_core::mail_error($error_message);
                 }
             }
         } else {
             pb_backupbuddy::status('details', 'No local destination file limit to enforce.');
         }
         // End remote backup limit
     }
     // end foreach.
     // Load fileoptions to the send.
     pb_backupbuddy::status('details', 'About to load fileoptions data.');
     require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
     pb_backupbuddy::status('details', 'Fileoptions instance #11.');
     $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
     if (true !== ($result = $fileoptions_obj->is_ok())) {
         pb_backupbuddy::status('error', __('Fatal Error #9034.2344848. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
         return false;
     }
     pb_backupbuddy::status('details', 'Fileoptions data loaded.');
     $fileoptions =& $fileoptions_obj->options;
     $fileoptions['write_speed'] = $total_transfer_time / $total_transfer_size;
     return true;
 }
 function send_remote_destination($destination_id, $delete_after = false)
 {
     pb_backupbuddy::status('details', 'Sending file to remote destination ID: `' . $destination_id . '`. Delete after: `' . $delete_after . '`.');
     pb_backupbuddy::status('details', 'IMPORTANT: If the transfer is set to be chunked then only the first chunk status will be displayed during this process. Subsequent chunks will happen after this has finished.');
     $response = backupbuddy_core::send_remote_destination($destination_id, $this->_backup['archive_file'], '', false, $delete_after);
     if (false === $response) {
         // Send failure.
         $error_message = 'BackupBuddy failed sending a backup to the remote destination "' . pb_backupbuddy::$options['remote_destinations'][$destination_id]['title'] . '" (id: ' . $destination_id . '). Please verify and test destination settings and permissions. Check the error log for further details.';
         pb_backupbuddy::status('error', 'Failure sending to remote destination. Details: ' . $error_message);
         backupbuddy_core::mail_error($error_message);
     }
 }
Esempio n. 9
0
 public static function send($destination_settings, $file, $send_id = '', $delete_after = false)
 {
     if (is_array($file)) {
         // As of v6.1.0.1 no longer accepting multiple files to send.
         $file = $file[0];
     }
     if ('' != $send_id) {
         pb_backupbuddy::add_status_serial('remote_send-' . $send_id);
         pb_backupbuddy::status('details', '----- Initiating master send function for BackupBuddy v' . pb_backupbuddy::settings('version') . '. Post-send deletion: ' . $delete_after);
         require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
         $fileoptions_file = backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt';
         if (!file_exists($fileoptions_file)) {
             //pb_backupbuddy::status( 'details', 'Fileoptions file `' . $fileoptions_file . '` does not exist yet; creating.' );
             //pb_backupbuddy::status( 'details', 'Fileoptions instance #19.' );
             $fileoptions_obj = new pb_backupbuddy_fileoptions($fileoptions_file, $read_only = false, $ignore_lock = true, $create_file = true);
         } else {
             //pb_backupbuddy::status( 'details', 'Fileoptions file exists; loading.' );
             //pb_backupbuddy::status( 'details', 'Fileoptions instance #18.' );
             $fileoptions_obj = new pb_backupbuddy_fileoptions($fileoptions_file, $read_only = false, $ignore_lock = false, $create_file = false);
         }
         if (true !== ($result = $fileoptions_obj->is_ok())) {
             pb_backupbuddy::status('error', __('Fatal Error #9034.2344848. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
             return false;
         }
         //pb_backupbuddy::status( 'details', 'Fileoptions data loaded.' );
         $fileoptions =& $fileoptions_obj->options;
         if ('' == $fileoptions) {
             // Set defaults.
             $fileoptions = backupbuddy_core::get_remote_send_defaults();
             $fileoptions['type'] = $destination_settings['type'];
             $fileoptions['file'] = $file;
             $fileoptions['retries'] = 0;
         }
         $fileoptions['sendID'] = $send_id;
         $fileoptions['destinationSettings'] = $destination_settings;
         // always store the LATEST settings for resume info and retry function.
         $fileoptions['update_time'] = time();
         $fileoptions['deleteAfter'] = $delete_after;
         $fileoptions_obj->save();
         if (isset($fileoptions['status']) && 'aborted' == $fileoptions['status']) {
             pb_backupbuddy::status('warning', 'Destination send triggered on an ABORTED transfer. Ending send function.');
             return false;
         }
         unset($fileoptions_obj);
     }
     if (false === ($destination = self::_init_destination($destination_settings))) {
         echo '{Error #546893498a. Destination configuration file missing.}';
         if ('' != $send_id) {
             pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
         }
         return false;
     }
     $destination_settings = $destination['settings'];
     // Settings with defaults applied, normalized, etc.
     if (!file_exists($file)) {
         pb_backupbuddy::status('error', 'Error #58459458743. The file that was attempted to be sent to a remote destination, `' . $file . '`, was not found. It either does not exist or permissions prevent accessing it. Check that local backup limits are not causing it to be deleted.');
         if ('' != $send_id) {
             pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
         }
         return false;
     }
     if (!method_exists($destination['class'], 'send')) {
         pb_backupbuddy::status('error', 'Destination class `' . $destination['class'] . '` does not support send operation -- missing function.');
         if ('' != $send_id) {
             pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
         }
         return false;
     }
     global $pb_backupbuddy_destination_errors;
     $pb_backupbuddy_destination_errors = array();
     $result = call_user_func_array("{$destination['class']}::send", array($destination_settings, $file, $send_id, $delete_after));
     /* $result values:
      *		false		Transfer FAILED.
      *		true		Non-chunked transfer succeeded.
      *		array()		array(
      *						multipart_id,				// Unique string ID for multipart send. Empty string if last chunk finished sending successfully.
      *						multipart_status_message
      *					)
      */
     if ($result === false) {
         $error_details = implode('; ', $pb_backupbuddy_destination_errors);
         if ('' != $error_details) {
             $error_details = ' Details: ' . $error_details;
         }
         $log_directory = backupbuddy_core::getLogDirectory();
         $preError = 'There was an error sending to the remote destination titled `' . $destination_settings['title'] . '` of type `' . backupbuddy_core::pretty_destination_type($destination_settings['type']) . '`. One or more files may have not been fully transferred. Please see error details for additional information. If the error persists, enable full error logging and try again for full details and troubleshooting. Details: ' . "\n\n";
         $logFile = $log_directory . 'status-remote_send-' . $send_id . '_' . pb_backupbuddy::$options['log_serial'] . '.txt';
         pb_backupbuddy::status('details', 'Looking for remote send log file to send in error email: `' . $logFile . '`.');
         if (!file_exists($logFile)) {
             pb_backupbuddy::status('details', 'Remote send log file not found.');
             backupbuddy_core::mail_error($preError . $error_details);
         } else {
             // Log exists. Attach.
             pb_backupbuddy::status('details', 'Remote send log file found. Attaching to error email.');
             backupbuddy_core::mail_error($preError . $error_details . "\n\nSee the attached log for details.", '', array($logFile));
         }
         // Save error details into fileoptions for this send.
         //pb_backupbuddy::status( 'details', 'About to load fileoptions data.' );
         require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
         pb_backupbuddy::status('details', 'Fileoptions instance #45.');
         $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
         if (true !== ($fileoptions_result = $fileoptions_obj->is_ok())) {
             pb_backupbuddy::status('error', __('Error #9034.32731. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $fileoptions_result);
         }
         //pb_backupbuddy::status( 'details', 'Fileoptions data loaded.' );
         $fileoptions =& $fileoptions_obj->options;
         $fileoptions['status'] = 'failed';
         $fileoptions['error'] = 'Error sending.' . $error_details;
         $fileoptions['updated_time'] = time();
         $fileoptions_obj->save();
         unset($fileoptions_obj);
     }
     if (is_array($result)) {
         // Send is multipart.
         pb_backupbuddy::status('details', 'Multipart chunk mode completed a pass of the send function. Resuming will be needed. Result: `' . print_r($result, true) . '`.');
         if ('' != $send_id) {
             //pb_backupbuddy::status( 'details', 'About to load fileoptions data.' );
             require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
             //pb_backupbuddy::status( 'details', 'Fileoptions instance #17.' );
             $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
             if (true !== ($fileoptions_result = $fileoptions_obj->is_ok())) {
                 pb_backupbuddy::status('error', __('Fatal Error #9034.387462. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $fileoptions_result);
                 return false;
             }
             //pb_backupbuddy::status( 'details', 'Fileoptions data loaded.' );
             $fileoptions =& $fileoptions_obj->options;
             $fileoptions['_multipart_status'] = $result[1];
             $fileoptions['updated_time'] = time();
             pb_backupbuddy::status('details', 'Destination debugging details: `' . print_r($fileoptions, true) . '`.');
             $fileoptions_obj->save();
             unset($fileoptions_obj);
             pb_backupbuddy::status('details', 'Next multipart chunk will be processed shortly. Now waiting on its cron...');
         }
     } else {
         // Single all-at-once send.
         if (false === $result) {
             pb_backupbuddy::status('details', 'Completed send function. Failure. Post-send deletion will be skipped if enabled.');
         } elseif (true === $result) {
             pb_backupbuddy::status('details', 'Completed send function. Success.');
         } else {
             pb_backupbuddy::status('warning', 'Completed send function. Unknown result: `' . $result . '`.');
         }
         pb_backupbuddy::status('details', 'About to load fileoptions data.');
         require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
         pb_backupbuddy::status('details', 'Fileoptions instance #16.');
         $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
         if (true !== ($fileoptions_result = $fileoptions_obj->is_ok())) {
             pb_backupbuddy::status('error', __('Error #9034.387462. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $fileoptions_result);
         }
         pb_backupbuddy::status('details', 'Fileoptions data loaded.');
         $fileoptions =& $fileoptions_obj->options;
         $fileoptions['updated_time'] = time();
         unset($fileoptions_obj);
     }
     // File transfer completely finished successfully.
     if (true === $result) {
         $fileSize = filesize($file);
         $serial = backupbuddy_core::get_serial_from_file($file);
         // Handle deletion of send file if enabled.
         if (true === $delete_after && false !== $result) {
             pb_backupbuddy::status('details', __('Post-send deletion enabled.', 'it-l10n-backupbuddy'));
             if (false === $result) {
                 pb_backupbuddy::status('details', 'Skipping post-send deletion since transfer failed.');
             } else {
                 pb_backupbuddy::status('details', 'Performing post-send deletion since transfer succeeded.');
                 pb_backupbuddy::status('details', 'Deleting local file `' . $file . '`.');
                 // Handle post-send deletion on success.
                 if (file_exists($file)) {
                     $unlink_result = @unlink($file);
                     if (true !== $unlink_result) {
                         pb_backupbuddy::status('error', 'Unable to unlink local file `' . $file . '`.');
                     }
                 }
                 if (file_exists($file)) {
                     // File still exists.
                     pb_backupbuddy::status('details', __('Error. Unable to delete local file `' . $file . '` after send as set in settings.', 'it-l10n-backupbuddy'));
                     backupbuddy_core::mail_error('BackupBuddy was unable to delete local file `' . $file . '` after successful remove transfer though post-remote send deletion is enabled. You may want to delete it manually. This can be caused by permission problems or improper server configuration.');
                 } else {
                     // Deleted.
                     pb_backupbuddy::status('details', __('Deleted local archive after successful remote destination send based on settings.', 'it-l10n-backupbuddy'));
                     pb_backupbuddy::status('archiveDeleted', '');
                 }
             }
         } else {
             pb_backupbuddy::status('details', 'Post-send deletion not enabled.');
         }
         // Send email notification if enabled.
         if ('' != pb_backupbuddy::$options['email_notify_send_finish']) {
             pb_backupbuddy::status('details', __('Sending finished destination send email notification.', 'it-l10n-backupbuddy'));
             $extraReplacements = array();
             $extraReplacements = array('{backup_file}' => $file, '{backup_size}' => $fileSize, '{backup_serial}' => $serial);
             backupbuddy_core::mail_notify_scheduled($serial, 'destinationComplete', __('Destination send complete to', 'it-l10n-backupbuddy') . ' ' . backupbuddy_core::pretty_destination_type($destination_settings['type']), $extraReplacements);
         } else {
             pb_backupbuddy::status('details', __('Finished sending email NOT enabled. Skipping.', 'it-l10n-backupbuddy'));
         }
         // Save notification of final results.
         $data = array();
         $data['serial'] = $serial;
         $data['file'] = $file;
         $data['size'] = $fileSize;
         $data['pretty_size'] = pb_backupbuddy::$format->file_size($fileSize);
         backupbuddy_core::addNotification('remote_send_success', 'Remote file transfer completed', 'A file has successfully completed sending to a remote location.', $data);
     }
     // NOTE: Call this before removing status serial so it shows in log.
     pb_backupbuddy::status('details', 'Ending send() function pass.');
     // Return logging to normal file.
     if ('' != $send_id) {
         pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
     }
     return $result;
 }
Esempio n. 10
0
 public static function send($settings = array(), $file, $send_id = '', $delete_after = false)
 {
     $settings = self::_init($settings);
     // Handles formatting & sanitizing settings.
     // Process multipart transfer that we already initiated in a previous runthrough.
     if ($settings['_multipart_id'] != '') {
         // Multipart upload initiated and needs parts sent.
         $backup_type = str_replace('/', '', $settings['_multipart_backup_type']);
         // For use later by file limiting.
         $backup_size = $settings['_multipart_backup_size'];
         $this_part_number = $settings['_multipart_partnumber'] + 1;
         // Open file for streaming.
         $f = @fopen($settings['_multipart_file'], 'rb');
         if (false === $f) {
             return self::_error('Error #437734. Unable to open file `' . $settings['_multipart_file'] . '` to send. Did it get deleted?');
         }
         if (-1 == @fseek($f, (int) $settings['_multipart_counts'][$settings['_multipart_partnumber']]['seekTo'])) {
             return self::_error('Error #833838: Unable to fseek file.');
         }
         $sendStart = time(true);
         pb_backupbuddy::status('details', 'Beginning upload of part `' . $this_part_number . '` of `' . count($settings['_multipart_counts']) . '` parts of file `' . $settings['_multipart_file'] . '` to remote location `' . $settings['_multipart_remotefile'] . '` with multipart ID `' . $settings['_multipart_id'] . '`.');
         try {
             $response = self::$_client->uploadPart(array('Bucket' => $settings['bucket'], 'Key' => $settings['_multipart_remotefile'], 'UploadId' => $settings['_multipart_id'], 'PartNumber' => $this_part_number, 'ContentLength' => (int) $settings['_multipart_counts'][$settings['_multipart_partnumber']]['length'], 'Body' => $f));
         } catch (Exception $e) {
             @fclose($f);
             return self::_error('Unable to upload file part for multipart upload `' . $settings['_multipart_id'] . '`. Details: `' . $e->getMessage() . '`.');
         }
         @fclose($f);
         pb_backupbuddy::status('details', 'Success sending chunk. Upload details: `' . print_r($response, true) . '`.');
         $uploaded_size = $backup_size;
         $uploaded_speed = time(true) - $sendStart;
         pb_backupbuddy::status('details', 'Uploaded size: ' . pb_backupbuddy::$format->file_size($uploaded_size) . ', Speed: ' . pb_backupbuddy::$format->file_size($uploaded_speed) . '/sec.');
         // Load fileoptions to the send.
         pb_backupbuddy::status('details', 'About to load fileoptions data.');
         require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
         pb_backupbuddy::status('details', 'Fileoptions instance #10.');
         $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
         if (true !== ($result = $fileoptions_obj->is_ok())) {
             return self::_error(__('Fatal Error #9034.2344848. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
         }
         pb_backupbuddy::status('details', 'Fileoptions data loaded.');
         $fileoptions =& $fileoptions_obj->options;
         $update_status = 'Sent part ' . $this_part_number . ' of ' . count($settings['_multipart_counts']) . '.';
         // Made it here so success sending part. Increment for next part to send.
         $settings['_multipart_partnumber']++;
         if (!isset($settings['_multipart_counts'][$settings['_multipart_partnumber']])) {
             // No more parts exist for this file. Tell S3 the multipart upload is complete and move on.
             pb_backupbuddy::status('details', 'S3 getting parts with etags to notify S3 of completed multipart send.');
             try {
                 $response = self::$_client->listParts(array('Bucket' => $settings['bucket'], 'UploadId' => $settings['_multipart_id'], 'Key' => $settings['_multipart_remotefile']));
                 $etag_parts = $etag_parts->Parts;
             } catch (Exception $e) {
                 return self::_error('Error #8332893: Unable to list parts on server. Details: `' . $e->getMessage() . '`.');
             }
             pb_backupbuddy::status('details', 'Got parts list. Details: ' . print_r($etag_parts, true));
             pb_backupbuddy::status('details', 'Notifying server of multipart upload completion.');
             try {
                 $response = self::$_client->completeMultipartUpload(array('Bucket' => $settings['bucket'], 'UploadId' => $settings['_multipart_id'], 'Key' => $settings['_multipart_remotefile'], 'Parts' => $etag_parts));
             } catch (Exception $e) {
                 return self::_error('Unable to notify server of completion of all parts for multipart upload `' . $settings['_multipart_id'] . '`. Details: `' . $e->getMessage() . '`.');
             }
             pb_backupbuddy::status('details', 'Server notified of multipart completion.');
             pb_backupbuddy::status('details', 'No more parts left for this multipart upload. Clearing multipart instance variables.');
             $settings['_multipart_partnumber'] = 0;
             $settings['_multipart_id'] = '';
             $settings['_multipart_file'] = '';
             $settings['_multipart_remotefile'] = '';
             // Multipart completed so safe to prevent housekeeping of incomplete multipart uploads.
             $settings['_multipart_transferspeeds'][] = $uploaded_speed;
             // Overall upload speed average.
             $uploaded_speed = array_sum($settings['_multipart_transferspeeds']) / count($settings['_multipart_counts']);
             pb_backupbuddy::status('details', 'Upload speed average of all chunks: `' . pb_backupbuddy::$format->file_size($uploaded_speed) . '`.');
             $settings['_multipart_counts'] = array();
             // Update stats.
             $fileoptions['_multipart_status'] = $update_status;
             $fileoptions['finish_time'] = time();
             $fileoptions['status'] = 'success';
             if (isset($uploaded_speed)) {
                 $fileoptions['write_speed'] = $uploaded_speed;
             }
             $fileoptions_obj->save();
             unset($fileoptions);
         }
         // Schedule to continue if anything is left to upload for this multipart of any individual files.
         if ($settings['_multipart_id'] != '') {
             pb_backupbuddy::status('details', 'S3 multipart upload has more parts left. Scheduling next part send.');
             $cronTime = time();
             $cronArgs = array($settings, $file, $send_id, $delete_after);
             $cronHashID = md5($cronTime . serialize($cronArgs));
             $cronArgs[] = $cronHashID;
             $schedule_result = backupbuddy_core::schedule_single_event($cronTime, pb_backupbuddy::cron_tag('destination_send'), $cronArgs);
             if (true === $schedule_result) {
                 pb_backupbuddy::status('details', 'Next S3 chunk step cron event scheduled.');
             } else {
                 pb_backupbuddy::status('error', 'Next S3 chunk step cron even FAILED to be scheduled.');
             }
             spawn_cron(time() + 150);
             // Adds > 60 seconds to get around once per minute cron running limit.
             update_option('_transient_doing_cron', 0);
             // Prevent cron-blocking for next item.
             return array($settings['_multipart_id'], 'Sent part ' . $this_part_number . ' of ' . count($settings['_multipart_counts']) . ' parts.');
         }
     } else {
         // not multipart continuation
         // Handle chunking of file into a multipart upload (if applicable).
         $file_size = filesize($file);
         if ($settings['max_chunk_size'] >= self::MINIMUM_CHUNK_SIZE && $file_size / 1024 / 1024 > $settings['max_chunk_size']) {
             // minimum chunk size is 5mb. Anything under 5mb we will not chunk.
             pb_backupbuddy::status('details', 'File size of ' . pb_backupbuddy::$format->file_size($file_size) . ' exceeds max chunk size of ' . $settings['max_chunk_size'] . 'MB set in settings for sending file as multipart upload.');
             // About to chunk so cleanup any previous hanging multipart transfers.
             self::multipart_cleanup($settings, $lessLogs = false);
             // Initiate multipart upload with S3.
             pb_backupbuddy::status('details', 'Initiating multipart transfer.');
             try {
                 $response = self::$_client->createMultipartUpload(array('Bucket' => $settings['bucket'], 'Key' => $settings['directory'] . basename($file), 'StorageClass' => $settings['storage'], 'ServerSideEncryption' => 'AES256'));
             } catch (Exception $e) {
                 return self::_error('Error #389383: Unable to initiate multipart upload. Details: `' . $e->getMessage() . '`.');
             }
             // Made it here so SUCCESS initiating multipart!
             $upload_id = (string) $response['UploadId'];
             pb_backupbuddy::status('details', 'Initiated multipart upload with ID `' . $upload_id . '`.');
             $backup_type = backupbuddy_core::getBackupTypeFromFile($file);
             // Calculate multipart settings.
             $multipart_destination_settings = $settings;
             $multipart_destination_settings['_multipart_id'] = $upload_id;
             $multipart_destination_settings['_multipart_partnumber'] = 0;
             $multipart_destination_settings['_multipart_file'] = $file;
             $multipart_destination_settings['_multipart_remotefile'] = $settings['directory'] . basename($file);
             $multipart_destination_settings['_multipart_counts'] = self::_get_multipart_counts($file_size, $settings['max_chunk_size'] * 1024 * 1024);
             // Size of chunks expected to be in bytes.
             $multipart_destination_settings['_multipart_backup_type'] = $backup_type;
             $multipart_destination_settings['_multipart_backup_size'] = $file_size;
             pb_backupbuddy::status('details', 'Multipart settings to pass:'******'details', 'Scheduling send of next part.');
             $cronTime = time();
             $cronArgs = array($multipart_destination_settings, $file, $send_id, $delete_after);
             $cronHashID = md5($cronTime . serialize($cronArgs));
             $cronArgs[] = $cronHashID;
             backupbuddy_core::schedule_single_event($cronTime, pb_backupbuddy::cron_tag('destination_send'), $cronArgs);
             spawn_cron(time() + 150);
             // Adds > 60 seconds to get around once per minute cron running limit.
             update_option('_transient_doing_cron', 0);
             // Prevent cron-blocking for next item.
             pb_backupbuddy::status('details', 'Scheduled send of next part(s). Done for this cycle.');
             return array($upload_id, 'Starting send of ' . count($multipart_destination_settings['_multipart_counts']) . ' parts.');
         } else {
             // did not meet chunking criteria.
             if ($settings['max_chunk_size'] != '0') {
                 if ($file_size / 1024 / 1024 > self::MINIMUM_CHUNK_SIZE) {
                     pb_backupbuddy::status('details', 'File size of ' . pb_backupbuddy::$format->file_size($file_size) . ' is less than the max chunk size of ' . $settings['max_chunk_size'] . 'MB; not chunking into multipart upload.');
                 } else {
                     pb_backupbuddy::status('details', 'File size of ' . pb_backupbuddy::$format->file_size($file_size) . ' is less than the minimum allowed chunk size of ' . self::MINIMUM_CHUNK_SIZE . 'MB; not chunking into multipart upload.');
                 }
             } else {
                 pb_backupbuddy::status('details', 'Max chunk size set to zero so not chunking into multipart upload.');
             }
             // Open file for streaming.
             $f = @fopen($file, 'rb');
             if (false === $f) {
                 return self::_error('Error #2379327. Unable to open file `' . $file . '` to send. Did it get deleted?');
             }
             // Initiate SINGLE PART upload.
             $startSend = time(true);
             pb_backupbuddy::status('details', 'Initiating non-chunked transfer.');
             try {
                 $response = self::$_client->upload($settings['bucket'], $settings['directory'] . basename($file), $f, 'private', array('StorageClass' => $settings['storage'], 'ServerSideEncryption' => 'AES256'));
             } catch (Exception $e) {
                 return self::_error('Error #389383: Unable to initiate non-chunked upload. Details: `' . $e->getMessage() . '`.');
             }
             @fclose($f);
             // Made it here so SUCCESS sending.
             $uploaded_size = $file_size;
             $uploaded_speed = $file_size / (time(true) - $startSend);
             pb_backupbuddy::status('details', 'Success uploading file `' . basename($file) . '`. Upload details: `' . print_r($response, true) . '`. Uploaded size: ' . pb_backupbuddy::$format->file_size($uploaded_size) . ', Speed: ' . pb_backupbuddy::$format->file_size($uploaded_speed) . '/sec.');
             // Load destination fileoptions.
             pb_backupbuddy::status('details', 'About to load fileoptions data.');
             require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
             pb_backupbuddy::status('details', 'Fileoptions instance #882.');
             $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
             if (true !== ($result = $fileoptions_obj->is_ok())) {
                 return self::_error(__('Fatal Error #9034.23737. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
             }
             pb_backupbuddy::status('details', 'Fileoptions data loaded.');
             $fileoptions =& $fileoptions_obj->options;
             // Save stats.
             if (isset($uploaded_speed)) {
                 $fileoptions['write_speed'] = $uploaded_speed;
                 $fileoptions_obj->save();
             }
             unset($fileoptions_obj);
         }
         // End non-chunked upload.
     }
     // end not multipart continuation.
     // BEGIN FILE LIMIT PROCESSING. Enforce archive limits if applicable.
     if ($backup_type == 'full') {
         $limit = $full_archive_limit;
         pb_backupbuddy::status('details', 'Full backup archive limit of `' . $limit . '` of type `full` based on destination settings.');
     } elseif ($backup_type == 'db') {
         $limit = $db_archive_limit;
         pb_backupbuddy::status('details', 'Database backup archive limit of `' . $limit . '` of type `db` based on destination settings.');
     } elseif ($backup_type == 'files') {
         $limit = $db_archive_limit;
         pb_backupbuddy::status('details', 'Database backup archive limit of `' . $limit . '` of type `files` based on destination settings.');
     } else {
         $limit = 0;
         pb_backupbuddy::status('warning', 'Warning #237332. Unable to determine backup type (reported: `' . $backup_type . '`) so archive limits NOT enforced for this backup.');
     }
     if ($limit > 0) {
         pb_backupbuddy::status('details', 'Archive limit enforcement beginning.');
         // Get file listing.
         try {
             $response_manage = self::$_client->listObjects(array('Bucket' => $settings['bucket'], 'Prefix' => $settings['directory'] . 'backup-' . backup_prefix()));
             // List all users files in this directory that are a backup for this site (limited by prefix).
         } catch (Exception $e) {
             self::_error('Error #9338292: Unable to list files for archive limiting. Details: `' . $e->getMessage() . '`.');
         }
         // List backups associated with this site by date.
         $backups = array();
         foreach ($response_manage->Contents as $object) {
             $file = str_replace($settings['directory'], '', $object['Key']);
             $backups[$file] = strtotime($object['LastModified']);
         }
         arsort($backups);
         pb_backupbuddy::status('details', 'Stash found `' . count($backups) . '` backups of this type when checking archive limits.');
         if (count($backups) > $limit) {
             pb_backupbuddy::status('details', 'More archives (' . count($backups) . ') than limit (' . $limit . ') allows. Trimming...');
             $i = 0;
             $delete_fail_count = 0;
             foreach ($backups as $buname => $butime) {
                 $i++;
                 if ($i > $limit) {
                     pb_backupbuddy::status('details', 'Trimming excess file `' . $buname . '`...');
                     try {
                         $response = self::$_client->deleteObject(array('Bucket' => $settings['bucket'], 'Key' => $settings['directory'] . $buname));
                     } catch (Exception $e) {
                         self::_error('Unable to delete excess Stash file `' . $buname . '`. Details: `' . $e->getMessage() . '`.');
                         $delete_fail_count++;
                     }
                 }
             }
             pb_backupbuddy::status('details', 'Finished trimming excess backups.');
             if ($delete_fail_count !== 0) {
                 $error_message = 'Stash remote limit could not delete ' . $delete_fail_count . ' backups.';
                 pb_backupbuddy::status('error', $error_message);
                 backupbuddy_core::mail_error($error_message);
             }
         }
         pb_backupbuddy::status('details', 'Stash completed archive limiting.');
     } else {
         pb_backupbuddy::status('details', 'No Stash archive file limit to enforce.');
     }
     // End remote backup limit
     if (isset($fileoptions_obj)) {
         unset($fileoptions_obj);
     }
     // Success if we made it this far.
     return true;
 }
Esempio n. 11
0
 public static function periodic_cleanup($backup_age_limit = 172800, $die_on_fail = true)
 {
     $max_importbuddy_age = 60 * 60 * 1;
     // 1hr - Max age, in seconds, importbuddy files can be there before cleaning up (delay useful if just imported and testing out site).
     $max_status_log_age = 48;
     // Max age in hours.
     $max_site_log_size = pb_backupbuddy::$options['max_site_log_size'] * 1024 * 1024;
     // in bytes.
     pb_backupbuddy::status('message', 'Starting cleanup procedure for BackupBuddy v' . pb_backupbuddy::settings('version') . '.');
     if (!isset(pb_backupbuddy::$options)) {
         self::load();
     }
     // Alert user if no new backups FINISHED within X number of days if enabled. Max 1 email notification per 24 hours period.
     if (pb_backupbuddy::$options['no_new_backups_error_days'] > 0) {
         if (pb_backupbuddy::$options['last_backup_finish'] > 0) {
             $time_since_last = time() - pb_backupbuddy::$options['last_backup_finish'];
             $days_since_last = $time_since_last / 60 / 60 / 24;
             if ($days_since_last > pb_backupbuddy::$options['no_new_backups_error_days']) {
                 $last_sent = get_transient('pb_backupbuddy_no_new_backup_error');
                 if (false === $last_sent) {
                     $last_sent = time();
                     set_transient('pb_backupbuddy_no_new_backup_error', $last_sent, 60 * 60 * 24);
                 }
                 if (time() - $last_sent > 60 * 60 * 24) {
                     // 24hrs+ elapsed since last email sent.
                     $message = 'Alert! BackupBuddy is configured to notify you if no new backups have completed in `' . pb_backupbuddy::$options['no_new_backups_error_days'] . '` days. It has been `' . $days_since_last . '` days since your last completed backups.';
                     pb_backupbuddy::status('warning', $message);
                     backupbuddy_core::mail_error($message);
                 }
             }
         }
     }
     // TODO: Check for orphaned .gz files in root from PCLZip.
     // Cleanup backup itegrity portion of array (status logging info inside function).
     // DEPRECATED: self::trim_backups_integrity_stats();
     /***** BEGIN CLEANUP LOGS *****/
     // Purge old logs.
     pb_backupbuddy::status('details', 'Cleaning up old logs.');
     $log_directory = backupbuddy_core::getLogDirectory();
     // Purge individual backup status logs unmodified in certain number of hours.
     $files = glob($log_directory . 'status-*.txt');
     if (is_array($files) && !empty($files)) {
         // For robustness. Without open_basedir the glob() function returns an empty array for no match. With open_basedir in effect the glob() function returns a boolean false for no match.
         foreach ($files as $file) {
             $file_stats = stat($file);
             if (time() - $file_stats['mtime'] > $max_status_log_age) {
                 @unlink($file);
             }
         }
     }
     // Purge site-wide log if over certain size.
     $files = glob($log_directory . 'log-*.txt');
     if (is_array($files) && !empty($files)) {
         // For robustness. Without open_basedir the glob() function returns an empty array for no match. With open_basedir in effect the glob() function returns a boolean false for no match.
         foreach ($files as $file) {
             $file_stats = stat($file);
             if ($file_stats['size'] > $max_site_log_size) {
                 self::mail_error('NOTICE ONLY (not an error): A BackupBuddy log file has exceeded the size threshold of ' . $max_site_log_size . ' KB and has been deleted to maintain performance. This is only a notice. Deleted log file: ' . $file . '.');
                 @unlink($file);
             }
         }
     }
     /***** END CLEANUP LOGS *****/
     // Cleanup any temporary local destinations.
     pb_backupbuddy::status('details', 'Cleaning up any temporary local destinations.');
     foreach (pb_backupbuddy::$options['remote_destinations'] as $destination_id => $destination) {
         if ($destination['type'] == 'local' && (isset($destination['temporary']) && $destination['temporary'] === true)) {
             // If local and temporary.
             if (time() - $destination['created'] > $backup_age_limit) {
                 // Older than 12 hours; clear out!
                 pb_backupbuddy::status('details', 'Cleaned up stale local destination `' . $destination_id . '`.');
                 unset(pb_backupbuddy::$options['remote_destinations'][$destination_id]);
                 pb_backupbuddy::save();
             }
         }
     }
     // Cleanup excess remote sending stats.
     pb_backupbuddy::status('details', 'Cleaning up remote send stats.');
     self::trim_remote_send_stats($backup_age_limit);
     // Verify directory existance and anti-directory browsing is in place everywhere.
     self::verify_directories();
     require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
     // Purge fileoptions files without matching backup file in existance that are older than 30 days.
     pb_backupbuddy::status('details', 'Cleaning up old backup fileoptions option files.');
     $fileoptions_directory = backupbuddy_core::getLogDirectory() . 'fileoptions/';
     $files = glob($fileoptions_directory . '*.txt');
     if (!is_array($files)) {
         $files = array();
     }
     foreach ($files as $file) {
         $backup_options = new pb_backupbuddy_fileoptions($file, $read_only = true);
         if (true !== ($result = $backup_options->is_ok())) {
             pb_backupbuddy::status('error', 'Error retrieving fileoptions file `' . $file . '`. Err 335353266.');
         } else {
             if (isset($backup_options->options['archive_file'])) {
                 if (!file_exists($backup_options->options['archive_file'])) {
                     // No corresponding backup ZIP file.
                     $modified = filemtime($file);
                     if (time() - $modified > self::MAX_SECONDS_TO_KEEP_ORPHANED_FILEOPTIONS_FILES) {
                         // Too many days old so delete.
                         if (false === unlink($file)) {
                             pb_backupbuddy::status('error', 'Unable to delete orphaned fileoptions file `' . $file . '`.');
                         }
                         if (file_exists($file . '.lock')) {
                             @unlink($file . '.lock');
                         }
                     } else {
                         // Do not delete orphaned fileoptions because it is not old enough. Recent backups page needs these to list the backup.
                     }
                 } else {
                     // Backup ZIP file exists.
                 }
             }
         }
     }
     // end foreach.
     // Handle high security mode archives directory .htaccess system. If high security backup directory mode: Make sure backup archives are NOT downloadable by default publicly. This is only lifted for ~8 seconds during a backup download for security. Overwrites any existing .htaccess in this location.
     if (pb_backupbuddy::$options['lock_archives_directory'] == '0') {
         // Normal security mode. Put normal .htaccess.
         pb_backupbuddy::status('details', 'Removing .htaccess high security mode for backups directory. Normal mode .htaccess to be added next.');
         // Remove high security .htaccess.
         if (file_exists(backupbuddy_core::getBackupDirectory() . '.htaccess')) {
             $unlink_status = @unlink(backupbuddy_core::getBackupDirectory() . '.htaccess');
             if ($unlink_status === false) {
                 pb_backupbuddy::alert('Error #844594. Unable to temporarily remove .htaccess security protection on archives directory to allow downloading. Please verify permissions of the BackupBuddy archives directory or manually download via FTP.');
             }
         }
         // Place normal .htaccess.
         pb_backupbuddy::anti_directory_browsing(backupbuddy_core::getBackupDirectory(), $die_on_fail);
     } else {
         // High security mode. Make sure high security .htaccess in place.
         pb_backupbuddy::status('details', 'Adding .htaccess high security mode for backups directory.');
         $htaccess_creation_status = @file_put_contents(backupbuddy_core::getBackupDirectory() . '.htaccess', 'deny from all');
         if ($htaccess_creation_status === false) {
             pb_backupbuddy::alert('Error #344894545. Security Warning! Unable to create security file (.htaccess) in backups archive directory. This file prevents unauthorized downloading of backups should someone be able to guess the backup location and filenames. This is unlikely but for best security should be in place. Please verify permissions on the backups directory.');
         }
     }
     // Remove any copy of importbuddy.php in root.
     pb_backupbuddy::status('details', 'Cleaning up importbuddy.php script in site root if it exists & is not very recent.');
     if (file_exists(ABSPATH . 'importbuddy.php')) {
         $modified = filemtime(ABSPATH . 'importbuddy.php');
         if (FALSE === $modified || time() > $modified + $max_importbuddy_age) {
             // If time modified unknown OR was modified long enough ago.
             pb_backupbuddy::status('details', 'Unlinked importbuddy.php in root of site.');
             unlink(ABSPATH . 'importbuddy.php');
         } else {
             pb_backupbuddy::status('details', 'SKIPPED unlinking importbuddy.php in root of site as it is fresh and may still be in use.');
         }
     }
     // Remove any copy of importbuddy directory in root.
     pb_backupbuddy::status('details', 'Cleaning up importbuddy directory in site root if it exists & is not very recent.');
     if (file_exists(ABSPATH . 'importbuddy/')) {
         $modified = filemtime(ABSPATH . 'importbuddy/');
         if (FALSE === $modified || time() > $modified + $max_importbuddy_age) {
             // If time modified unknown OR was modified long enough ago.
             pb_backupbuddy::status('details', 'Unlinked importbuddy directory recursively in root of site.');
             pb_backupbuddy::$filesystem->unlink_recursive(ABSPATH . 'importbuddy/');
         } else {
             pb_backupbuddy::status('details', 'SKIPPED unlinked importbuddy directory recursively in root of site as it is fresh and may still be in use.');
         }
     }
     // Remove any old temporary directories in wp-content/uploads/backupbuddy_temp/. Logs any directories it cannot delete.
     pb_backupbuddy::status('details', 'Cleaning up any old temporary zip directories in: wp-content/uploads/backupbuddy_temp/');
     $temp_directory = WP_CONTENT_DIR . '/uploads/backupbuddy_temp/';
     $files = glob($temp_directory . '*');
     if (is_array($files) && !empty($files)) {
         // For robustness. Without open_basedir the glob() function returns an empty array for no match. With open_basedir in effect the glob() function returns a boolean false for no match.
         foreach ($files as $file) {
             if (strpos($file, 'index.') !== false || strpos($file, '.htaccess') !== false) {
                 // Index file or htaccess dont get deleted so go to next file.
                 continue;
             }
             $file_stats = stat($file);
             if (0 == $backup_age_limit || time() - $file_stats['mtime'] > $backup_age_limit) {
                 // If older than 12 hours, delete the log.
                 if (@pb_backupbuddy::$filesystem->unlink_recursive($file) === false) {
                     pb_backupbuddy::status('error', 'Unable to clean up (delete) temporary directory/file: `' . $file . '`. You should manually delete it or check permissions.');
                 }
             }
         }
     }
     // Cleanup any temp files from a failed restore within WordPress. (extract file feature).
     $temp_dir = get_temp_dir();
     pb_backupbuddy::status('details', 'Cleaning up temporary files from individual file / directory restores in directory `' . $temp_dir . '`...');
     $possibly_temp_restore_dirs = glob($temp_dir . 'backupbuddy-*');
     if (!is_array($possibly_temp_restore_dirs)) {
         $possibly_temp_restore_dirs = array();
     }
     foreach ($possibly_temp_restore_dirs as $possibly_temp_restore_dir) {
         if (false === pb_backupbuddy::$filesystem->unlink_recursive($possibly_temp_restore_dir)) {
             // Delete.
             pb_backupbuddy::status('details', 'Unable to delete temporary holding directory `' . $possibly_temp_restore_dir . '`.');
         } else {
             pb_backupbuddy::status('details', 'Cleaned up temporary files.');
         }
     }
     pb_backupbuddy::status('details', 'Individual file / directory restore cleanup complete.');
     // Remove any old temporary zip directories: wp-content/uploads/backupbuddy_backups/temp_zip_XXXX/. Logs any directories it cannot delete.
     pb_backupbuddy::status('details', 'Cleaning up any old temporary zip directories in backup directory temp location `' . backupbuddy_core::getBackupDirectory() . 'temp_zip_XXXX/`.');
     // $temp_directory = WP_CONTENT_DIR . '/uploads/backupbuddy_backups/temp_zip_*';
     $temp_directory = backupbuddy_core::getBackupDirectory() . 'temp_zip_*';
     $files = glob($temp_directory . '*');
     if (is_array($files) && !empty($files)) {
         // For robustness. Without open_basedir the glob() function returns an empty array for no match. With open_basedir in effect the glob() function returns a boolean false for no match.
         foreach ($files as $file) {
             if (strpos($file, 'index.') !== false || strpos($file, '.htaccess') !== false) {
                 // Index file or htaccess dont get deleted so go to next file.
                 continue;
             }
             $file_stats = stat($file);
             if (time() - $file_stats['mtime'] > $backup_age_limit) {
                 // If older than 12 hours, delete the log.
                 if (@pb_backupbuddy::$filesystem->unlink_recursive($file) === false) {
                     $message = 'BackupBuddy was unable to clean up (delete) temporary directory/file: `' . $file . '`. You should manually delete it and/or verify proper file permissions to allow BackupBuddy to clean up for you.';
                     pb_backupbuddy::status('error', $message);
                     self::mail_error($message);
                 }
             }
         }
     }
     // Cleanup remote S3 multipart chunking.
     foreach (pb_backupbuddy::$options['remote_destinations'] as $destination) {
         if ($destination['type'] != 's3') {
             continue;
         }
         if (isset($destination['max_chunk_size']) && $destination['max_chunk_size'] == '0') {
             continue;
         }
         pb_backupbuddy::status('details', 'Found S3 Multipart Chunking Destinations to cleanup.');
         require_once pb_backupbuddy::plugin_path() . '/destinations/bootstrap.php';
         $cleanup_result = pb_backupbuddy_destinations::multipart_cleanup($destination);
         /*
         if ( true === $cleanup_result ) {
         	pb_backupbuddy::status( 'details', 'S3 Multipart Chunking Cleanup Success.' );
         } else {
         	pb_backupbuddy::status( 'error', 'S3 Multipart Chunking Cleanup FAILURE. Manually cleanup stalled multipart send via S3 or try again later.' );
         }
         */
     }
     @clearstatcache();
     // Clears file info stat cache.
     pb_backupbuddy::status('message', 'Finished cleanup procedure.');
 }
<?php

backupbuddy_core::verifyAjaxAccess();
/* email_error_test()
 *
 * Test sending emails on the Settings page. Tries sending email and dies with "1" on success, else error message string echo'd out and dies.
 *
 */
$email = pb_backupbuddy::_POST('email');
if ($email == '') {
    die('You must supply an Error email address to send test message to.');
}
backupbuddy_core::mail_error('THIS IS ONLY A TEST. This is a test of the Error Notification email.', $email);
die('1');
Esempio n. 13
0
 public static function send($settings = array(), $files = array(), $send_id = '')
 {
     global $pb_backupbuddy_destination_errors;
     if ('1' == $settings['disabled']) {
         $pb_backupbuddy_destination_errors[] = __('Error #48933: This destination is currently disabled. Enable it under this destination\'s Advanced Settings.', 'it-l10n-backupbuddy');
         return false;
     }
     if (!is_array($files)) {
         $files = array($files);
     }
     $rs_container = $settings['container'];
     $limit = $settings['archive_limit'];
     if (false === ($conn = self::connect($settings))) {
         return false;
     }
     // Set container
     @$conn->create_container($rs_container);
     // Create container if it does not exist.
     $container = $conn->get_container($rs_container);
     // Get container.
     foreach ($files as $rs_file) {
         pb_backupbuddy::status('details', 'About to create object on Rackspace...');
         // Put file to Rackspace.
         $sendbackup = $container->create_object(basename($rs_file));
         pb_backupbuddy::status('details', 'Object created. About to stream actual file `' . $rs_file . '`...');
         if ($sendbackup->load_from_filename($rs_file)) {
             pb_backupbuddy::status('details', 'Send succeeded.');
             // Start remote backup limit
             if ($limit > 0) {
                 pb_backupbuddy::status('details', 'Archive limit of `' . $limit . '` in settings.');
                 $bkupprefix = backupbuddy_core::backup_prefix();
                 $results = $container->get_objects(0, NULL, 'backup-' . $bkupprefix . '-');
                 // Create array of backups and organize by date
                 $backups = array();
                 foreach ($results as $backup) {
                     $backups[$backup->name] = $backup->last_modified;
                 }
                 arsort($backups);
                 if (count($backups) > $limit) {
                     pb_backupbuddy::status('details', 'More archives (' . count($backups) . ') than limit (' . $limit . ') allows. Trimming...');
                     $i = 0;
                     $delete_fail_count = 0;
                     foreach ($backups as $buname => $butime) {
                         $i++;
                         if ($i > $limit) {
                             pb_backupbuddy::status('details', 'Trimming excess file `' . $buname . '`...');
                             if (!$container->delete_object($buname)) {
                                 pb_backupbuddy::status('details', 'Unable to delete excess Rackspace file `' . $buname . '`');
                                 $delete_fail_count++;
                             }
                         }
                     }
                     if ($delete_fail_count !== 0) {
                         $error_message = 'Rackspace remote limit could not delete `' . $delete_fail_count . '` backups.';
                         pb_backupbuddy::status('error', $error_message);
                         backupbuddy_core::mail_error($error_message);
                     }
                 }
             } else {
                 pb_backupbuddy::status('details', 'No Rackspace file limit to enforce.');
             }
             // End remote backup limit
             return true;
             // Success.
         } else {
             // Failed.
             $error_message = 'ERROR #9025: Connected to Rackspace but unable to put file. Verify Rackspace settings included Rackspace permissions.' . "\n\n" . 'http://ithemes.com/codex/page/BackupBuddy:_Error_Codes#9025';
             pb_backupbuddy::status('details', $error_message, 'error');
             backupbuddy_core::mail_error(__($error_message, 'it-l10n-backupbuddy'));
             return false;
             // Failed.
         }
     }
     // end foreach.
 }
Esempio n. 14
0
File: init.php Progetto: russtx/tac
 public static function send($settings = array(), $files = array(), $send_id = '', $delete_after = false)
 {
     if (!is_array($files)) {
         $files = array($files);
     }
     pb_backupbuddy::status('details', 'Dropbox2 send function started. Remote send id: `' . $send_id . '`.');
     // Normalize settings, apply defaults, etc.
     $settings = self::_normalizeSettings($settings);
     // Connect to Dropbox.
     if (false === self::_connect($settings['access_token'])) {
         // Try to connect. Return false if fail.
         return false;
     }
     $max_chunk_size_bytes = $settings['max_chunk_size'] * 1024 * 1024;
     /***** BEGIN MULTIPART CHUNKED CONTINUE *****/
     // Continue Multipart Chunked Upload
     if ($settings['_chunk_upload_id'] != '') {
         $file = $settings['_chunk_file'];
         pb_backupbuddy::status('details', 'Dropbox (PHP 5.3+) preparing to send chunked multipart upload part ' . ($settings['_chunk_sent_count'] + 1) . ' of ' . $settings['_chunk_total_count'] . ' with set chunk size of `' . $settings['max_chunk_size'] . '` MB. Dropbox Upload ID: `' . $settings['_chunk_upload_id'] . '`.');
         pb_backupbuddy::status('details', 'Opening file `' . basename($file) . '` to send.');
         $f = @fopen($file, 'rb');
         if (false === $f) {
             pb_backupbuddy::status('error', 'Error #87954435. Unable to open file `' . $file . '` to send to Dropbox.');
             return false;
         }
         // Seek to next chunk location.
         pb_backupbuddy::status('details', 'Seeking file to byte `' . $settings['_chunk_next_offset'] . '`.');
         if (0 != fseek($f, $settings['_chunk_next_offset'])) {
             // return of 0 is success.
             pb_backupbuddy::status('error', 'Unable to seek file to proper location offset `' . $settings['_chunk_next_offset'] . '`.');
         } else {
             pb_backupbuddy::status('details', 'Seek success.');
         }
         // Read this file chunk into memory.
         pb_backupbuddy::status('details', 'Reading chunk into memory.');
         try {
             $data = self::readFully($f, $settings['_chunk_maxsize']);
         } catch (\Exception $e) {
             pb_backupbuddy::status('error', 'Dropbox Error #484938376: ' . $e->getMessage());
             return false;
         }
         pb_backupbuddy::status('details', 'About to put chunk to Dropbox for continuation.');
         $send_time = -microtime(true);
         try {
             $result = self::$_dbxClient->chunkedUploadContinue($settings['_chunk_upload_id'], $settings['_chunk_next_offset'], $data);
         } catch (\Exception $e) {
             pb_backupbuddy::status('error', 'Dropbox Error #8754646: ' . $e->getMessage());
             return false;
         }
         // Examine response from Dropbox.
         if (true === $result) {
             // Upload success.
             pb_backupbuddy::status('details', 'Chunk upload continuation success with valid offset.');
         } elseif (false === $result) {
             // Failed.
             pb_backupbuddy::status('error', 'Chunk upload continuation failed at offset `' . $settings['_chunk_next_offset'] . '`.');
             return false;
         } elseif (is_numeric($result)) {
             // offset wrong. Update to use this.
             pb_backupbuddy::status('details', 'Chunk upload continuation received an updated offset response of `' . $result . '` when we tried `' . $settings['_chunk_next_offset'] . '`.');
             $settings['_chunk_next_offset'] = $result;
             // Try resending with corrected offset.
             try {
                 $result = self::$_dbxClient->chunkedUploadContinue($settings['_chunk_upload_id'], $settings['_chunk_next_offset'], $data);
             } catch (\Exception $e) {
                 pb_backupbuddy::status('error', 'Dropbox Error #8263836: ' . $e->getMessage());
                 return false;
             }
         }
         $send_time += microtime(true);
         $data_length = strlen($data);
         unset($data);
         // Calculate some stats to log.
         $chunk_transfer_speed = $data_length / $send_time;
         pb_backupbuddy::status('details', 'Dropbox chunk transfer stats - Sent: `' . pb_backupbuddy::$format->file_size($data_length) . '`, Transfer duration: `' . $send_time . '`, Speed: `' . pb_backupbuddy::$format->file_size($chunk_transfer_speed) . '`.');
         // Set options for subsequent step chunks.
         $chunked_destination_settings = $settings;
         $chunked_destination_settings['_chunk_offset'] = $data_length;
         $chunked_destination_settings['_chunk_sent_count']++;
         $chunked_destination_settings['_chunk_next_offset'] = $data_length * $chunked_destination_settings['_chunk_sent_count'];
         // First chunk was sent initiationg multipart send.
         $chunked_destination_settings['_chunk_transfer_speeds'][] = $chunk_transfer_speed;
         // Load destination fileoptions.
         pb_backupbuddy::status('details', 'About to load fileoptions data.');
         require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
         pb_backupbuddy::status('details', 'Fileoptions instance #15.');
         $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
         if (true !== ($result = $fileoptions_obj->is_ok())) {
             pb_backupbuddy::status('error', __('Fatal Error #9034.84838. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
             return false;
         }
         pb_backupbuddy::status('details', 'Fileoptions data loaded.');
         $fileoptions =& $fileoptions_obj->options;
         // Multipart send completed. Send finished signal to Dropbox to seal the deal.
         if (true === feof($f)) {
             pb_backupbuddy::status('details', 'At end of file. Finishing transfer and notifying Dropbox of file transfer completion.');
             $chunked_destination_settings['_chunk_upload_id'] = '';
             // Unset since chunking finished.
             try {
                 $result = self::$_dbxClient->chunkedUploadFinish($settings['_chunk_upload_id'], $settings['directory'] . '/' . basename($file), dbx\WriteMode::add());
             } catch (\Exception $e) {
                 pb_backupbuddy::status('error', 'Dropbox Error #549838979: ' . $e->getMessage());
                 return false;
             }
             pb_backupbuddy::status('details', 'Chunked upload finish results: `' . print_r($result, true) . '`.');
             if (filesize($settings['_chunk_file']) != $result['bytes']) {
                 pb_backupbuddy::status('error', 'Error #8958944. Dropbox reported file size differs from local size. The file upload may have been corrupted.');
                 return false;
             }
             $fileoptions['write_speed'] = array_sum($chunked_destination_settings['_chunk_transfer_speeds']) / $chunked_destination_settings['_chunk_sent_count'];
             $fileoptions['_multipart_status'] = 'Sent part ' . $chunked_destination_settings['_chunk_sent_count'] . ' of ' . $chunked_destination_settings['_chunk_total_count'] . '.';
             $fileoptions['finish_time'] = time();
             $fileoptions['status'] = 'success';
             $fileoptions_obj->save();
             unset($fileoptions_obj);
         }
         fclose($f);
         pb_backupbuddy::status('details', 'Sent chunk number `' . $chunked_destination_settings['_chunk_sent_count'] . '` to Dropbox with upload ID: `' . $chunked_destination_settings['_chunk_upload_id'] . '`. Next offset: `' . $chunked_destination_settings['_chunk_next_offset'] . '`.');
         // Schedule to continue if anything is left to upload for this multipart of any individual files.
         if ($chunked_destination_settings['_chunk_upload_id'] != '' || count($files) > 0) {
             pb_backupbuddy::status('details', 'Dropbox multipart upload has more parts left. Scheduling next part send.');
             $cronTime = time();
             $cronArgs = array($chunked_destination_settings, $files, $send_id, $delete_after);
             $cronHashID = md5($cronTime . serialize($cronArgs));
             $cronArgs[] = $cronHashID;
             $schedule_result = backupbuddy_core::schedule_single_event($cronTime, pb_backupbuddy::cron_tag('destination_send'), $cronArgs);
             if (true === $schedule_result) {
                 pb_backupbuddy::status('details', 'Next Dropbox chunk step cron event scheduled.');
             } else {
                 pb_backupbuddy::status('error', 'Next Dropbox chunk step cron even FAILED to be scheduled.');
             }
             spawn_cron(time() + 150);
             // Adds > 60 seconds to get around once per minute cron running limit.
             update_option('_transient_doing_cron', 0);
             // Prevent cron-blocking for next item.
             return array($chunked_destination_settings['_chunk_upload_id'], 'Sent ' . $chunked_destination_settings['_chunk_sent_count'] . ' of ' . $chunked_destination_settings['_chunk_total_count'] . ' parts.');
         }
     }
     // end continue multipart chunked upload.
     /***** END MULTIPART CHUNKED CONTINUE *****/
     pb_backupbuddy::status('details', 'Looping through files to send to Dropbox.');
     foreach ($files as $file_id => $file) {
         $file_size = filesize($file);
         pb_backupbuddy::status('details', 'Opening file `' . basename($file) . '` to send.');
         $f = @fopen($file, 'rb');
         if (false === $f) {
             pb_backupbuddy::status('error', 'Error #8457573. Unable to open file `' . $file . '` to send to Dropbox.');
             return false;
         }
         if ($settings['max_chunk_size'] >= 5 && $file_size / 1024 / 1024 > $settings['max_chunk_size']) {
             // chunked send.
             pb_backupbuddy::status('details', 'File exceeds chunking limit of `' . $settings['max_chunk_size'] . '` MB. Using chunked upload for this file transfer.');
             // Read first file chunk into memory.
             pb_backupbuddy::status('details', 'Reading first chunk into memory.');
             try {
                 $data = self::readFully($f, $max_chunk_size_bytes);
             } catch (\Exception $e) {
                 pb_backupbuddy::status('error', 'Dropbox Error #5684574373: ' . $e->getMessage());
                 return false;
             }
             // Start chunk upload to get upload ID. Sends first chunk piece.
             $send_time = -microtime(true);
             pb_backupbuddy::status('details', 'About to start chunked upload & put first chunk of file `' . basename($file) . '` to Dropbox (PHP 5.3+).');
             try {
                 $result = self::$_dbxClient->chunkedUploadStart($data);
             } catch (\Exception $e) {
                 pb_backupbuddy::status('error', 'Dropbox Error: ' . $e->getMessage());
                 return false;
             }
             $send_time += microtime(true);
             @fclose($f);
             $data_length = strlen($data);
             unset($data);
             // Calculate some stats to log.
             $chunk_transfer_speed = $data_length / $send_time;
             pb_backupbuddy::status('details', 'Dropbox chunk transfer stats - Sent: `' . pb_backupbuddy::$format->file_size($data_length) . '`, Transfer duration: `' . $send_time . '`, Speed: `' . pb_backupbuddy::$format->file_size($chunk_transfer_speed) . '`.');
             // Set options for subsequent step chunks.
             $chunked_destination_settings = $settings;
             $chunked_destination_settings['_chunk_file'] = $file;
             $chunked_destination_settings['_chunk_maxsize'] = $max_chunk_size_bytes;
             $chunked_destination_settings['_chunk_upload_id'] = $result;
             $chunked_destination_settings['_chunk_offset'] = $data_length;
             $chunked_destination_settings['_chunk_next_offset'] = $data_length;
             // First chunk was sent initiationg multipart send.
             $chunked_destination_settings['_chunk_sent_count'] = 1;
             $chunked_destination_settings['_chunk_total_count'] = ceil($file_size / $max_chunk_size_bytes);
             $chunked_destination_settings['_chunk_transfer_speeds'][] = $chunk_transfer_speed;
             pb_backupbuddy::status('details', 'Sent first chunk to Dropbox with upload ID: `' . $chunked_destination_settings['_chunk_upload_id'] . '`. Offset: `' . $chunked_destination_settings['_chunk_offset'] . '`.');
             // Remove this file from list to send before passing $files to schedule next cron. Multipart will handle this from here on out.
             unset($files[$file_id]);
             // Schedule next chunk to send.
             pb_backupbuddy::status('details', 'Dropbox (PHP 5.3+) scheduling send of next part(s).');
             $cronTime = time();
             $cronArgs = array($chunked_destination_settings, $files, $send_id, $delete_after);
             $cronHashID = md5($cronTime . serialize($cronArgs));
             $cronArgs[] = $cronHashID;
             if (false === backupbuddy_core::schedule_single_event($cronTime, pb_backupbuddy::cron_tag('destination_send'), $cronArgs)) {
                 pb_backupbuddy::status('error', 'Error #948844: Unable to schedule next Dropbox2 cron chunk.');
                 return false;
             } else {
                 pb_backupbuddy::status('details', 'Success scheduling next cron chunk.');
             }
             spawn_cron(time() + 150);
             // Adds > 60 seconds to get around once per minute cron running limit.
             update_option('_transient_doing_cron', 0);
             // Prevent cron-blocking for next item.
             pb_backupbuddy::status('details', 'Dropbox (PHP 5.3+) scheduled send of next part(s). Done for this cycle.');
             return array($chunked_destination_settings['_chunk_upload_id'], 'Sent 1 of ' . $chunked_destination_settings['_chunk_total_count'] . ' parts.');
         } else {
             // normal (non-chunked) send.
             pb_backupbuddy::status('details', 'Dropbox send not set to be chunked.');
             pb_backupbuddy::status('details', 'About to put file `' . basename($file) . '` (' . pb_backupbuddy::$format->file_size($file_size) . ') to Dropbox (PHP 5.3+).');
             $send_time = -microtime(true);
             try {
                 $result = self::$_dbxClient->uploadFile($settings['directory'] . '/' . basename($file), dbx\WriteMode::add(), $f);
             } catch (\Exception $e) {
                 pb_backupbuddy::status('error', 'Dropbox Error: ' . $e->getMessage());
                 return false;
             }
             $send_time += microtime(true);
             @fclose($f);
             pb_backupbuddy::status('details', 'About to load fileoptions data.');
             require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
             pb_backupbuddy::status('details', 'Fileoptions instance #14.');
             $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
             if (true !== ($result = $fileoptions_obj->is_ok())) {
                 pb_backupbuddy::status('error', __('Fatal Error #9034.2344848. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
                 return false;
             }
             pb_backupbuddy::status('details', 'Fileoptions data loaded.');
             $fileoptions =& $fileoptions_obj->options;
             // Calculate some stats to log.
             $data_length = $file_size;
             $transfer_speed = $data_length / $send_time;
             pb_backupbuddy::status('details', 'Dropbox (non-chunked) transfer stats - Sent: `' . pb_backupbuddy::$format->file_size($data_length) . '`, Transfer duration: `' . $send_time . '`, Speed: `' . pb_backupbuddy::$format->file_size($transfer_speed) . '/sec`.');
             $fileoptions['write_speed'] = $transfer_speed;
             $fileoptions_obj->save();
             unset($fileoptions_obj);
         }
         // end normal (non-chunked) send.
         pb_backupbuddy::status('message', 'Success sending `' . basename($file) . '` to Dropbox!');
         // Start remote backup limit
         if ($settings['archive_limit'] > 0) {
             pb_backupbuddy::status('details', 'Dropbox file limit in place. Proceeding with enforcement.');
             $meta_data = self::$_dbxClient->getMetadataWithChildren($settings['directory']);
             // Create array of backups and organize by date
             $bkupprefix = backupbuddy_core::backup_prefix();
             $backups = array();
             foreach ((array) $meta_data['contents'] as $looping_file) {
                 if ($looping_file['is_dir'] == '1') {
                     // JUST IN CASE. IGNORE anything that is a directory.
                     continue;
                 }
                 // check if file is backup
                 if (strpos($looping_file['path'], 'backup-' . $bkupprefix . '-') !== false) {
                     // Appears to be a backup file.
                     $backups[$looping_file['path']] = strtotime($looping_file['modified']);
                 }
             }
             arsort($backups);
             if (count($backups) > $settings['archive_limit']) {
                 pb_backupbuddy::status('details', 'Dropbox backup file count of `' . count($backups) . '` exceeds limit of `' . $settings['archive_limit'] . '`.');
                 $i = 0;
                 $delete_fail_count = 0;
                 foreach ($backups as $buname => $butime) {
                     $i++;
                     if ($i > $settings['archive_limit']) {
                         if (!self::$_dbxClient->delete($buname)) {
                             // Try to delete backup on Dropbox. Increment failure count if unable to.
                             pb_backupbuddy::status('details', 'Unable to delete excess Dropbox file: `' . $buname . '`');
                             $delete_fail_count++;
                         } else {
                             pb_backupbuddy::status('details', 'Deleted excess Dropbox file: `' . $buname . '`');
                         }
                     }
                 }
                 if ($delete_fail_count !== 0) {
                     backupbuddy_core::mail_error(sprintf(__('Dropbox remote limit could not delete %s backups.', 'it-l10n-backupbuddy'), $delete_fail_count));
                 }
             }
         } else {
             pb_backupbuddy::status('details', 'No Dropbox file limit to enforce.');
         }
         // End remote backup limit
     }
     // end foreach.
     pb_backupbuddy::status('details', 'All files sent.');
     return true;
     // Success if made it this far.
 }
 public static function send($destination_settings, $files, $send_id = '', $delete_after = false)
 {
     if ('' != $send_id) {
         pb_backupbuddy::add_status_serial('remote_send-' . $send_id);
         pb_backupbuddy::status('details', '----- Initiating master send function. Post-send deletion: ' . $delete_after);
         require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
         $fileoptions_file = backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt';
         if (!file_exists($fileoptions_file)) {
             //pb_backupbuddy::status( 'details', 'Fileoptions file `' . $fileoptions_file . '` does not exist yet; creating.' );
             //pb_backupbuddy::status( 'details', 'Fileoptions instance #19.' );
             $fileoptions_obj = new pb_backupbuddy_fileoptions($fileoptions_file, $read_only = false, $ignore_lock = true, $create_file = true);
         } else {
             //pb_backupbuddy::status( 'details', 'Fileoptions file exists; loading.' );
             //pb_backupbuddy::status( 'details', 'Fileoptions instance #18.' );
             $fileoptions_obj = new pb_backupbuddy_fileoptions($fileoptions_file, $read_only = false, $ignore_lock = false, $create_file = false);
         }
         if (true !== ($result = $fileoptions_obj->is_ok())) {
             pb_backupbuddy::status('error', __('Fatal Error #9034.2344848. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
             return false;
         }
         //pb_backupbuddy::status( 'details', 'Fileoptions data loaded.' );
         $fileoptions =& $fileoptions_obj->options;
         if ('' == $fileoptions) {
             $fileoptions = backupbuddy_core::get_remote_send_defaults();
             $fileoptions['type'] = $destination_settings['type'];
             if (!is_array($files)) {
                 $fileoptions['file'] = $files;
             } else {
                 $fileoptions['file'] = $files[0];
             }
             $fileoptions_obj->save();
         }
         if (isset($fileoptions['status']) && 'aborted' == $fileoptions['status']) {
             pb_backupbuddy::status('warning', 'Destination send triggered on an ABORTED transfer. Ending send function.');
             return false;
         }
         unset($fileoptions_obj);
     }
     if (false === ($destination = self::_init_destination($destination_settings))) {
         echo '{Error #546893498a. Destination configuration file missing.}';
         if ('' != $send_id) {
             pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
         }
         return false;
     }
     $destination_settings = $destination['settings'];
     // Settings with defaults applied, normalized, etc.
     //$destination_info = $destination['info'];
     if (!is_array($files)) {
         $files = array($files);
     }
     $originalFiles = $files;
     $files_with_sizes = '';
     foreach ($files as $index => $file) {
         if ('' == $file) {
             unset($files[$index]);
             continue;
             // Not actually a file to send.
         }
         if (!file_exists($file)) {
             pb_backupbuddy::status('error', 'Error #58459458743. The file that was attempted to be sent to a remote destination, `' . $file . '`, was not found. It either does not exist or permissions prevent accessing it.');
             if ('' != $send_id) {
                 pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
             }
             return false;
         }
         $files_with_sizes .= $file . ' (' . pb_backupbuddy::$format->file_size(filesize($file)) . '); ';
     }
     //pb_backupbuddy::status( 'details', 'Sending files `' . $files_with_sizes . '` to destination type `' . $destination_settings['type'] . '` titled `' . $destination_settings['title'] . '`.' );
     unset($files_with_sizes);
     if (!method_exists($destination['class'], 'send')) {
         pb_backupbuddy::status('error', 'Destination class `' . $destination['class'] . '` does not support send operation -- missing function.');
         if ('' != $send_id) {
             pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
         }
         return false;
     }
     //pb_backupbuddy::status( 'details', 'Calling send function.' );
     //$result = $destination_class::send( $destination_settings, $files );
     global $pb_backupbuddy_destination_errors;
     $pb_backupbuddy_destination_errors = array();
     $result = call_user_func_array("{$destination['class']}::send", array($destination_settings, $files, $send_id, $delete_after));
     if ($result === false) {
         $error_details = implode('; ', $pb_backupbuddy_destination_errors);
         if ('' != $error_details) {
             $error_details = ' Details: ' . $error_details;
         }
         $log_directory = backupbuddy_core::getLogDirectory();
         $preError = 'There was an error sending to the remote destination. One or more files may have not been fully transferred. Please see error details for additional information. If the error persists, enable full error logging and try again for full details and troubleshooting. Details: ' . "\n\n";
         $logFile = $log_directory . 'status-remote_send-' . $send_id . '_' . backupbuddy_core::get_serial_from_file($file) . '.txt';
         pb_backupbuddy::status('details', 'Looking for remote send log file `' . $logFile . '`.');
         if (!file_exists($logFile)) {
             pb_backupbuddy::status('details', 'Remote send log file not found.');
             backupbuddy_core::mail_error($preError . $error_details);
         } else {
             // Log exists. Attach.
             pb_backupbuddy::status('details', 'Remote send log file found. Attaching to error email.');
             backupbuddy_core::mail_error($preError . $error_details . "\n\nSee the attached log for details.", '', array($logFile));
         }
         // Save error details into fileoptions for this send.
         //pb_backupbuddy::status( 'details', 'About to load fileoptions data.' );
         require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
         pb_backupbuddy::status('details', 'Fileoptions instance #45.');
         $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
         if (true !== ($fileoptions_result = $fileoptions_obj->is_ok())) {
             pb_backupbuddy::status('error', __('Error #9034.32731. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $fileoptions_result);
         }
         //pb_backupbuddy::status( 'details', 'Fileoptions data loaded.' );
         $fileoptions =& $fileoptions_obj->options;
         $fileoptions['error'] = 'Error sending.' . $error_details;
         $fileoptions_obj->save();
         unset($fileoptions_obj);
     }
     if (is_array($result)) {
         // Send is multipart.
         pb_backupbuddy::status('details', 'Multipart chunk mode completed a pass of the send function. Resuming will be needed. Result: `' . print_r($result, true) . '`.');
         if ('' != $send_id) {
             //pb_backupbuddy::status( 'details', 'About to load fileoptions data.' );
             require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
             //pb_backupbuddy::status( 'details', 'Fileoptions instance #17.' );
             $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
             if (true !== ($fileoptions_result = $fileoptions_obj->is_ok())) {
                 pb_backupbuddy::status('error', __('Fatal Error #9034.387462. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $fileoptions_result);
                 return false;
             }
             //pb_backupbuddy::status( 'details', 'Fileoptions data loaded.' );
             $fileoptions =& $fileoptions_obj->options;
             $fileoptions['_multipart_status'] = $result[1];
             pb_backupbuddy::status('details', 'Destination debugging details: `' . print_r($fileoptions, true) . '`.');
             $fileoptions_obj->save();
             unset($fileoptions_obj);
             pb_backupbuddy::status('details', 'Next multipart chunk will be processed shortly. Now waiting on its cron...');
         }
     } else {
         // Single all-at-once send.
         if (false === $result) {
             pb_backupbuddy::status('details', 'Completed send function. Failure.');
         } elseif (true === $result) {
             pb_backupbuddy::status('details', 'Completed send function. Success.');
         } else {
             pb_backupbuddy::status('warning', 'Completed send function. Unknown result: `' . $result . '`.');
         }
         if (true === $delete_after) {
             pb_backupbuddy::status('details', __('Post-send deletion enabled.', 'it-l10n-backupbuddy'));
             if (false === $result) {
                 pb_backupbuddy::status('details', 'Skipping post-send deletion since transfer failed.');
             } else {
                 pb_backupbuddy::status('details', 'Performing post-send deletion since transfer succeeded.');
                 pb_backupbuddy::status('details', 'About to load fileoptions data.');
                 require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
                 pb_backupbuddy::status('details', 'Fileoptions instance #16.');
                 $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
                 if (true !== ($fileoptions_result = $fileoptions_obj->is_ok())) {
                     pb_backupbuddy::status('error', __('Error #9034.387462. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $fileoptions_result);
                 }
                 pb_backupbuddy::status('details', 'Fileoptions data loaded.');
                 $fileoptions =& $fileoptions_obj->options;
                 array_push($originalFiles, $fileoptions['file']);
                 // Add file (maybe multipart) into files to clean up.
                 foreach ($originalFiles as $file) {
                     pb_backupbuddy::status('details', 'Deleting local file `' . $file . '`.');
                     // Handle post-send deletion on success.
                     if (file_exists($file)) {
                         $unlink_result = @unlink($file);
                         if (true !== $unlink_result) {
                             pb_backupbuddy::status('error', 'Unable to unlink local file `' . $file . '`.');
                         }
                     }
                     if (file_exists($file)) {
                         // File still exists.
                         pb_backupbuddy::status('details', __('Error. Unable to delete local file `' . $file . '` after send as set in settings.', 'it-l10n-backupbuddy'));
                         backupbuddy_core::mail_error('BackupBuddy was unable to delete local file `' . $file . '` after successful remove transfer though post-remote send deletion is enabled. You may want to delete it manually. This can be caused by permission problems or improper server configuration.');
                     } else {
                         // Deleted.
                         pb_backupbuddy::status('details', __('Deleted local archive after successful remote destination send based on settings.', 'it-l10n-backupbuddy'));
                         pb_backupbuddy::status('archiveDeleted', '');
                     }
                 }
             }
         } else {
             pb_backupbuddy::status('details', 'Post-send deletion not enabled.');
         }
     }
     // NOTE: Call this before removing status serial so it shows in log.
     //pb_backupbuddy::status( 'details', 'Finishing send() function.' );
     if ('' != $send_id) {
         pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
     }
     return $result;
 }
Esempio n. 16
0
 public static function send($settings = array(), $files = array(), $send_id = '')
 {
     $rs_username = $settings['username'];
     $rs_api_key = $settings['api_key'];
     $rs_container = $settings['container'];
     $limit = $settings['archive_limit'];
     $rs_server = $settings['server'];
     require_once dirname(__FILE__) . '/lib/rackspace/cloudfiles.php';
     $auth = new CF_Authentication($rs_username, $rs_api_key, NULL, $rs_server);
     $auth->authenticate();
     $conn = new CF_Connection($auth);
     // Set container
     @$conn->create_container($rs_container);
     // Create container if it does not exist.
     $container = $conn->get_container($rs_container);
     // Get container.
     foreach ($files as $rs_file) {
         pb_backupbuddy::status('details', 'About to create object on Rackspace...');
         // Put file to Rackspace.
         $sendbackup = $container->create_object(basename($rs_file));
         pb_backupbuddy::status('details', 'Object created. About to stream actual file `' . $rs_file . '`...');
         if ($sendbackup->load_from_filename($rs_file)) {
             pb_backupbuddy::status('details', 'Send succeeded.');
             // Start remote backup limit
             if ($limit > 0) {
                 pb_backupbuddy::status('details', 'Archive limit of `' . $limit . '` in settings.');
                 $bkupprefix = backupbuddy_core::backup_prefix();
                 $results = $container->get_objects(0, NULL, 'backup-' . $bkupprefix . '-');
                 // Create array of backups and organize by date
                 $backups = array();
                 foreach ($results as $backup) {
                     $backups[$backup->name] = $backup->last_modified;
                 }
                 arsort($backups);
                 if (count($backups) > $limit) {
                     pb_backupbuddy::status('details', 'More archives (' . count($backups) . ') than limit (' . $limit . ') allows. Trimming...');
                     $i = 0;
                     $delete_fail_count = 0;
                     foreach ($backups as $buname => $butime) {
                         $i++;
                         if ($i > $limit) {
                             pb_backupbuddy::status('details', 'Trimming excess file `' . $buname . '`...');
                             if (!$container->delete_object($buname)) {
                                 pb_backupbuddy::status('details', 'Unable to delete excess Rackspace file `' . $buname . '`');
                                 $delete_fail_count++;
                             }
                         }
                     }
                     if ($delete_fail_count !== 0) {
                         $error_message = 'Rackspace remote limit could not delete `' . $delete_fail_count . '` backups.';
                         pb_backupbuddy::status('error', $error_message);
                         backupbuddy_core::mail_error($error_message);
                     }
                 }
             } else {
                 pb_backupbuddy::status('details', 'No Rackspace file limit to enforce.');
             }
             // End remote backup limit
             return true;
             // Success.
         } else {
             // Failed.
             $error_message = 'ERROR #9025: Connected to Rackspace but unable to put file. Verify Rackspace settings included Rackspace permissions.' . "\n\n" . 'http://ithemes.com/codex/page/BackupBuddy:_Error_Codes#9025';
             pb_backupbuddy::status('details', $error_message, 'error');
             backupbuddy_core::mail_error(__($error_message, 'it-l10n-backupbuddy'));
             return false;
             // Failed.
         }
     }
     // end foreach.
 }
Esempio n. 17
0
 public static function send($settings = array(), $files = array(), $send_id = '', $delete_after = false, $delete_remote_after = false)
 {
     global $pb_backupbuddy_destination_errors;
     if ('1' == $settings['disabled']) {
         $pb_backupbuddy_destination_errors[] = __('Error #48933: This destination is currently disabled. Enable it under this destination\'s Advanced Settings.', 'it-l10n-backupbuddy');
         return false;
     }
     if (!is_array($files)) {
         $files = array($files);
     }
     pb_backupbuddy::status('details', 'Google Drive send() function started. Settings: `' . print_r($settings, true) . '`.');
     self::$_timeStart = microtime(true);
     $settings = self::_normalizeSettings($settings);
     if (false === ($settings = self::_connect($settings))) {
         // $settings =
         return self::_error('Error #38923923: Unable to connect with Google Drive. See log for details.');
     }
     $folderID = $settings['folderID'];
     if ('' == $folderID) {
         $folderID = 'root';
     }
     $chunkSizeBytes = $settings['max_burst'] * 1024 * 1024;
     // Send X mb at a time to limit memory usage.
     foreach ($files as $file) {
         // Determine backup type for limiting later.
         $backup_type = '';
         if (stristr($file, '-db-') !== false) {
             $backup_type = 'db';
         } elseif (stristr($file, '-full-') !== false) {
             $backup_type = 'full';
         } elseif (stristr($file, '-files-') !== false) {
             $backup_type = 'files';
         } elseif (stristr($file, '-export-') !== false) {
             $backup_type = 'export';
         }
         if (!file_exists($file)) {
             return self::_error('Error #37792: File selected to send not found: `' . $file . '`.');
         }
         $fileSize = filesize($file);
         $fileinfo = pathinfo($file);
         $fileextension = $fileinfo['extension'];
         if ('zip' == $fileextension) {
             $mimeType = 'application/zip';
         } elseif ('php' == $fileextension) {
             $mimeType = 'application/x-httpd-php';
         } else {
             $mimeType = '';
         }
         pb_backupbuddy::status('details', 'About to upload file `' . $file . '` of size `' . $fileSize . '` with mimetype `' . $mimeType . '` into folder `' . $folderID . '`. Internal chunk size of `' . $chunkSizeBytes . '` bytes.');
         if ($fileSize > $chunkSizeBytes) {
             pb_backupbuddy::status('details', 'File size `' . pb_backupbuddy::$format->file_size($fileSize) . '` exceeds max burst size `' . $settings['max_burst'] . ' MB` so this will be sent in bursts. If time limit nears then send will be chunked across multiple PHP loads.');
             $settings['_chunks_total'] = ceil($fileSize / $chunkSizeBytes);
         }
         if (0 == $settings['_chunks_total']) {
             $settings['_chunks_total'] = 1;
         }
         //Insert a file
         $driveFile = new Google_Service_Drive_DriveFile();
         $driveFile->setTitle(basename($file));
         $driveFile->setDescription('BackupBuddy file');
         $driveFile->setMimeType($mimeType);
         // Set the parent folder.
         if ('root' != $folderID) {
             $parentsCollectionData = new Google_Service_Drive_ParentReference();
             $parentsCollectionData->setId($folderID);
             $driveFile->setParents(array($parentsCollectionData));
         }
         self::$_client->setDefer(true);
         try {
             $insertRequest = self::$_drive->files->insert($driveFile);
         } catch (Exception $e) {
             pb_backupbuddy::alert('Error #3232783268336: initiating upload. Details: ' . $e->getMessage());
             return false;
         }
         // Handle getting resume information to see if resuming is still an option.
         $resumable = false;
         if ('' != $settings['_media_resumeUri']) {
             $headers = array('content-range' => 'bytes */' . $fileSize);
             $request = new Google_Http_Request($settings['_media_resumeUri'], 'PUT', $headers, '');
             $response = self::$_client->getIo()->makeRequest($request);
             if (308 == $response->getResponseHttpCode()) {
                 $range = $response->getResponseHeader('range');
                 if (!empty($range) && preg_match('/bytes=0-(\\d+)$/', $range, $matches)) {
                     $resumable = true;
                     pb_backupbuddy::status('details', 'Last send reported next byte to be `' . $settings['_media_progress'] . '`.');
                     $settings['_media_progress'] = $matches[1] + 1;
                     pb_backupbuddy::status('details', 'Google Drive resuming is available. Google Drive reports next byte to be `' . $settings['_media_progress'] . '`. Range: `' . $range . '`.');
                 }
             }
             if (!$resumable) {
                 pb_backupbuddy::status('details', 'Google Drive could not resume. Too much time may have passed or some other cause.');
             }
             if ($settings['_media_progress'] >= $fileSize) {
                 pb_backupbuddy::status('details', 'Google Drive resuming not needed. Remote file meets or exceeds file size. Completed.');
                 return true;
             }
         }
         // See https://developers.google.com/api-client-library/php/guide/media_upload
         try {
             $media = new Google_Http_MediaFileUpload(self::$_client, $insertRequest, $mimeType, null, true, $chunkSizeBytes);
         } catch (Exception $e) {
             pb_backupbuddy::alert('Error #3893273937: initiating upload. Details: ' . $e->getMessage());
             return;
         }
         $media->setFileSize($fileSize);
         // Reset these internal variables. NOTE: These are by default private. Must modify MediaFileUpload.php to make this possible by setting these vars public. Thanks Google!
         if ('' != $settings['_media_resumeUri']) {
             $media->resumeUri = $settings['_media_resumeUri'];
             $media->progress = $settings['_media_progress'];
         }
         pb_backupbuddy::status('details', 'Opening file for sending in binary mode.');
         $fs = fopen($file, 'rb');
         // If chunked resuming then seek to the correct place in the file.
         if ('' != $settings['_media_progress'] && $settings['_media_progress'] > 0) {
             // Resuming send of a partially transferred file.
             if (0 !== fseek($fs, $settings['_media_progress'])) {
                 // Go off the resume point as given by Google in case it didnt all make it. //$settings['resume_point'] ) ) { // Returns 0 on success.
                 pb_backupbuddy::status('error', 'Error #3872733: Failed to seek file to resume point `' . $settings['_media_progress'] . '` via fseek().');
                 return false;
             }
             $prevPointer = $settings['_media_progress'];
             //$settings['resume_point'];
         } else {
             // New file send.
             $prevPointer = 0;
         }
         $needProcessChunking = false;
         // Set true if we need to spawn off resuming to a new PHP page load.
         $uploadStatus = false;
         while (!$uploadStatus && !feof($fs)) {
             $chunk = fread($fs, $chunkSizeBytes);
             pb_backupbuddy::status('details', 'Chunk of size `' . pb_backupbuddy::$format->file_size($chunkSizeBytes) . '` read into memory. Total bytes summed: `' . ($settings['_media_progress'] + strlen($chunk)) . '` of filesize: `' . $fileSize . '`.');
             pb_backupbuddy::status('details', 'Sending burst file data next. If next message is not "Burst file data sent" then the send likely timed out. Try reducing burst size. Sending now...');
             // Send chunk of data.
             try {
                 $uploadStatus = $media->nextChunk($chunk);
             } catch (Exception $e) {
                 global $pb_backupbuddy_destination_errors;
                 $pb_backupbuddy_destination_errors[] = $e->getMessage();
                 $error = $e->getMessage();
                 pb_backupbuddy::status('error', 'Error #8239832: Error sending burst data. Details: `' . $error . '`.');
                 return false;
             }
             $settings['_chunks_sent']++;
             self::$_chunksSentThisRound++;
             pb_backupbuddy::status('details', 'Burst file data sent.');
             $maxTime = $settings['max_time'];
             if ('' == $maxTime || !is_numeric($maxTime)) {
                 pb_backupbuddy::status('details', 'Max time not set in settings so detecting server max PHP runtime.');
                 $maxTime = backupbuddy_core::detectMaxExecutionTime();
             }
             //return;
             // Handle splitting up across multiple PHP page loads if needed.
             if (!feof($fs) && 0 != $maxTime) {
                 // More data remains so see if we need to consider chunking to a new PHP process.
                 // If we are within X second of reaching maximum PHP runtime then stop here so that it can be picked up in another PHP process...
                 $totalSizeSent = self::$_chunksSentThisRound * $chunkSizeBytes;
                 // Total bytes sent this PHP load.
                 $bytesPerSec = $totalSizeSent / (microtime(true) - self::$_timeStart);
                 $timeRemaining = $maxTime - (microtime(true) - self::$_timeStart + self::TIME_WIGGLE_ROOM);
                 if ($timeRemaining < 0) {
                     $timeRemaining = 0;
                 }
                 $bytesWeCouldSendWithTimeLeft = $bytesPerSec * $timeRemaining;
                 pb_backupbuddy::status('details', 'Total sent: `' . pb_backupbuddy::$format->file_size($totalSizeSent) . '`. Speed (per sec): `' . pb_backupbuddy::$format->file_size($bytesPerSec) . '`. Time Remaining (w/ wiggle): `' . $timeRemaining . '`. Size that could potentially be sent with remaining time: `' . pb_backupbuddy::$format->file_size($bytesWeCouldSendWithTimeLeft) . '` with chunk size of `' . pb_backupbuddy::$format->file_size($chunkSizeBytes) . '`.');
                 if ($bytesWeCouldSendWithTimeLeft < $chunkSizeBytes) {
                     // We can send more than a whole chunk (including wiggle room) so send another bit.
                     pb_backupbuddy::status('message', 'Not enough time left (~`' . $timeRemaining . '`) with max time of `' . $maxTime . '` sec to send another chunk at `' . pb_backupbuddy::$format->file_size($bytesPerSec) . '` / sec. Ran for ' . round(microtime(true) - self::$_timeStart, 3) . ' sec. Proceeding to use chunking.');
                     @fclose($fs);
                     // Tells next chunk where to pick up.
                     if (isset($chunksTotal)) {
                         $settings['_chunks_total'] = $chunksTotal;
                     }
                     // Grab these vars from the class.  Note that we changed these vars from private to public to make chunked resuming possible.
                     $settings['_media_resumeUri'] = $media->resumeUri;
                     $settings['_media_progress'] = $media->progress;
                     // Schedule cron.
                     $cronTime = time();
                     $cronArgs = array($settings, $files, $send_id, $delete_after);
                     $cronHashID = md5($cronTime . serialize($cronArgs));
                     $cronArgs[] = $cronHashID;
                     $schedule_result = backupbuddy_core::schedule_single_event($cronTime, 'destination_send', $cronArgs);
                     if (true === $schedule_result) {
                         pb_backupbuddy::status('details', 'Next Site chunk step cron event scheduled.');
                     } else {
                         pb_backupbuddy::status('error', 'Next Site chunk step cron even FAILED to be scheduled.');
                     }
                     spawn_cron(time() + 150);
                     // Adds > 60 seconds to get around once per minute cron running limit.
                     update_option('_transient_doing_cron', 0);
                     // Prevent cron-blocking for next item.
                     return array($prevPointer, 'Sent part ' . $settings['_chunks_sent'] . ' of ~' . $settings['_chunks_total'] . ' parts.');
                     // filepointer location, elapsed time during the import
                 } else {
                     // End if.
                     pb_backupbuddy::status('details', 'Not approaching limits.');
                 }
             } else {
                 pb_backupbuddy::status('details', 'No more data remains (eg for chunking) so finishing up.');
                 if ('' != $send_id) {
                     require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
                     $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
                     if (true !== ($result = $fileoptions_obj->is_ok())) {
                         pb_backupbuddy::status('error', __('Fatal Error #9034.397237. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
                         return false;
                     }
                     pb_backupbuddy::status('details', 'Fileoptions data loaded.');
                     $fileoptions =& $fileoptions_obj->options;
                     $fileoptions['_multipart_status'] = 'Sent part ' . $settings['_chunks_sent'] . ' of ~' . $settings['_chunks_total'] . ' parts.';
                     $fileoptions['finish_time'] = microtime(true);
                     $fileoptions['status'] = 'success';
                     $fileoptions_obj->save();
                     unset($fileoptions_obj);
                 }
             }
         }
         fclose($fs);
         self::$_client->setDefer(false);
         if (false == $uploadStatus) {
             global $pb_backupbuddy_destination_errors;
             $pb_backupbuddy_destination_errors[] = 'Error #84347474 sending. Details: ' . $uploadStatus;
             return false;
         } else {
             // Success.
             if (true === $delete_remote_after) {
                 self::deleteFile($settings, $uploadStatus->id);
             }
         }
     }
     // end foreach.
     $db_archive_limit = $settings['db_archive_limit'];
     $full_archive_limit = $settings['full_archive_limit'];
     $files_archive_limit = $settings['files_archive_limit'];
     // BEGIN FILE LIMIT PROCESSING. Enforce archive limits if applicable.
     if ($backup_type == 'full') {
         $limit = $full_archive_limit;
     } elseif ($backup_type == 'db') {
         $limit = $db_archive_limit;
     } elseif ($backup_type == 'files') {
         $limit = $files_archive_limit;
     } else {
         $limit = 0;
         pb_backupbuddy::status('warning', 'Warning #34352453244. Google Drive was unable to determine backup type (reported: `' . $backup_type . '`) so archive limits NOT enforced for this backup.');
     }
     pb_backupbuddy::status('details', 'Google Drive database backup archive limit of `' . $limit . '` of type `' . $backup_type . '` based on destination settings.');
     if ($limit > 0) {
         pb_backupbuddy::status('details', 'Google Drive archive limit enforcement beginning.');
         // Get file listing.
         $searchCount = 1;
         $remoteFiles = array();
         while (count($remoteFiles) == 0 && $searchCount < 5) {
             pb_backupbuddy::status('details', 'Checking archive limits. Attempt ' . $searchCount . '.');
             $remoteFiles = pb_backupbuddy_destination_gdrive::listFiles($settings, "title contains 'backup-' AND title contains '-" . $backup_type . "-' AND '" . $folderID . "' IN parents AND trashed=false");
             //"title contains 'backup' and trashed=false" );
             sleep(1);
             $searchCount++;
         }
         // List backups associated with this site by date.
         $backups = array();
         $prefix = backupbuddy_core::backup_prefix();
         foreach ($remoteFiles as $remoteFile) {
             if ('application/vnd.google-apps.folder' == $remoteFile->mimeType) {
                 // Ignore folders.
                 continue;
             }
             if (strpos($remoteFile->originalFilename, 'backup-' . $prefix . '-') !== false) {
                 // Appears to be a backup file for this site.
                 $backups[$remoteFile->id] = strtotime($remoteFile->modifiedDate);
             }
         }
         arsort($backups);
         pb_backupbuddy::status('details', 'Google Drive found `' . count($backups) . '` backups of this type when checking archive limits.');
         if (count($backups) > $limit) {
             pb_backupbuddy::status('details', 'More archives (' . count($backups) . ') than limit (' . $limit . ') allows. Trimming...');
             $i = 0;
             $delete_fail_count = 0;
             foreach ($backups as $buname => $butime) {
                 $i++;
                 if ($i > $limit) {
                     pb_backupbuddy::status('details', 'Trimming excess file `' . $buname . '`...');
                     if (true !== self::deleteFile($settings, $buname)) {
                         pb_backupbuddy::status('details', 'Unable to delete excess Google Drive file `' . $buname . '`. Details: `' . print_r($pb_backupbuddy_destination_errors, true) . '`.');
                         $delete_fail_count++;
                     }
                 }
             }
             pb_backupbuddy::status('details', 'Finished trimming excess backups.');
             if ($delete_fail_count !== 0) {
                 $error_message = 'Google Drive remote limit could not delete ' . $delete_fail_count . ' backups.';
                 pb_backupbuddy::status('error', $error_message);
                 backupbuddy_core::mail_error($error_message);
             }
         }
         pb_backupbuddy::status('details', 'Google Drive completed archive limiting.');
     } else {
         pb_backupbuddy::status('details', 'No Google Drive archive file limit to enforce.');
     }
     // End remote backup limit
     // Made it this far then success.
     return true;
 }
Esempio n. 18
0
 public static function archiveLimit($settings, $backup_type)
 {
     $settings = self::_init($settings);
     pb_backupbuddy::status('error', 'Error #8339832893: TODO archiveLimit().');
     if ($backup_type == 'full') {
         $limit = $settings['full_archive_limit'];
         pb_backupbuddy::status('details', 'Full backup archive limit of `' . $limit . '` of type `full` based on destination settings.');
     } elseif ($backup_type == 'db') {
         $limit = $settings['db_archive_limit'];
         pb_backupbuddy::status('details', 'Database backup archive limit of `' . $limit . '` of type `db` based on destination settings.');
     } elseif ($backup_type == 'files') {
         $limit = $settings['files_archive_limit'];
         pb_backupbuddy::status('details', 'Database backup archive limit of `' . $limit . '` of type `files` based on destination settings.');
     } else {
         $limit = 0;
         pb_backupbuddy::status('warning', 'Warning #237332. Unable to determine backup type (reported: `' . $backup_type . '`) so archive limits NOT enforced for this backup.');
     }
     if ($limit > 0) {
         pb_backupbuddy::status('details', 'Archive limit enforcement beginning.');
         // Get file listing.
         $files = self::listFiles($settings, $prefix = '');
         if (!is_array($files)) {
             pb_backupbuddy::status('Error #3892383: Unable to list files. Skipping archive limiting.');
             return false;
         }
         $remotePath = 'backup-' . backupbuddy_core::backup_prefix();
         $prefixLen = strlen(backupbuddy_core::backup_prefix());
         // List backups associated with this site by date.
         $backups = array();
         foreach ($files as $file) {
             if ($file['backup_type'] != $backup_type) {
                 continue;
             }
             if (!backupbuddy_core::startsWith(basename($file['filename']), $remotePath)) {
                 // Only show backups for this site unless set to show all.
                 continue;
             }
             $backups[$file['filename']] = $file['uploaded_timestamp'];
         }
         unset($files);
         arsort($backups);
         pb_backupbuddy::status('details', 'Found `' . count($backups) . '` backups of this type when checking archive limits.');
         if (count($backups) > $limit) {
             pb_backupbuddy::status('details', 'More archives (' . count($backups) . ') than limit (' . $limit . ') allows. Trimming...');
             $i = 0;
             $delete_fail_count = 0;
             foreach ($backups as $buname => $butime) {
                 $i++;
                 if ($i > $limit) {
                     pb_backupbuddy::status('details', 'Trimming excess file `' . $buname . '`...');
                     $delete_response = self::deleteFile($settings, substr($buname, $prefixLen + 1));
                     if (true !== $delete_response) {
                         self::_error('Unable to delete excess Stash file `' . $buname . '`. Details: `' . $delete_response . '`.');
                         $delete_fail_count++;
                     }
                 }
             }
             // end foreach.
             pb_backupbuddy::status('details', 'Finished trimming excess backups.');
             if ($delete_fail_count !== 0) {
                 $error_message = 'Stash remote limit could not delete ' . $delete_fail_count . ' backups.';
                 pb_backupbuddy::status('error', $error_message);
                 backupbuddy_core::mail_error($error_message);
             }
         }
         pb_backupbuddy::status('details', 'Stash completed archive limiting.');
     } else {
         pb_backupbuddy::status('details', 'No Stash archive file limit to enforce.');
     }
     // End remote backup limit
     return true;
 }
Esempio n. 19
0
 public static function send($settings = array(), $files = array(), $send_id = '')
 {
     pb_backupbuddy::status('details', 'FTP class send() function started.');
     if ($settings['active_mode'] == '0') {
         $active_mode = false;
     } else {
         $active_mode = true;
     }
     $server = $settings['address'];
     $username = $settings['username'];
     $password = $settings['password'];
     $path = $settings['path'];
     $ftps = $settings['ftps'];
     $limit = $settings['archive_limit'];
     $active = $settings['active_mode'];
     $port = '21';
     // Default FTP port.
     if (strstr($server, ':')) {
         // Handle custom FTP port.
         $server_params = explode(':', $server);
         $server = $server_params[0];
         $port = $server_params[1];
     }
     // Connect to server.
     if ($ftps == '1') {
         // Connect with FTPs.
         if (function_exists('ftp_ssl_connect')) {
             $conn_id = ftp_ssl_connect($server, $port);
             if ($conn_id === false) {
                 pb_backupbuddy::status('details', 'Unable to connect to FTPS  `' . $server . '` on port `' . $port . '` (check address/FTPS support and that server can connect to this address via this port).', 'error');
                 return false;
             } else {
                 pb_backupbuddy::status('details', 'Connected to FTPs.');
             }
         } else {
             pb_backupbuddy::status('details', 'Your web server doesnt support FTPS in PHP.', 'error');
             return false;
         }
     } else {
         // Connect with FTP (normal).
         if (function_exists('ftp_connect')) {
             $conn_id = ftp_connect($server, $port);
             if ($conn_id === false) {
                 pb_backupbuddy::status('details', 'ERROR: Unable to connect to FTP server `' . $server . '` on port `' . $port . '` (check address and that server can connect to this address via this port).', 'error');
                 return false;
             } else {
                 pb_backupbuddy::status('details', 'Connected to FTP.');
             }
         } else {
             pb_backupbuddy::status('details', 'Your web server doesnt support FTP in PHP.', 'error');
             return false;
         }
     }
     // Log in.
     $login_result = @ftp_login($conn_id, $username, $password);
     if ($login_result === false) {
         backupbuddy_core::mail_error('ERROR #9011 ( http://ithemes.com/codex/page/BackupBuddy:_Error_Codes#9011 ).  FTP/FTPs login failed on scheduled FTP.');
         return false;
     } else {
         pb_backupbuddy::status('details', 'Logged in. Sending backup via FTP/FTPs ...');
     }
     if ($active_mode === true) {
         // do nothing, active is default.
         pb_backupbuddy::status('details', 'Active FTP mode based on settings.');
     } elseif ($active_mode === false) {
         // Turn passive mode on.
         pb_backupbuddy::status('details', 'Passive FTP mode based on settings.');
         ftp_pasv($conn_id, true);
     } else {
         pb_backupbuddy::status('error', 'Unknown FTP active/passive mode: `' . $active_mode . '`.');
     }
     // Create directory if it does not exist.
     @ftp_mkdir($conn_id, $path);
     // Change to directory.
     pb_backupbuddy::status('details', 'Entering FTP directory `' . $path . '`.');
     ftp_chdir($conn_id, $path);
     // Upload files.
     $total_transfer_size = 0;
     $total_transfer_time = 0;
     foreach ($files as $file) {
         if (!file_exists($file)) {
             pb_backupbuddy::status('error', 'Error #859485495. Could not upload local file `' . $file . '` to send to FTP as it does not exist. Verify the file exists, permissions of file, parent directory, and that ownership is correct. You may need suphp installed on the server.');
         }
         if (!is_readable($file)) {
             pb_backupbuddy::status('error', 'Error #8594846548. Could not read local file `' . $file . '` to sendto FTP as it is not readable. Verify permissions of file, parent directory, and that ownership is correct. You may need suphp installed on the server.');
         }
         $filesize = filesize($file);
         $total_transfer_size += $filesize;
         $destination_file = basename($file);
         // Using chdir() so path not needed. $path . '/' . basename( $file );
         pb_backupbuddy::status('details', 'About to put to FTP local file `' . $file . '` of size `' . pb_backupbuddy::$format->file_size($filesize) . '` to remote file `' . $destination_file . '`.');
         $send_time = -microtime(true);
         $upload = ftp_put($conn_id, $destination_file, $file, FTP_BINARY);
         $send_time += microtime(true);
         $total_transfer_time += $send_time;
         if ($upload === false) {
             $error_message = 'ERROR #9012 ( http://ithemes.com/codex/page/BackupBuddy:_Error_Codes#9012 ).  FTP/FTPs file upload failed. Check file permissions & disk quota.';
             pb_backupbuddy::status('error', $error_message);
             backupbuddy_core::mail_error($error_message);
             return false;
         } else {
             pb_backupbuddy::status('details', 'Success completely sending `' . basename($file) . '` to destination.');
             // Start remote backup limit
             if ($limit > 0) {
                 pb_backupbuddy::status('details', 'Getting contents of backup directory.');
                 ftp_chdir($conn_id, $path);
                 $contents = ftp_nlist($conn_id, '');
                 // Create array of backups
                 $bkupprefix = backupbuddy_core::backup_prefix();
                 $backups = array();
                 foreach ($contents as $backup) {
                     // check if file is backup
                     $pos = strpos($backup, 'backup-' . $bkupprefix . '-');
                     if ($pos !== FALSE) {
                         array_push($backups, $backup);
                     }
                 }
                 arsort($backups);
                 // some ftp servers seem to not report in proper order so reversing insufficiently reliable. need to reverse sort by filename. array_reverse( (array)$backups );
                 if (count($backups) > $limit) {
                     $delete_fail_count = 0;
                     $i = 0;
                     foreach ($backups as $backup) {
                         $i++;
                         if ($i > $limit) {
                             if (!ftp_delete($conn_id, $backup)) {
                                 pb_backupbuddy::status('details', 'Unable to delete excess FTP file `' . $backup . '` in path `' . $path . '`.');
                                 $delete_fail_count++;
                             }
                         }
                     }
                     if ($delete_fail_count !== 0) {
                         backupbuddy_core::mail_error(sprintf(__('FTP remote limit could not delete %s backups. Please check and verify file permissions.', 'it-l10n-backupbuddy'), $delete_fail_count));
                     }
                 }
             } else {
                 pb_backupbuddy::status('details', 'No FTP file limit to enforce.');
             }
             // End remote backup limit
         }
     }
     // end $files loop.
     // Load destination fileoptions.
     pb_backupbuddy::status('details', 'About to load fileoptions data.');
     require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
     pb_backupbuddy::status('details', 'Fileoptions instance #13.');
     $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
     if (true !== ($result = $fileoptions_obj->is_ok())) {
         pb_backupbuddy::status('error', __('Fatal Error #9034.84838. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
         return false;
     }
     pb_backupbuddy::status('details', 'Fileoptions data loaded.');
     $fileoptions =& $fileoptions_obj->options;
     // Save stats.
     $fileoptions['write_speed'] = $total_transfer_size / $total_transfer_time;
     //$fileoptions['finish_time'] = time();
     //$fileoptions['status'] = 'success';
     $fileoptions_obj->save();
     unset($fileoptions_obj);
     ftp_close($conn_id);
     return true;
 }
Esempio n. 20
0
 public static function send_remote_destination($destination_id, $file, $trigger = '', $send_importbuddy = false, $delete_after = false, $identifier = '', $destination_settings = '')
 {
     if (defined('PB_DEMO_MODE')) {
         return false;
     }
     if (!file_exists($file)) {
         pb_backupbuddy::status('error', 'Error #8583489734: Unable to send file `' . $file . '` to remote destination as it no longer exists. It may have been deleted or permissions are invalid.');
         return false;
     }
     $migrationkey_transient_time = 60 * 60 * 24;
     if ('' == $file) {
         $backup_file_size = 50000;
         // not sure why anything current would be sending importbuddy but NOT sending a backup but just in case...
     } else {
         $backup_file_size = filesize($file);
     }
     // Generate remote send ID for reference and add it as a new logging serial for better recording details.
     if ('' == $identifier) {
         $identifier = pb_backupbuddy::random_string(12);
     }
     // Set migration key for later determining last initiated migration.
     if ('migration' == $trigger) {
         set_transient('pb_backupbuddy_migrationkey', $identifier, $migrationkey_transient_time);
     }
     pb_backupbuddy::status('details', 'Sending file `' . $file . '` to remote destination `' . $destination_id . '` with ID `' . $identifier . '` triggered by `' . $trigger . '`.');
     //pb_backupbuddy::status( 'details', 'About to create initial fileoptions data.' );
     require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
     pb_backupbuddy::status('details', 'Fileoptions instance #35.');
     $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $identifier . '.txt', $read_only = false, $ignore_lock = true, $create_file = true);
     if (true !== ($result = $fileoptions_obj->is_ok())) {
         pb_backupbuddy::status('error', __('Fatal Error #9034 A. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
         return false;
     }
     //pb_backupbuddy::status( 'details', 'Fileoptions data loaded.' );
     $fileoptions =& $fileoptions_obj->options;
     // Set reference.
     // Record some statistics.
     $fileoptions = array_merge(self::get_remote_send_defaults(), array('destination' => $destination_id, 'file' => $file, 'file_size' => $backup_file_size, 'trigger' => $trigger, 'send_importbuddy' => $send_importbuddy, 'start_time' => time(), 'finish_time' => 0, 'status' => 'running', 'write_speed' => 0));
     pb_backupbuddy::save();
     // Destination settings were not passed so get them based on the destination ID provided.
     if (!is_array($destination_settings)) {
         $destination_settings =& pb_backupbuddy::$options['remote_destinations'][$destination_id];
     }
     // For Stash we will check the quota prior to initiating send.
     if (pb_backupbuddy::$options['remote_destinations'][$destination_id]['type'] == 'stash') {
         // Pass off to destination handler.
         require_once pb_backupbuddy::plugin_path() . '/destinations/bootstrap.php';
         $send_result = pb_backupbuddy_destinations::get_info('stash');
         // Used to kick the Stash destination into life.
         $stash_quota = pb_backupbuddy_destination_stash::get_quota(pb_backupbuddy::$options['remote_destinations'][$destination_id], true);
         if ($file != '') {
             $backup_file_size = filesize($file);
         } else {
             $backup_file_size = 50000;
         }
         if ($backup_file_size + $stash_quota['quota_used'] > $stash_quota['quota_total']) {
             $message = '';
             $message .= "You do not have enough Stash storage space to send this file. Please upgrade your Stash storage at http://ithemes.com/member/panel/stash.php or delete files to make space.\n\n";
             $message .= 'Attempting to send file of size ' . pb_backupbuddy::$format->file_size($backup_file_size) . ' but you only have ' . $stash_quota['quota_available_nice'] . ' available. ';
             $message .= 'Currently using ' . $stash_quota['quota_used_nice'] . ' of ' . $stash_quota['quota_total_nice'] . ' (' . $stash_quota['quota_used_percent'] . '%).';
             pb_backupbuddy::status('error', $message);
             backupbuddy_core::mail_error($message);
             $fileoptions['status'] = 'Failure. Insufficient destination space.';
             $fileoptions_obj->save();
             return false;
         } else {
             if (isset($stash_quota['quota_warning']) && $stash_quota['quota_warning'] != '') {
                 // We log warning of usage but dont send error email.
                 $message = '';
                 $message .= 'WARNING: ' . $stash_quota['quota_warning'] . "\n\nPlease upgrade your Stash storage at http://ithemes.com/member/panel/stash.php or delete files to make space.\n\n";
                 $message .= 'Currently using ' . $stash_quota['quota_used_nice'] . ' of ' . $stash_quota['quota_total_nice'] . ' (' . $stash_quota['quota_used_percent'] . '%).';
                 pb_backupbuddy::status('details', $message);
                 //backupbuddy_core::mail_error( $message );
             }
         }
     }
     // end if stash.
     /*
     if ( $send_importbuddy === true ) {
     	pb_backupbuddy::status( 'details', 'Generating temporary importbuddy.php file for remote send.' );
     	pb_backupbuddy::anti_directory_browsing( backupbuddy_core::getTempDirectory(), $die = false );
     	$importbuddy_temp = backupbuddy_core::getTempDirectory() . 'importbuddy.php'; // Full path & filename to temporary importbuddy
     	self::importbuddy( $importbuddy_temp ); // Create temporary importbuddy.
     	pb_backupbuddy::status( 'details', 'Generated temporary importbuddy.' );
     	$files[] = $importbuddy_temp; // Add importbuddy file to the list of files to send.
     	$send_importbuddy = true; // Track to delete after finished.
     } else {
     	pb_backupbuddy::status( 'details', 'Not sending importbuddy.' );
     }
     */
     // Clear fileoptions so other stuff can access it if needed.
     $fileoptions_obj->save();
     $fileoptions_obj->unlock();
     unset($fileoptions_obj);
     // Pass off to destination handler.
     require_once pb_backupbuddy::plugin_path() . '/destinations/bootstrap.php';
     pb_backupbuddy::status('details', 'Calling destination send() function.');
     $send_result = pb_backupbuddy_destinations::send($destination_settings, $file, $identifier, $delete_after);
     pb_backupbuddy::status('details', 'Finished destination send() function.');
     self::kick_db();
     // Kick the database to make sure it didn't go away, preventing options saving.
     // Reload fileoptions.
     pb_backupbuddy::status('details', 'About to load fileoptions data for saving send status.');
     require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
     pb_backupbuddy::status('details', 'Fileoptions instance #34.');
     $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $identifier . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
     if (true !== ($result = $fileoptions_obj->is_ok())) {
         pb_backupbuddy::status('error', __('Fatal Error #9034 G. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
         return false;
     }
     pb_backupbuddy::status('details', 'Fileoptions data loaded for ID `' . $identifier . '`.');
     $fileoptions =& $fileoptions_obj->options;
     // Set reference.
     // Update stats.
     $fileoptions[$identifier]['finish_time'] = microtime(true);
     if ($send_result === true) {
         // succeeded.
         $fileoptions['status'] = 'success';
         $fileoptions['finish_time'] = microtime(true);
         pb_backupbuddy::status('details', 'Remote send SUCCESS.');
     } elseif ($send_result === false) {
         // failed.
         $fileoptions['status'] = 'failure';
         pb_backupbuddy::status('details', 'Remote send FAILURE.');
     } elseif (is_array($send_result)) {
         // Array so multipart.
         $fileoptions['status'] = 'multipart';
         $fileoptions['finish_time'] = 0;
         $fileoptions['_multipart_id'] = $send_result[0];
         $fileoptions['_multipart_status'] = $send_result[1];
         pb_backupbuddy::status('details', 'Multipart send in progress.');
     } else {
         pb_backupbuddy::status('error', 'Error #5485785576463. Invalid status send result: `' . $send_result . '`.');
     }
     $fileoptions_obj->save();
     // If we sent importbuddy then delete the local copy to clean up.
     if ($send_importbuddy !== false) {
         @unlink($importbuddy_temp);
         // Delete temporary importbuddy.
     }
     // As of v5.0: Post-send deletion now handled within destinations/bootstrap.php send() to support chunked sends.
     return $send_result;
 }
Esempio n. 21
0
 public static function send($settings = array(), $files = array(), $send_id = '')
 {
     global $pb_backupbuddy_destination_errors;
     if ('1' == $settings['disabled']) {
         $pb_backupbuddy_destination_errors[] = __('Error #48933: This destination is currently disabled. Enable it under this destination\'s Advanced Settings.', 'it-l10n-backupbuddy');
         return false;
     }
     if (!is_array($files)) {
         $files = array($files);
     }
     $token =& $settings['token'];
     $directory = '/' . ltrim($settings['directory'], '/\\');
     $limit = $settings['archive_limit'];
     // Normalize picky dropbox directory.
     $directory = trim($directory, '\\/');
     pb_backupbuddy::status('details', 'About to load Dropbuddy library...');
     require_once pb_backupbuddy::plugin_path() . '/destinations/dropbox/lib/dropbuddy/dropbuddy.php';
     pb_backupbuddy::status('details', 'Dropbuddy loaded.');
     //pb_backupbuddy::status( 'details', 'Authenticating to dropbox with token: `' . implode( ';', $token ) . '`.' );
     $dropbuddy = new pb_backupbuddy_dropbuddy($token);
     pb_backupbuddy::status('details', 'Dropbuddy object created.');
     if ($dropbuddy->authenticate() !== true) {
         pb_backupbuddy::status('details', 'Dropbox authentication failed in send().');
         return false;
     } else {
         pb_backupbuddy::status('details', 'Authenticated to Dropbox.');
     }
     $memory = pb_backupbuddy_destination_dropbox::memory_guesstimate();
     pb_backupbuddy::status('details', 'Dropbox limitation estimated to be max transfer size of ' . round($memory['hypothesis'], 0) . 'MB based on PHP memory limit of ' . $memory['limit'] . 'MB & current loaded WordPress plugins.');
     pb_backupbuddy::status('details', 'Looping through files to send to Dropbox.');
     foreach ($files as $file) {
         pb_backupbuddy::status('details', 'About to put file `' . basename($file) . '` (' . pb_backupbuddy::$format->file_size(filesize($file)) . ') to Dropbox (v1).');
         try {
             $status = $dropbuddy->put_file($directory . '/' . basename($file), $file);
         } catch (Dropbox_Exception $e) {
             pb_backupbuddy::status('error', 'Dropbox exception caught. Error #8954785: ' . $e->getMessage());
             return false;
         }
         if ($status === true) {
             pb_backupbuddy::status('details', 'SUCCESS sending to Dropbox!');
         } else {
             pb_backupbuddy::status('details', 'Dropbox file send FAILURE. HTTP Status: ' . $status['httpStatus'] . '; Body: ' . $status['body'], 'error');
             return false;
         }
         // Start remote backup limit
         if ($limit > 0) {
             pb_backupbuddy::status('details', 'Dropbox file limit in place. Proceeding with enforcement.');
             $meta_data = $dropbuddy->get_meta_data($directory);
             // Create array of backups and organize by date
             $bkupprefix = backupbuddy_core::backup_prefix();
             $backups = array();
             foreach ((array) $meta_data['contents'] as $looping_file) {
                 if ('1' == $looping_file['is_dir']) {
                     // Additional safety layer to ignore subdirectory.
                     continue;
                 }
                 // check if file is backup
                 if (strpos($looping_file['path'], 'backup-' . $bkupprefix . '-') !== false) {
                     $backups[$looping_file['path']] = strtotime($looping_file['modified']);
                 }
             }
             arsort($backups);
             if (count($backups) > $limit) {
                 pb_backupbuddy::status('details', 'Dropbox backup file count of `' . count($backups) . '` exceeds limit of `' . $limit . '`.');
                 $i = 0;
                 $delete_fail_count = 0;
                 foreach ($backups as $buname => $butime) {
                     $i++;
                     if ($i > $limit) {
                         if (!$dropbuddy->delete($buname)) {
                             // Try to delete backup on Dropbox. Increment failure count if unable to.
                             pb_backupbuddy::status('details', 'Unable to delete excess Dropbox file: `' . $buname . '`');
                             $delete_fail_count++;
                         }
                     }
                 }
                 if ($delete_fail_count !== 0) {
                     backupbuddy_core::mail_error(sprintf(__('Dropbox remote limit could not delete %s backups.', 'it-l10n-backupbuddy'), $delete_fail_count));
                 }
             }
         } else {
             pb_backupbuddy::status('details', 'No Dropbox file limit to enforce.');
         }
         // End remote backup limit
     }
     // end foreach.
     pb_backupbuddy::status('details', 'All files sent.');
     return true;
     // Success if made it this far.
 }
Esempio n. 22
0
 public static function send($settings = array(), $files = array(), $send_id = '')
 {
     global $pb_backupbuddy_destination_errors;
     if ('1' == $settings['disabled']) {
         $pb_backupbuddy_destination_errors[] = __('Error #48933: This destination is currently disabled. Enable it under this destination\'s Advanced Settings.', 'it-l10n-backupbuddy');
         return false;
     }
     if (!is_array($files)) {
         $files = array($files);
     }
     pb_backupbuddy::status('details', 'FTP class send() function started.');
     self::_init();
     // Connect to server.
     $server = $settings['address'];
     $port = '22';
     // Default sFTP port.
     if (strstr($server, ':')) {
         // Handle custom sFTP port.
         $server_params = explode(':', $server);
         $server = $server_params[0];
         $port = $server_params[1];
     }
     pb_backupbuddy::status('details', 'Connecting to sFTP server...');
     $sftp = new Net_SFTP($server, $port);
     if (!$sftp->login($settings['username'], $settings['password'])) {
         pb_backupbuddy::status('error', 'Connection to sFTP server FAILED.');
         pb_backupbuddy::status('details', 'sFTP log (if available & enabled via full logging mode): `' . $sftp->getSFTPLog() . '`.');
         return false;
     } else {
         pb_backupbuddy::status('details', 'Success connecting to sFTP server.');
     }
     pb_backupbuddy::status('details', 'Attempting to create path (if it does not exist)...');
     if (true === $sftp->mkdir($settings['path'])) {
         // Try to make directory.
         pb_backupbuddy::status('details', 'Directory created.');
     } else {
         pb_backupbuddy::status('details', 'Directory not created.');
     }
     // Change to directory.
     pb_backupbuddy::status('details', 'Attempting to change into directory...');
     if (true === $sftp->chdir($settings['path'])) {
         pb_backupbuddy::status('details', 'Changed into directory `' . $settings['path'] . '`. All uploads will be relative to this.');
     } else {
         pb_backupbuddy::status('error', 'Unable to change into specified path. Verify the path is correct with valid permissions.');
         pb_backupbuddy::status('details', 'sFTP log (if available & enabled via full logging mode): `' . $sftp->getSFTPLog() . '`.');
         return false;
     }
     // Upload files.
     $total_transfer_size = 0;
     $total_transfer_time = 0;
     foreach ($files as $file) {
         if (!file_exists($file)) {
             pb_backupbuddy::status('error', 'Error #859485495. Could not upload local file `' . $file . '` to send to sFTP as it does not exist. Verify the file exists, permissions of file, parent directory, and that ownership is correct. You may need suphp installed on the server.');
         }
         if (!is_readable($file)) {
             pb_backupbuddy::status('error', 'Error #8594846548. Could not read local file `' . $file . '` to send to sFTP as it is not readable. Verify permissions of file, parent directory, and that ownership is correct. You may need suphp installed on the server.');
         }
         $filesize = filesize($file);
         $total_transfer_size += $filesize;
         $destination_file = basename($file);
         pb_backupbuddy::status('details', 'About to put to sFTP local file `' . $file . '` of size `' . pb_backupbuddy::$format->file_size($filesize) . '` to remote file `' . $destination_file . '`.');
         $send_time = -microtime(true);
         $upload = $sftp->put($destination_file, $file, NET_SFTP_LOCAL_FILE);
         $send_time += microtime(true);
         $total_transfer_time += $send_time;
         if ($upload === false) {
             // Failed sending.
             $error_message = 'ERROR #9012b ( http://ithemes.com/codex/page/BackupBuddy:_Error_Codes#9012 ).  sFTP file upload failed. Check file permissions & disk quota.';
             pb_backupbuddy::status('error', $error_message);
             backupbuddy_core::mail_error($error_message);
             pb_backupbuddy::status('details', 'sFTP log (if available & enabled via full logging mode): `' . $sftp->getSFTPLog() . '`.');
             return false;
         } else {
             // Success sending.
             pb_backupbuddy::status('details', 'Success completely sending `' . basename($file) . '` to destination.');
             // Start remote backup limit
             if ($settings['archive_limit'] > 0) {
                 pb_backupbuddy::status('details', 'Archive limit enabled. Getting contents of backup directory.');
                 $contents = $sftp->rawlist($settings['path']);
                 // already in destination directory/path.
                 // Create array of backups
                 $bkupprefix = backupbuddy_core::backup_prefix();
                 $backups = array();
                 foreach ($contents as $filename => $backup) {
                     // check if file is backup
                     $pos = strpos($filename, 'backup-' . $bkupprefix . '-');
                     if ($pos !== FALSE) {
                         $backups[] = array('file' => $filename, 'modified' => $backup['mtime']);
                     }
                 }
                 function backupbuddy_number_sort($a, $b)
                 {
                     return $a['modified'] < $b['modified'];
                 }
                 // Sort by modified using custom sort function above.
                 usort($backups, 'backupbuddy_number_sort');
                 if (count($backups) > $settings['archive_limit']) {
                     pb_backupbuddy::status('details', 'More backups found (' . count($backups) . ') than limit permits (' . $settings['archive_limit'] . ').' . print_r($backups, true));
                     $delete_fail_count = 0;
                     $i = 0;
                     foreach ($backups as $backup) {
                         $i++;
                         if ($i > $settings['archive_limit']) {
                             if (false === $sftp->delete($settings['path'] . '/' . $backup['file'])) {
                                 pb_backupbuddy::status('details', 'Unable to delete excess sFTP file `' . $backup['file'] . '` in path `' . $settings['path'] . '`.');
                                 $delete_fail_count++;
                             } else {
                                 pb_backupbuddy::status('details', 'Deleted excess sFTP file `' . $backup['file'] . '` in path `' . $settings['path'] . '`.');
                             }
                         }
                     }
                     if ($delete_fail_count != 0) {
                         backupbuddy_core::mail_error(sprintf(__('sFTP remote limit could not delete %s backups. Please check and verify file permissions.', 'it-l10n-backupbuddy'), $delete_fail_count));
                         pb_backupbuddy::status('error', 'Unable to delete one or more excess backup archives. File storage limit may be exceeded. Manually clean up backups and check permissions.');
                     } else {
                         pb_backupbuddy::status('details', 'No problems encountered deleting excess backups.');
                     }
                 } else {
                     pb_backupbuddy::status('details', 'Not enough backups found to exceed limit. Skipping limit enforcement.');
                 }
             } else {
                 pb_backupbuddy::status('details', 'No sFTP archive file limit to enforce.');
             }
             // End remote backup limit
         }
     }
     // end $files loop.
     // Load destination fileoptions.
     pb_backupbuddy::status('details', 'About to load fileoptions data.');
     require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
     pb_backupbuddy::status('details', 'Fileoptions instance #6.');
     $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
     if (true !== ($result = $fileoptions_obj->is_ok())) {
         pb_backupbuddy::status('error', __('Fatal Error #9034.843498. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
         return false;
     }
     pb_backupbuddy::status('details', 'Fileoptions data loaded.');
     $fileoptions =& $fileoptions_obj->options;
     // Save stats.
     $fileoptions['write_speed'] = $total_transfer_size / $total_transfer_time;
     $fileoptions_obj->save();
     unset($fileoptions_obj);
     return true;
 }
Esempio n. 23
0
File: init.php Progetto: russtx/tac
 public static function send($settings = array(), $files = array(), $send_id = '', $delete_after = false)
 {
     if (!is_array($files)) {
         $files = array($files);
     }
     global $pb_backupbuddy_destination_errors;
     $backup_type_dir = '';
     $region = '';
     $settings['bucket'] = strtolower($settings['bucket']);
     // Buckets must be lowercase.
     if (!is_array($files)) {
         $files = array($files);
     }
     $limit = $settings['archive_limit'];
     $max_chunk_size = $settings['max_chunk_size'];
     $remote_path = self::get_remote_path($settings['directory']);
     // Has leading and trailng slashes.
     if ($settings['ssl'] == '0') {
         $disable_ssl = true;
     } else {
         $disable_ssl = false;
     }
     $multipart_id = $settings['_multipart_id'];
     $multipart_counts = $settings['_multipart_counts'];
     pb_backupbuddy::status('details', 'S3 remote path set to `' . $remote_path . '`.');
     pb_backupbuddy::status('details', 'Loading S3 SDK library file...');
     require_once dirname(dirname(__FILE__)) . '/_s3lib/aws-sdk/sdk.class.php';
     pb_backupbuddy::status('details', 'S3 SDK file loaded.');
     // S3 API talk.
     $manage_data = pb_backupbuddy_destination_s3::get_credentials($settings);
     // Process multipart transfer that we already initiated in a previous PHP load.
     if ($multipart_id != '') {
         // Multipart upload initiated and needs parts sent.
         // Create S3 instance.
         pb_backupbuddy::status('details', 'Creating S3 instance.');
         $s3 = new AmazonS3($manage_data);
         // the key, secret, token
         if ($disable_ssl === true) {
             @$s3->disable_ssl(true);
         }
         pb_backupbuddy::status('details', 'S3 instance created.');
         // Verify bucket exists; create if not. Also set region to the region bucket exists in.
         if (false === self::_prepareBucketAndRegion($s3, $settings)) {
             global $pb_backupbuddy_destination_errors;
             $pb_backupbuddy_destination_errors[] = 'Could not prepare bucket.';
             return false;
         }
         $this_part_number = $settings['_multipart_partnumber'] + 1;
         pb_backupbuddy::status('details', 'S3 beginning upload of part `' . $this_part_number . '` of `' . count($settings['_multipart_counts']) . '` parts of file `' . $settings['_multipart_file'] . '` to remote location `' . $settings['_multipart_remotefile'] . '` with multipart ID `' . $settings['_multipart_id'] . '`.');
         $response = $s3->upload_part($manage_data['bucket'], $settings['_multipart_remotefile'], $settings['_multipart_id'], array('expect' => '100-continue', 'fileUpload' => $settings['_multipart_file'], 'partNumber' => $this_part_number, 'seekTo' => (int) $settings['_multipart_counts'][$settings['_multipart_partnumber']]['seekTo'], 'length' => (int) $settings['_multipart_counts'][$settings['_multipart_partnumber']]['length']));
         if (!$response->isOK()) {
             $this_error = 'S3 unable to upload file part for multipart upload `' . $settings['_multipart_id'] . '`. Details: `' . print_r($response, true) . '`.';
             $pb_backupbuddy_destination_errors[] = $this_error;
             pb_backupbuddy::status('error', $this_error);
             return false;
         } else {
             // Send success.
             pb_backupbuddy::status('details', 'Success sending chunk. Upload details: `' . print_r($response, true) . '`.');
             $uploaded_size = $response->header['_info']['size_upload'];
             $uploaded_speed = $response->header['_info']['speed_upload'];
             pb_backupbuddy::status('details', 'Uploaded size: ' . pb_backupbuddy::$format->file_size($uploaded_size) . ', Speed: ' . pb_backupbuddy::$format->file_size($uploaded_speed) . '/sec.');
         }
         // Load fileoptions to the send.
         pb_backupbuddy::status('details', 'About to load fileoptions data.');
         require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
         pb_backupbuddy::status('details', 'Fileoptions instance #10.');
         $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
         if (true !== ($result = $fileoptions_obj->is_ok())) {
             pb_backupbuddy::status('error', __('Fatal Error #9034.2344848. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
             global $pb_backupbuddy_destination_errors;
             $pb_backupbuddy_destination_errors[] = '#9034.2344848';
             return false;
         }
         pb_backupbuddy::status('details', 'Fileoptions data loaded.');
         $fileoptions =& $fileoptions_obj->options;
         $update_status = 'Sent part ' . $this_part_number . ' of ' . count($settings['_multipart_counts']) . '.';
         // Made it here so success sending part. Increment for next part to send.
         $settings['_multipart_partnumber']++;
         if (!isset($settings['_multipart_counts'][$settings['_multipart_partnumber']])) {
             // No more parts exist for this file. Tell S3 the multipart upload is complete and move on.
             pb_backupbuddy::status('details', 'S3 getting parts with etags to notify S3 of completed multipart send.');
             $etag_parts = $s3->list_parts($manage_data['bucket'], $settings['_multipart_remotefile'], $settings['_multipart_id']);
             pb_backupbuddy::status('details', 'S3 got parts list. Details: ' . print_r($etag_parts, true));
             pb_backupbuddy::status('details', 'Notifying S3 of multipart upload completion.');
             $response = $s3->complete_multipart_upload($manage_data['bucket'], $settings['_multipart_remotefile'], $settings['_multipart_id'], $etag_parts);
             if (!$response->isOK()) {
                 $this_error = 'S3 unable to notify S3 of completion of all parts for multipart upload `' . $settings['_multipart_id'] . '`.';
                 global $pb_backupbuddy_destination_errors;
                 $pb_backupbuddy_destination_errors[] = $this_error;
                 pb_backupbuddy::status('error', $this_error);
                 return false;
             } else {
                 pb_backupbuddy::status('details', 'S3 notified S3 of multipart completion.');
             }
             pb_backupbuddy::status('details', 'S3 has no more parts left for this multipart upload. Clearing multipart instance variables.');
             $settings['_multipart_partnumber'] = 0;
             $settings['_multipart_id'] = '';
             $settings['_multipart_file'] = '';
             $settings['_multipart_remotefile'] = '';
             // Multipart completed so safe to prevent housekeeping of incomplete multipart uploads.
             $settings['_multipart_transferspeeds'][] = $uploaded_speed;
             // Overall upload speed average.
             $uploaded_speed = array_sum($settings['_multipart_transferspeeds']) / count($settings['_multipart_counts']);
             pb_backupbuddy::status('details', 'Upload speed average of all chunks: `' . pb_backupbuddy::$format->file_size($uploaded_speed) . '`.');
             $settings['_multipart_counts'] = array();
             // Update stats.
             $fileoptions['_multipart_status'] = $update_status;
             $fileoptions['finish_time'] = time();
             $fileoptions['status'] = 'success';
             if (isset($uploaded_speed)) {
                 $fileoptions['write_speed'] = $uploaded_speed;
             }
             $fileoptions_obj->save();
             unset($fileoptions);
         }
         // Schedule to continue if anything is left to upload for this multipart of any individual files.
         if ($settings['_multipart_id'] != '' || count($files) > 0) {
             pb_backupbuddy::status('details', 'S3 multipart upload has more parts left. Scheduling next part send.');
             $cronTime = time();
             $cronArgs = array($settings, $files, $send_id, $delete_after);
             $cronHashID = md5($cronTime . serialize($cronArgs));
             $cronArgs[] = $cronHashID;
             $schedule_result = backupbuddy_core::schedule_single_event($cronTime, pb_backupbuddy::cron_tag('destination_send'), $cronArgs);
             if (true === $schedule_result) {
                 pb_backupbuddy::status('details', 'Next S3 chunk step cron event scheduled.');
             } else {
                 pb_backupbuddy::status('error', 'Next S3 chunk step cron even FAILED to be scheduled.');
             }
             spawn_cron(time() + 150);
             // Adds > 60 seconds to get around once per minute cron running limit.
             update_option('_transient_doing_cron', 0);
             // Prevent cron-blocking for next item.
             return array($settings['_multipart_id'], 'Sent part ' . $this_part_number . ' of ' . count($settings['_multipart_counts']) . ' parts.');
         }
     }
     // end if multipart continuation.
     require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
     // Upload each file.
     foreach ($files as $file_id => $file) {
         // Determine backup type directory (if zip).
         $backup_type_dir = '';
         $backup_type = '';
         if (stristr($file, '.zip') !== false) {
             // If a zip try to determine backup type.
             pb_backupbuddy::status('details', 'S3: Zip file. Detecting backup type if possible.');
             $serial = backupbuddy_core::get_serial_from_file($file);
             // See if we can get backup type from fileoptions data.
             pb_backupbuddy::status('details', 'Fileoptions instance #9.');
             $backup_options = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/' . $serial . '.txt', $read_only = true, $ignore_lock = true);
             if (true !== ($result = $backup_options->is_ok())) {
                 pb_backupbuddy::status('error', 'Unable to open fileoptions file `' . backupbuddy_core::getLogDirectory() . 'fileoptions/' . $serial . '.txt' . '`.');
             } else {
                 if (isset($backup_options->options['integrity']['detected_type'])) {
                     pb_backupbuddy::status('details', 'S3: Detected backup type as `' . $backup_options->options['integrity']['detected_type'] . '` via integrity check data.');
                     //$backup_type_dir = $backup_options->options['integrity']['detected_type'] . '/';
                     $backup_type = $backup_options->options['integrity']['detected_type'];
                 }
             }
             // If still do not know backup type then attempt to deduce it from filename.
             if ($backup_type == '') {
                 if (stristr($file, '-db-') !== false) {
                     pb_backupbuddy::status('details', 'S3: Detected backup type as `db` via filename.');
                     //$backup_type_dir = 'db/';
                     $backup_type = 'db';
                 } elseif (stristr($file, '-full-') !== false) {
                     pb_backupbuddy::status('details', 'S3: Detected backup type as `full` via filename.');
                     //$backup_type_dir = 'full/';
                     $backup_type = 'full';
                 } else {
                     pb_backupbuddy::status('details', 'S3: Could not detect backup type via integrity details nor filename.');
                 }
             }
         }
         $credentials = pb_backupbuddy_destination_s3::get_credentials($settings);
         // Create S3 instance.
         pb_backupbuddy::status('details', 'Creating S3 instance.');
         $s3 = new AmazonS3($credentials);
         // the key, secret, token
         if ($disable_ssl === true) {
             @$s3->disable_ssl(true);
         }
         pb_backupbuddy::status('details', 'S3 instance created.');
         // Verify bucket exists; create if not. Also set region to the region bucket exists in.
         if (false === self::_prepareBucketAndRegion($s3, $settings)) {
             global $pb_backupbuddy_destination_errors;
             $pb_backupbuddy_destination_errors[] = 'Could not prepare bucket.';
             return false;
         }
         // Handle chunking of file into a multipart upload (if applicable).
         $file_size = filesize($file);
         if ($max_chunk_size >= self::MINIMUM_CHUNK_SIZE && $file_size / 1024 / 1024 > $max_chunk_size) {
             // minimum chunk size is 5mb. Anything under 5mb we will not chunk.
             // About to chunk so cleanup any previous hanging multipart transfers.
             self::multipart_cleanup($settings, $lessLogs = false);
             pb_backupbuddy::status('details', 'S3 file size of ' . pb_backupbuddy::$format->file_size($file_size) . ' exceeds max chunk size of ' . $max_chunk_size . 'MB set in settings for sending file as multipart upload.');
             // Initiate multipart upload with S3.
             pb_backupbuddy::status('details', 'Initiating S3 multipart upload.');
             $response = $s3->initiate_multipart_upload($settings['bucket'], $remote_path . $backup_type_dir . basename($file), array('encryption' => 'AES256'));
             if (!$response->isOK()) {
                 $this_error = 'S3 was unable to initiate multipart upload.';
                 global $pb_backupbuddy_destination_errors;
                 $pb_backupbuddy_destination_errors[] = $this_error;
                 pb_backupbuddy::status('error', $this_error);
                 return false;
             } else {
                 $upload_id = (string) $response->body->UploadId;
                 pb_backupbuddy::status('details', 'S3 initiated multipart upload with ID `' . $upload_id . '`.');
             }
             // Get chunk parts for multipart transfer.
             pb_backupbuddy::status('details', 'S3 getting multipart counts.');
             $parts = $s3->get_multipart_counts($file_size, $max_chunk_size * 1024 * 1024);
             // Size of chunks expected to be in bytes.
             $multipart_destination_settings = $settings;
             $multipart_destination_settings['_multipart_id'] = $upload_id;
             $multipart_destination_settings['_multipart_partnumber'] = 0;
             $multipart_destination_settings['_multipart_file'] = $file;
             $multipart_destination_settings['_multipart_remotefile'] = $remote_path . basename($file);
             $multipart_destination_settings['_multipart_counts'] = $parts;
             pb_backupbuddy::status('details', 'S3 multipart settings to pass:'******'details', 'S3 scheduling send of next part(s).');
             $cronTime = time();
             $cronArgs = array($multipart_destination_settings, $files, $send_id, $delete_after);
             $cronHashID = md5($cronTime . serialize($cronArgs));
             $cronArgs[] = $cronHashID;
             backupbuddy_core::schedule_single_event($cronTime, pb_backupbuddy::cron_tag('destination_send'), $cronArgs);
             spawn_cron(time() + 150);
             // Adds > 60 seconds to get around once per minute cron running limit.
             update_option('_transient_doing_cron', 0);
             // Prevent cron-blocking for next item.
             pb_backupbuddy::status('details', 'S3 scheduled send of next part(s). Done for this cycle.');
             return array($upload_id, 'Starting send of ' . count($multipart_destination_settings['_multipart_counts']) . ' parts.');
         } else {
             // did not meet chunking criteria.
             if ($max_chunk_size != '0') {
                 if ($file_size / 1024 / 1024 > self::MINIMUM_CHUNK_SIZE) {
                     pb_backupbuddy::status('details', 'File size of ' . pb_backupbuddy::$format->file_size($file_size) . ' is less than the max chunk size of ' . $max_chunk_size . 'MB; not chunking into multipart upload.');
                 } else {
                     pb_backupbuddy::status('details', 'File size of ' . pb_backupbuddy::$format->file_size($file_size) . ' is less than the minimum allowed chunk size of ' . self::MINIMUM_CHUNK_SIZE . 'MB; not chunking into multipart upload.');
                 }
             } else {
                 pb_backupbuddy::status('details', 'Max chunk size set to zero so not chunking into multipart upload.');
             }
         }
         // SEND file.
         if ('standard' == $settings['storage']) {
             $storageVal = AmazonS3::STORAGE_STANDARD;
         } elseif ('reduced' == $settings['storage']) {
             $storageVal = AmazonS3::STORAGE_REDUCED;
         } else {
             pb_backupbuddy::status('error', 'Error #854784: Unknown S3 storage type: `' . $settings['storage'] . '`.');
         }
         pb_backupbuddy::status('details', 'About to put (upload) object to S3: `' . $remote_path . $backup_type_dir . basename($file) . '`. Storage type: `' . $settings['storage'] . ' (' . $storageVal . ')`.');
         $response = $s3->create_object($settings['bucket'], $remote_path . $backup_type_dir . basename($file), array('fileUpload' => $file, 'encryption' => 'AES256', 'storage' => $storageVal));
         unset($storageVal);
         // Validate response. On failure notify S3 API that things went wrong.
         if (!$response->isOK()) {
             // Send FAILED.
             $this_error = 'Failure uploading file to S3 storage. Failure details: `' . print_r($response, true) . '`';
             $pb_backupbuddy_destination_errors[] = $this_error;
             pb_backupbuddy::status('error', $this_error);
             return false;
         } else {
             // Send SUCCESS.
             pb_backupbuddy::status('details', 'Success uploading file to S3 storage. Upload details: `' . print_r($response, true) . '`.');
             $uploaded_size = $response->header['_info']['size_upload'];
             $uploaded_speed = $response->header['_info']['speed_upload'];
             pb_backupbuddy::status('details', 'Uploaded size: ' . pb_backupbuddy::$format->file_size($uploaded_size) . ', Speed: ' . pb_backupbuddy::$format->file_size($uploaded_speed) . '/sec.');
         }
         unset($files[$file_id]);
         // Remove from list of files we have not sent yet.
         pb_backupbuddy::status('details', 'S3 success sending file `' . basename($file) . '`. File uploaded and reported to S3 as completed.');
         // Load destination fileoptions.
         pb_backupbuddy::status('details', 'About to load fileoptions data.');
         require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
         pb_backupbuddy::status('details', 'Fileoptions instance #8.');
         $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
         if (true !== ($result = $fileoptions_obj->is_ok())) {
             pb_backupbuddy::status('error', __('Fatal Error #9034.84838. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
             global $pb_backupbuddy_destination_errors;
             $pb_backupbuddy_destination_errors[] = '#9034.84838';
             return false;
         }
         pb_backupbuddy::status('details', 'Fileoptions data loaded.');
         $fileoptions =& $fileoptions_obj->options;
         // Save stats.
         if (isset($uploaded_speed)) {
             $fileoptions['write_speed'] = $uploaded_speed;
             $fileoptions_obj->save();
         }
         unset($fileoptions_obj);
     }
     // end foreach.
     // BEGIN backup limits.
     if ($limit > 0) {
         pb_backupbuddy::status('details', 'S3 archive limit enforcement to `' . $limit . '` archives beginning.');
         // S3 object for managing files.
         $s3_manage = new AmazonS3($manage_data);
         if ($disable_ssl === true) {
             @$s3_manage->disable_ssl(true);
         }
         if (false === self::_prepareBucketAndRegion($s3_manage, $settings)) {
             global $pb_backupbuddy_destination_errors;
             $pb_backupbuddy_destination_errors[] = 'Could not prepare bucket.';
             return false;
         }
         // Get file listing.
         $response_manage = $s3_manage->list_objects($manage_data['bucket'], array('prefix' => $remote_path . $backup_type_dir));
         // list all the files in the subscriber account
         // Create array of backups and organize by date
         $prefix = backupbuddy_core::backup_prefix();
         // List backups associated with this site by date.
         $backups = array();
         foreach ($response_manage->body->Contents as $object) {
             $file = str_replace($remote_path . $backup_type_dir, '', $object->Key);
             if (FALSE !== stristr($file, '/')) {
                 // CRITICAL CODE! Subdir found due to slash. Do NOT display any files within a deeper subdirectory. Without this files could be deleted not belonging to this destination!
                 continue;
             }
             if (!preg_match(self::BACKUP_FILENAME_PATTERN, $file)) {
                 // CRITICAL CODE! Safety against accidental deletion of non-BB files. Do NOT delete files that do not look like a BackupBuddy backup filename.
                 continue;
             }
             if (FALSE === strpos($file, 'backup-' . $prefix . '-')) {
                 // Not a backup for THIS site. Skip interacting with for limits.
                 continue;
             }
             // S3 stores files in a directory per site so no need to check prefix here! if ( false !== strpos( $file, 'backup-' . $prefix . '-' ) ) { // if backup has this site prefix...
             $backups[$file] = strtotime($object->LastModified);
         }
         arsort($backups);
         pb_backupbuddy::status('details', 'S3 found `' . count($backups) . '` backups when checking archive limits.');
         if (count($backups) > $limit) {
             pb_backupbuddy::status('details', 'More archives (' . count($backups) . ') than limit (' . $limit . ') allows. Trimming...');
             $i = 0;
             $delete_fail_count = 0;
             foreach ($backups as $buname => $butime) {
                 $i++;
                 if ($i > $limit) {
                     pb_backupbuddy::status('details', 'Trimming excess file `' . $buname . '`...');
                     $response = $s3_manage->delete_object($manage_data['bucket'], $remote_path . $backup_type_dir . $buname);
                     if (!$response->isOK()) {
                         pb_backupbuddy::status('details', 'Unable to delete excess S3 file `' . $buname . '`. Details: `' . print_r($response, true) . '`.');
                         $delete_fail_count++;
                     }
                 }
             }
             pb_backupbuddy::status('details', 'Finished trimming excess backups.');
             if ($delete_fail_count !== 0) {
                 $error_message = 'S3 remote limit could not delete ' . $delete_fail_count . ' backups.';
                 pb_backupbuddy::status('error', $error_message);
                 backupbuddy_core::mail_error($error_message);
             }
         }
         pb_backupbuddy::status('details', 'S3 completed archive limiting.');
     } else {
         pb_backupbuddy::status('details', 'No S3 archive file limit to enforce.');
     }
     // End remote backup limit
     // END backup limits.
     if (isset($fileoptions_obj)) {
         unset($fileoptions_obj);
     }
     // Success if we made it this far.
     return true;
 }
Esempio n. 24
0
 public static function send($settings = array(), $files = array(), $send_id = '', $clear_uploads = false)
 {
     global $pb_backupbuddy_destination_errors;
     if (!is_array($files)) {
         $files = array($files);
     }
     if ($clear_uploads === false) {
         // Uncomment the following line to override and always clear.
         //$clear_uploads = true;
     }
     $itxapi_username = $settings['itxapi_username'];
     $itxapi_password = $settings['itxapi_password'];
     $db_archive_limit = $settings['db_archive_limit'];
     $full_archive_limit = $settings['full_archive_limit'];
     $files_archive_limit = $settings['files_archive_limit'];
     $max_chunk_size = $settings['max_chunk_size'];
     $remote_path = self::get_remote_path($settings['directory']);
     // Has leading and trailng slashes.
     if ($settings['ssl'] == '0') {
         $disable_ssl = true;
     } else {
         $disable_ssl = false;
     }
     $multipart_id = $settings['_multipart_id'];
     $multipart_counts = $settings['_multipart_counts'];
     pb_backupbuddy::status('details', 'Stash remote path set to `' . $remote_path . '`.');
     require_once dirname(__FILE__) . '/lib/class.itx_helper.php';
     require_once dirname(dirname(__FILE__)) . '/_s3lib/aws-sdk/sdk.class.php';
     // Stash API talk.
     $stash = new ITXAPI_Helper(pb_backupbuddy_destination_stash::ITXAPI_KEY, pb_backupbuddy_destination_stash::ITXAPI_URL, $itxapi_username, $itxapi_password);
     $manage_data = pb_backupbuddy_destination_stash::get_manage_data($settings);
     if (!is_array($manage_data['credentials'])) {
         pb_backupbuddy::status('error', 'Error #8484383b: Your authentication credentials for Stash failed. Verify your login and password to Stash. You may need to update the Stash destination settings. Perhaps you recently changed your password?');
         return false;
     }
     // Wipe all current uploads.
     if ($clear_uploads === true) {
         pb_backupbuddy::status('details', 'Clearing any current uploads via Stash call to `abort-all`.');
         $abort_url = $stash->get_upload_url(null, 'abort-all');
         $request = new RequestCore($abort_url);
         $response = $request->send_request(true);
     }
     // Process multipart transfer that we already initiated in a previous PHP load.
     if ($multipart_id != '') {
         // Multipart upload initiated and needs parts sent.
         // Create S3 instance.
         pb_backupbuddy::status('details', 'Creating Stash S3 instance.');
         $s3 = new AmazonS3($settings['_multipart_upload_data']['credentials']);
         // the key, secret, token
         if ($disable_ssl === true) {
             @$s3->disable_ssl(true);
         }
         pb_backupbuddy::status('details', 'Stash S3 instance created.');
         $backup_type = str_replace('/', '', $settings['_multipart_backup_type_dir']);
         // For use later by file limiting.
         $this_part_number = $settings['_multipart_partnumber'] + 1;
         pb_backupbuddy::status('details', 'Stash beginning upload of part `' . $this_part_number . '` of `' . count($settings['_multipart_counts']) . '` parts of file `' . $settings['_multipart_file'] . '` with multipart ID `' . $settings['_multipart_id'] . '`.');
         $response = $s3->upload_part($settings['_multipart_upload_data']['bucket'], $settings['_multipart_upload_data']['object'], $settings['_multipart_id'], array('expect' => '100-continue', 'fileUpload' => $settings['_multipart_file'], 'partNumber' => $this_part_number, 'seekTo' => (int) $settings['_multipart_counts'][$settings['_multipart_partnumber']]['seekTo'], 'length' => (int) $settings['_multipart_counts'][$settings['_multipart_partnumber']]['length']));
         if (!$response->isOK()) {
             $this_error = 'Stash unable to upload file part for multipart upload `' . $settings['_multipart_id'] . '`. Details: `' . print_r($response, true) . '`.';
             $pb_backupbuddy_destination_errors[] = $this_error;
             pb_backupbuddy::status('error', $this_error);
             return false;
         } else {
             $uploaded_size = $response->header['_info']['size_upload'];
             $uploaded_speed = $response->header['_info']['speed_upload'];
             pb_backupbuddy::status('details', 'Uploaded size: ' . pb_backupbuddy::$format->file_size($uploaded_size) . ', Speed: ' . pb_backupbuddy::$format->file_size($uploaded_speed) . '/sec.');
         }
         // Load fileoptions to the send.
         pb_backupbuddy::status('details', 'About to load fileoptions data.');
         require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
         $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
         if (true !== ($result = $fileoptions_obj->is_ok())) {
             pb_backupbuddy::status('error', __('Fatal Error #9034.2344848. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
             return false;
         }
         pb_backupbuddy::status('details', 'Fileoptions data loaded.');
         $fileoptions =& $fileoptions_obj->options;
         $update_status = 'Sent part ' . $this_part_number . ' of ' . count($settings['_multipart_counts']) . '.';
         // Made it here so success sending part. Increment for next part to send.
         $settings['_multipart_partnumber']++;
         if (!isset($settings['_multipart_counts'][$settings['_multipart_partnumber']])) {
             // No more parts exist for this file. Tell S3 the multipart upload is complete and move on.
             pb_backupbuddy::status('details', 'Stash getting parts with etags to notify S3 of completed multipart send.');
             $etag_parts = $s3->list_parts($settings['_multipart_upload_data']['bucket'], $settings['_multipart_upload_data']['object'], $settings['_multipart_id']);
             pb_backupbuddy::status('details', 'Stash got parts list. Notifying S3 of multipart upload completion.');
             $response = $s3->complete_multipart_upload($settings['_multipart_upload_data']['bucket'], $settings['_multipart_upload_data']['object'], $settings['_multipart_id'], $etag_parts);
             if (!$response->isOK()) {
                 $this_error = 'Stash unable to notify S3 of completion of all parts for multipart upload `' . $settings['_multipart_id'] . '`.';
                 $pb_backupbuddy_destination_errors[] = $this_error;
                 pb_backupbuddy::status('error', $this_error);
                 return false;
             } else {
                 pb_backupbuddy::status('details', 'Stash notified S3 of multipart completion.');
             }
             $backup_type_dir = $settings['_multipart_backup_type_dir'];
             // Notify Stash API that things were succesful.
             $done_url = $stash->get_upload_url($settings['_multipart_file'], 'done', $remote_path . $backup_type_dir . basename($settings['_multipart_file']));
             pb_backupbuddy::status('details', 'Notifying Stash of completed multipart upload with done url `' . $done_url . '`.');
             $request = new RequestCore($done_url);
             $response = $request->send_request(true);
             if (!$response->isOK()) {
                 $this_error = 'Error #756834682. Could not finalize Stash upload. Response code: `' . $response->get_response_code() . '`; Response body: `' . $response->get_response_body() . '`; Response headers: `' . $response->get_response_header() . '`.';
                 $pb_backupbuddy_destination_errors[] = $this_error;
                 pb_backupbuddy::status('error', $this_error);
                 return false;
             } else {
                 // Good server response.
                 // See if we got an optional json response.
                 $upload_data = @json_decode($response->body, true);
                 if (isset($upload_data['error'])) {
                     $this_error = 'Stash error(s): `' . implode(' - ', $upload_data['error']) . '`.';
                     $pb_backupbuddy_destination_errors[] = $this_error;
                     pb_backupbuddy::status('error', $this_error);
                     return false;
                 }
                 pb_backupbuddy::status('details', 'Stash success sending file `' . basename($settings['_multipart_file']) . '`. File uploaded via multipart across `' . $this_part_number . '` parts and reported to Stash as completed.');
             }
             pb_backupbuddy::status('details', 'Stash has no more parts left for this multipart upload. Clearing multipart instance variables.');
             $settings['_multipart_partnumber'] = 0;
             $settings['_multipart_id'] = '';
             $settings['_multipart_file'] = '';
             $settings['_multipart_upload_data'] = array();
             $settings['_multipart_transferspeeds'][] = $uploaded_speed;
             // Overall upload speed average.
             $uploaded_speed = array_sum($settings['_multipart_transferspeeds']) / count($settings['_multipart_counts']);
             pb_backupbuddy::status('details', 'Upload speed average of all chunks: `' . pb_backupbuddy::$format->file_size($uploaded_speed) . '`.');
             $settings['_multipart_counts'] = array();
             // Update stats.
             $fileoptions['_multipart_status'] = $update_status;
             $fileoptions['finish_time'] = time();
             $fileoptions['status'] = 'success';
             if (isset($uploaded_speed)) {
                 $fileoptions['write_speed'] = $uploaded_speed;
             }
             $fileoptions_obj->save();
             unset($fileoptions);
         }
         delete_transient('pb_backupbuddy_stashquota_' . $settings['itxapi_username']);
         // Delete quota transient since it probably has changed now.
         // Schedule to continue if anything is left to upload for this multipart of any individual files.
         if ($settings['_multipart_id'] != '' || count($files) > 0) {
             pb_backupbuddy::status('details', 'Stash multipart upload has more parts left. Scheduling next part send.');
             $schedule_result = backupbuddy_core::schedule_single_event(time(), pb_backupbuddy::cron_tag('destination_send'), array($settings, $files, $send_id));
             if (true === $schedule_result) {
                 pb_backupbuddy::status('details', 'Next Stash chunk step cron event scheduled.');
             } else {
                 pb_backupbuddy::status('error', 'Next Stash chunk step cron even FAILED to be scheduled.');
             }
             spawn_cron(time() + 150);
             // Adds > 60 seconds to get around once per minute cron running limit.
             update_option('_transient_doing_cron', 0);
             // Prevent cron-blocking for next item.
             return array($settings['_multipart_id'], 'Sent part ' . $this_part_number . ' of ' . count($settings['_multipart_counts']) . ' parts.');
         }
     }
     // end if multipart continuation.
     require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
     // Upload each file.
     foreach ($files as $file_id => $file) {
         // Determine backup type directory (if zip).
         $backup_type_dir = '';
         $backup_type = '';
         if (stristr($file, '.zip') !== false) {
             // If a zip try to determine backup type.
             pb_backupbuddy::status('details', 'Stash: Zip file. Detecting backup type if possible.');
             $serial = backupbuddy_core::get_serial_from_file($file);
             // See if we can get backup type from fileoptions data.
             $backup_options = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/' . $serial . '.txt', $read_only = true, $ignore_lock = true);
             if (true !== ($result = $backup_options->is_ok())) {
                 pb_backupbuddy::status('error', 'Unable to open fileoptions file `' . backupbuddy_core::getLogDirectory() . 'fileoptions/' . $serial . '.txt' . '`.');
             } else {
                 if (isset($backup_options->options['integrity']['detected_type'])) {
                     pb_backupbuddy::status('details', 'Stash: Detected backup type as `' . $backup_options->options['integrity']['detected_type'] . '` via integrity check data.');
                     $backup_type_dir = $backup_options->options['integrity']['detected_type'] . '/';
                     $backup_type = $backup_options->options['integrity']['detected_type'];
                 }
             }
             // If still do not know backup type then attempt to deduce it from filename.
             if ($backup_type == '') {
                 if (stristr($file, '-db-') !== false) {
                     pb_backupbuddy::status('details', 'Stash: Detected backup type as `db` via filename.');
                     $backup_type_dir = 'db/';
                     $backup_type = 'db';
                 } elseif (stristr($file, '-full-') !== false) {
                     pb_backupbuddy::status('details', 'Stash: Detected backup type as `full` via filename.');
                     $backup_type_dir = 'full/';
                     $backup_type = 'full';
                 } elseif (stristr($file, '-files-') !== false) {
                     pb_backupbuddy::status('details', 'Stash: Detected backup type as `files` via filename.');
                     $backup_type_dir = 'files/';
                     $backup_type = 'files';
                 } else {
                     pb_backupbuddy::status('details', 'Stash: Could not detect backup type via integrity details nor filename.');
                 }
             }
         }
         // Interact with Stash API.
         pb_backupbuddy::status('details', 'Determining Stash upload URL for `' . $file . '`.` with destination remote path `' . $remote_path . $backup_type_dir . basename($file) . '`.');
         $upload_url = $stash->get_upload_url($file, 'request', $remote_path . $backup_type_dir . basename($file));
         pb_backupbuddy::status('details', 'Determined upload url: `' . $upload_url . '`.');
         $request = new RequestCore($upload_url);
         pb_backupbuddy::status('details', 'Sending Stash API request.');
         $response = $request->send_request(true);
         // Validate response.
         if (!$response->isOK()) {
             $this_error = 'Stash request for upload credentials failed.';
             $pb_backupbuddy_destination_errors[] = $this_error;
             pb_backupbuddy::status('error', $this_error);
             return false;
         }
         if (!($upload_data = json_decode($response->body, true))) {
             $this_error = 'Stash API did not give a valid JSON response.';
             $pb_backupbuddy_destination_errors[] = $this_error;
             pb_backupbuddy::status('error', $this_error);
             return false;
         }
         if (isset($upload_data['error'])) {
             $this_error = 'Stash error(s): `' . implode(' - ', $upload_data['error']) . '`.';
             $pb_backupbuddy_destination_errors[] = $this_error;
             pb_backupbuddy::status('error', $this_error);
             return false;
         }
         // Create S3 instance.
         pb_backupbuddy::status('details', 'Creating Stash S3 instance.');
         $s3 = new AmazonS3($upload_data['credentials']);
         // the key, secret, token
         if ($disable_ssl === true) {
             @$s3->disable_ssl(true);
         }
         pb_backupbuddy::status('details', 'Stash S3 instance created.');
         // Handle chunking of file into a multipart upload (if applicable).
         $file_size = filesize($file);
         if ($max_chunk_size >= self::MINIMUM_CHUNK_SIZE && $file_size / 1024 / 1024 > $max_chunk_size) {
             // minimum chunk size is 5mb. Anything under 5mb we will not chunk.
             pb_backupbuddy::status('details', 'Stash file size of ' . pb_backupbuddy::$format->file_size($file_size) . ' exceeds max chunk size of ' . $max_chunk_size . 'MB set in settings for sending file as multipart upload.');
             // Initiate multipart upload with S3.
             pb_backupbuddy::status('details', 'Initiating Stash multipart upload.');
             $response = $s3->initiate_multipart_upload($upload_data['bucket'], $upload_data['object'], array('encryption' => 'AES256'));
             if (!$response->isOK()) {
                 $this_error = 'Stash was unable to initiate multipart upload.';
                 $pb_backupbuddy_destination_errors[] = $this_error;
                 pb_backupbuddy::status('error', $this_error);
                 return false;
             } else {
                 $upload_id = (string) $response->body->UploadId;
                 pb_backupbuddy::status('details', 'Stash initiated multipart upload with ID `' . $upload_id . '`.');
             }
             // Get chunk parts for multipart transfer.
             pb_backupbuddy::status('details', 'Stash getting multipart counts.');
             $parts = $s3->get_multipart_counts($file_size, $max_chunk_size * 1024 * 1024);
             // Size of chunks expected to be in bytes.
             $multipart_destination_settings = $settings;
             $multipart_destination_settings['_multipart_id'] = $upload_id;
             $multipart_destination_settings['_multipart_partnumber'] = 0;
             $multipart_destination_settings['_multipart_file'] = $file;
             $multipart_destination_settings['_multipart_counts'] = $parts;
             $multipart_destination_settings['_multipart_upload_data'] = $upload_data;
             $multipart_destination_settings['_multipart_backup_type_dir'] = $backup_type_dir;
             pb_backupbuddy::status('details', 'Stash multipart settings to pass:'******'details', 'Stash scheduling send of next part(s).');
             backupbuddy_core::schedule_single_event(time(), pb_backupbuddy::cron_tag('destination_send'), array($multipart_destination_settings, $files, $send_id));
             spawn_cron(time() + 150);
             // Adds > 60 seconds to get around once per minute cron running limit.
             update_option('_transient_doing_cron', 0);
             // Prevent cron-blocking for next item.
             pb_backupbuddy::status('details', 'Stash scheduled send of next part(s). Done for this cycle.');
             return array($upload_id, 'Starting send of ' . count($multipart_destination_settings['_multipart_counts']) . ' parts.');
         } else {
             // did not meet chunking criteria.
             if ($max_chunk_size != '0') {
                 if ($file_size / 1024 / 1024 > self::MINIMUM_CHUNK_SIZE) {
                     pb_backupbuddy::status('details', 'File size of ' . pb_backupbuddy::$format->file_size($file_size) . ' is less than the max chunk size of ' . $max_chunk_size . 'MB; not chunking into multipart upload.');
                 } else {
                     pb_backupbuddy::status('details', 'File size of ' . pb_backupbuddy::$format->file_size($file_size) . ' is less than the minimum allowed chunk size of ' . self::MINIMUM_CHUNK_SIZE . 'MB; not chunking into multipart upload.');
                 }
             } else {
                 pb_backupbuddy::status('details', 'Max chunk size set to zero so not chunking into multipart upload.');
             }
         }
         // SEND file.
         pb_backupbuddy::status('details', 'About to put (upload) object to Stash.');
         $response = $s3->create_object($upload_data['bucket'], $upload_data['object'], array('fileUpload' => $file, 'encryption' => 'AES256'));
         // Validate response. On failure notify Stash API that things went wrong.
         if (!$response->isOK()) {
             // Send FAILED.
             pb_backupbuddy::status('details', 'Sending upload abort.');
             $request = new RequestCore($abort_url);
             $response = $request->send_request(true);
             $this_error = 'Could not upload to Stash, attempt aborted.';
             $pb_backupbuddy_destination_errors[] = $this_error;
             pb_backupbuddy::status('error', $this_error);
             return false;
         } else {
             // Send SUCCESS.
             pb_backupbuddy::status('details', 'Success uploading file to Stash storage. Notifying Stash API next. Upload details: `' . print_r($response, true) . '`.');
             $uploaded_size = $response->header['_info']['size_upload'];
             $uploaded_speed = $response->header['_info']['speed_upload'];
             pb_backupbuddy::status('details', 'Uploaded size: ' . pb_backupbuddy::$format->file_size($uploaded_size) . ', Speed: ' . pb_backupbuddy::$format->file_size($uploaded_speed) . '/sec.');
         }
         delete_transient('pb_backupbuddy_stashquota_' . $settings['itxapi_username']);
         // Delete quota transient since it probably has changed now.
         // Notify Stash API that things were succesful.
         $done_url = $stash->get_upload_url($file, 'done', $remote_path . $backup_type_dir . basename($file));
         pb_backupbuddy::status('details', 'Notifying Stash of completed upload with done url `' . $done_url . '`.');
         $request = new RequestCore($done_url);
         $response = $request->send_request(true);
         if (!$response->isOK()) {
             $this_error = 'Error #247568834682. Could not finalize Stash upload. Response code: `' . $response->get_response_code() . '`; Response body: `' . $response->get_response_body() . '`; Response headers: `' . $response->get_response_header() . '`.';
             $pb_backupbuddy_destination_errors[] = $this_error;
             pb_backupbuddy::status('error', $this_error);
             return false;
         } else {
             // Good server response.
             // See if we got an optional json response.
             $upload_data = @json_decode($response->body, true);
             if (isset($upload_data['error'])) {
                 // Some kind of error.
                 $this_error = 'Stash error(s): `' . implode(' - ', $upload_data['error']) . '`.';
                 $pb_backupbuddy_destination_errors[] = $this_error;
                 pb_backupbuddy::status('error', $this_error);
                 return false;
             }
             unset($files[$file_id]);
             // Remove from list of files we have not sent yet.
             pb_backupbuddy::status('details', 'Stash success sending file `' . basename($file) . '`. File uploaded and reported to Stash as completed.');
             // Load destination fileoptions.
             pb_backupbuddy::status('details', 'About to load fileoptions data.');
             require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
             $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
             if (true !== ($result = $fileoptions_obj->is_ok())) {
                 pb_backupbuddy::status('error', __('Fatal Error #9034.84838. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
                 return false;
             }
             pb_backupbuddy::status('details', 'Fileoptions data loaded.');
             $fileoptions =& $fileoptions_obj->options;
             // Save stats.
             if (isset($uploaded_speed)) {
                 $fileoptions['write_speed'] = $uploaded_speed;
                 $fileoptions_obj->save();
             }
             //$fileoptions['finish_time'] = time();
             //$fileoptions['status'] = 'success';
             unset($fileoptions_obj);
         }
     }
     // end foreach.
     // BEGIN FILE LIMIT PROCESSING. Enforce archive limits if applicable.
     if ($backup_type == 'full') {
         $limit = $full_archive_limit;
         pb_backupbuddy::status('details', 'Stash full backup archive limit of `' . $limit . '` of type `full` based on destination settings.');
     } elseif ($backup_type == 'db') {
         $limit = $db_archive_limit;
         pb_backupbuddy::status('details', 'Stash database backup archive limit of `' . $limit . '` of type `db` based on destination settings.');
     } elseif ($backup_type == 'files') {
         $limit = $db_archive_limit;
         pb_backupbuddy::status('details', 'Stash database backup archive limit of `' . $limit . '` of type `files` based on destination settings.');
     } else {
         $limit = 0;
         pb_backupbuddy::status('warning', 'Warning #54854895. Stash was unable to determine backup type (reported: `' . $backup_type . '`) so archive limits NOT enforced for this backup.');
     }
     if ($limit > 0) {
         pb_backupbuddy::status('details', 'Stash archive limit enforcement beginning.');
         // S3 object for managing files.
         $s3_manage = new AmazonS3($manage_data['credentials']);
         if ($disable_ssl === true) {
             @$s3_manage->disable_ssl(true);
         }
         // Get file listing.
         $response_manage = $s3_manage->list_objects($manage_data['bucket'], array('prefix' => $manage_data['subkey'] . $remote_path . $backup_type_dir));
         // list all the files in the subscriber account
         // Create array of backups and organize by date
         $prefix = backupbuddy_core::backup_prefix();
         // List backups associated with this site by date.
         $backups = array();
         foreach ($response_manage->body->Contents as $object) {
             $file = str_replace($manage_data['subkey'] . $remote_path . $backup_type_dir, '', $object->Key);
             // Stash stores files in a directory per site so no need to check prefix here! if ( false !== strpos( $file, 'backup-' . $prefix . '-' ) ) { // if backup has this site prefix...
             $backups[$file] = strtotime($object->LastModified);
         }
         arsort($backups);
         pb_backupbuddy::status('details', 'Stash found `' . count($backups) . '` backups of this type when checking archive limits.');
         if (count($backups) > $limit) {
             pb_backupbuddy::status('details', 'More archives (' . count($backups) . ') than limit (' . $limit . ') allows. Trimming...');
             $i = 0;
             $delete_fail_count = 0;
             foreach ($backups as $buname => $butime) {
                 $i++;
                 if ($i > $limit) {
                     pb_backupbuddy::status('details', 'Trimming excess file `' . $buname . '`...');
                     $response = $s3_manage->delete_object($manage_data['bucket'], $manage_data['subkey'] . $remote_path . $backup_type_dir . $buname);
                     if (!$response->isOK()) {
                         pb_backupbuddy::status('details', 'Unable to delete excess Stash file `' . $buname . '`. Details: `' . print_r($response, true) . '`.');
                         $delete_fail_count++;
                     }
                 }
             }
             pb_backupbuddy::status('details', 'Finished trimming excess backups.');
             if ($delete_fail_count !== 0) {
                 $error_message = 'Stash remote limit could not delete ' . $delete_fail_count . ' backups.';
                 pb_backupbuddy::status('error', $error_message);
                 backupbuddy_core::mail_error($error_message);
             }
         }
         pb_backupbuddy::status('details', 'Stash completed archive limiting.');
     } else {
         pb_backupbuddy::status('details', 'No Stash archive file limit to enforce.');
     }
     // End remote backup limit
     if (isset($fileoptions_obj)) {
         unset($fileoptions_obj);
     }
     // END FILE LIMIT PROCESSING.
     // Success if we made it this far.
     return true;
 }
Esempio n. 25
0
 public static function send($destination_settings, $files, $send_id = '')
 {
     if ('' != $send_id) {
         pb_backupbuddy::add_status_serial('remote_send-' . $send_id);
         pb_backupbuddy::status('details', '----- Initiating master send function.');
         require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
         $fileoptions_file = backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt';
         if (!file_exists($fileoptions_file)) {
             pb_backupbuddy::status('details', 'Fileoptions file `' . $fileoptions_file . '` does not exist yet; creating.');
             $fileoptions_obj = new pb_backupbuddy_fileoptions($fileoptions_file, $read_only = false, $ignore_lock = true, $create_file = true);
         } else {
             pb_backupbuddy::status('details', 'Fileoptions file exists; loading.');
             $fileoptions_obj = new pb_backupbuddy_fileoptions($fileoptions_file, $read_only = false, $ignore_lock = false, $create_file = false);
         }
         if (true !== ($result = $fileoptions_obj->is_ok())) {
             pb_backupbuddy::status('error', __('Fatal Error #9034.2344848. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result);
             return false;
         }
         pb_backupbuddy::status('details', 'Fileoptions data loaded.');
         $fileoptions =& $fileoptions_obj->options;
         if ('' == $fileoptions) {
             $fileoptions = backupbuddy_core::get_remote_send_defaults();
             $fileoptions['type'] = $destination_settings['type'];
             if (!is_array($files)) {
                 $fileoptions['file'] = $files;
             } else {
                 $fileoptions['file'] = $files[0];
             }
             $fileoptions_obj->save();
         }
         if (isset($fileoptions['status']) && 'aborted' == $fileoptions['status']) {
             pb_backupbuddy::status('warning', 'Destination send triggered on an ABORTED transfer. Ending send function.');
             return false;
         }
         unset($fileoptions_obj);
     }
     if (false === ($destination = self::_init_destination($destination_settings))) {
         echo '{Error #546893498a. Destination configuration file missing.}';
         if ('' != $send_id) {
             pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
         }
         return false;
     }
     $destination_settings = $destination['settings'];
     // Settings with defaults applied, normalized, etc.
     //$destination_info = $destination['info'];
     if (!is_array($files)) {
         $files = array($files);
     }
     $files_with_sizes = '';
     foreach ($files as $index => $file) {
         if ('' == $file) {
             unset($files[$index]);
             continue;
             // Not actually a file to send.
         }
         if (!file_exists($file)) {
             pb_backupbuddy::status('error', 'Error #58459458743. The file that was attempted to be sent to a remote destination, `' . $file . '`, was not found. It either does not exist or permissions prevent accessing it.');
             if ('' != $send_id) {
                 pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
             }
             return false;
         }
         $files_with_sizes .= $file . ' (' . pb_backupbuddy::$format->file_size(filesize($file)) . '); ';
     }
     pb_backupbuddy::status('details', 'Sending files `' . $files_with_sizes . '` to destination type `' . $destination_settings['type'] . '` titled `' . $destination_settings['title'] . '`.');
     unset($files_with_sizes);
     if (!method_exists($destination['class'], 'send')) {
         pb_backupbuddy::status('error', 'Destination class `' . $destination['class'] . '` does not support send operation -- missing function.');
         if ('' != $send_id) {
             pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
         }
         return false;
     }
     pb_backupbuddy::status('details', 'Calling send function.');
     //$result = $destination_class::send( $destination_settings, $files );
     global $pb_backupbuddy_destination_errors;
     $pb_backupbuddy_destination_errors = array();
     $result = call_user_func_array("{$destination['class']}::send", array($destination_settings, $files, $send_id));
     if ($result === false) {
         $error_details = implode('; ', $pb_backupbuddy_destination_errors);
         backupbuddy_core::mail_error('There was an error sending to the remote destination. One or more files may have not been fully transferred. Please see error details for additional information. If the error persists, enable full error logging and try again for full details and troubleshooting. Details: ' . "\n\n" . $error_details);
     }
     if (is_array($result)) {
         // Send is multipart.
         pb_backupbuddy::status('details', 'Completed send function. Multipart chunk mode. Result: `' . print_r($result, true) . '`.');
         if ('' != $send_id) {
             pb_backupbuddy::status('details', 'About to load fileoptions data.');
             require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php';
             $fileoptions_obj = new pb_backupbuddy_fileoptions(backupbuddy_core::getLogDirectory() . 'fileoptions/send-' . $send_id . '.txt', $read_only = false, $ignore_lock = false, $create_file = false);
             if (true !== ($fileoptions_result = $fileoptions_obj->is_ok())) {
                 pb_backupbuddy::status('error', __('Fatal Error #9034.387462. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $fileoptions_result);
                 return false;
             }
             pb_backupbuddy::status('details', 'Fileoptions data loaded.');
             $fileoptions =& $fileoptions_obj->options;
             $fileoptions['_multipart_status'] = $result[1];
             pb_backupbuddy::status('details', 'Destination debugging details: `' . print_r($fileoptions, true) . '`.');
             $fileoptions_obj->save();
             unset($fileoptions_obj);
             pb_backupbuddy::status('details', 'Next multipart chunk will be sent shortly...');
         }
     } else {
         // Single all-at-once send.
         pb_backupbuddy::status('details', 'Completed send function. Result: `' . $result . '`.');
     }
     if ('' != $send_id) {
         pb_backupbuddy::remove_status_serial('remote_send-' . $send_id);
     }
     return $result;
 }