public function start($sourceInfo) { $this->_before(__FUNCTION__); $pingTimePre = microtime(true); if (false === ($this->_state['remoteInfo'] = backupbuddy_remote_api::remoteCall($this->_state['destination'], 'getPreDeployInfo', array(), $timeout = 10))) { pb_backupbuddy::alert(implode(', ', backupbuddy_remote_api::getErrors())); return false; } $this->_state['remoteInfo'] = $this->_state['remoteInfo']['data']; $pingTimePost = microtime(true); $this->_state['remoteInfo']['pingTime'] = $pingTimePost - $pingTimePre; // Calculate plugins that do not match. $this->_state['pushPluginFiles'] = $this->calculatePluginDiff($sourceInfo['activePlugins'], $this->_state['remoteInfo']['activePlugins']); $this->_state['pullPluginFiles'] = $this->calculatePluginDiff($this->_state['remoteInfo']['activePlugins'], $sourceInfo['activePlugins']); if ($sourceInfo['activeTheme'] == $this->_state['remoteInfo']['activeTheme']) { // Calculate themes that do not match. $this->_state['pushThemeFiles'] = $this->calculateFileDiff($sourceInfo['themeSignatures'], $this->_state['remoteInfo']['themeSignatures']); $this->_state['pullThemeFiles'] = $this->calculateFileDiff($this->_state['remoteInfo']['themeSignatures'], $sourceInfo['themeSignatures']); } else { $this->_state['sendTheme'] = false; pb_backupbuddy::status('details', 'Different themes. No theme data will be sent.'); } // Calculate media files that do not match. $this->_state['pushMediaFiles'] = $this->calculateFileDiff($sourceInfo['mediaSignatures'], $this->_state['remoteInfo']['mediaSignatures']); // was calculateMediaDiff(). $this->_state['pullMediaFiles'] = $this->calculateFileDiff($this->_state['remoteInfo']['mediaSignatures'], $sourceInfo['mediaSignatures']); // was calculateMediaDiff(). unset($this->_state['remoteInfo']['mediaSignatures']); unset($this->_state['remoteInfo']['themeSignatures']); return true; }
public function start($sourceInfo) { $this->_before(__FUNCTION__); $pingTimePre = microtime(true); if (false === ($this->_state['remoteInfo'] = backupbuddy_remote_api::remoteCall($this->_state['destination'], 'getPreDeployInfo', array(), $timeout = 30))) { return $this->_error(implode(', ', backupbuddy_remote_api::getErrors())); } $this->_state['remoteInfo'] = $this->_state['remoteInfo']['data']; $pingTimePost = microtime(true); $this->_state['remoteInfo']['pingTime'] = $pingTimePost - $pingTimePre; // Calculate plugins that do not match. /* $this->_state['pushPluginFiles'] = $this->calculatePluginDiff( $sourceInfo['activePlugins'], $this->_state['remoteInfo']['activePlugins'] ); $this->_state['pullPluginFiles'] = $this->calculatePluginDiff( $this->_state['remoteInfo']['activePlugins'], $sourceInfo['activePlugins'] ); */ $this->_state['pushPluginFiles'] = $this->calculateFileDiff($sourceInfo['pluginSignatures'], $this->_state['remoteInfo']['pluginSignatures']); $this->_state['pullPluginFiles'] = $this->calculateFileDiff($this->_state['remoteInfo']['pluginSignatures'], $sourceInfo['pluginSignatures']); if ($sourceInfo['activeTheme'] == $this->_state['remoteInfo']['activeTheme']) { // Same theme so calculate theme files that do not match. $this->_state['pushThemeFiles'] = $this->calculateFileDiff($sourceInfo['themeSignatures'], $this->_state['remoteInfo']['themeSignatures']); $this->_state['pullThemeFiles'] = $this->calculateFileDiff($this->_state['remoteInfo']['themeSignatures'], $sourceInfo['themeSignatures']); } else { $this->_state['sendTheme'] = false; pb_backupbuddy::status('details', 'Different themes. Theme data will not be sent.'); } // Note: child theme support added in 6.0.0.6 so must check that remote index exists. if (isset($this->_state['remoteInfo']['activeChildTheme']) && $sourceInfo['activeChildTheme'] == $this->_state['remoteInfo']['activeChildTheme']) { // Same child theme so calculate theme files that do not match. $this->_state['pushChildThemeFiles'] = $this->calculateFileDiff($sourceInfo['childThemeSignatures'], $this->_state['remoteInfo']['childThemeSignatures']); $this->_state['pullChildThemeFiles'] = $this->calculateFileDiff($this->_state['remoteInfo']['childThemeSignatures'], $sourceInfo['childThemeSignatures']); } else { $this->_state['sendChildTheme'] = false; pb_backupbuddy::status('details', 'Different child themes. Theme data will not be sent.'); } // Calculate media files that do not match. $this->_state['pushMediaFiles'] = $this->calculateFileDiff($sourceInfo['mediaSignatures'], $this->_state['remoteInfo']['mediaSignatures']); // was calculateMediaDiff(). $this->_state['pullMediaFiles'] = $this->calculateFileDiff($this->_state['remoteInfo']['mediaSignatures'], $sourceInfo['mediaSignatures']); // was calculateMediaDiff(). // Store count of media files. //$sourceInfo['mediaCount'] = count( $sourceInfo['mediaSignatures'] ); //$this->_state['remoteInfo']['mediaCount'] = count( $this->_state['remoteInfo']['mediaSignatures'] ); unset($sourceInfo['mediaSignatures']); unset($sourceInfo['themeSignatures']); unset($sourceInfo['childThemeSignatures']); unset($sourceInfo['pluginSignatures']); unset($this->_state['remoteInfo']['mediaSignatures']); unset($this->_state['remoteInfo']['themeSignatures']); unset($this->_state['remoteInfo']['childThemeSignatures']); unset($this->_state['remoteInfo']['pluginSignatures']); return true; }
backupbuddy_core::cleanup_temp_tables($serial); die('1'); } elseif ('push' == $direction) { // Remote so call API to clean up. require_once pb_backupbuddy::plugin_path() . '/classes/remote_api.php'; $destinationID = pb_backupbuddy::_POST('destinationID'); if (!isset(pb_backupbuddy::$options['remote_destinations'][$destinationID])) { die('Error #8383983: Invalid destination ID `' . htmlentities($destinationID) . '`.'); } $destinationArray = pb_backupbuddy::$options['remote_destinations'][$destinationID]; if ('site' != $destinationArray['type']) { die('Error #8378332: Destination with ID `' . htmlentities($destinationID) . '` not of "site" type.'); } $apiKey = $destinationArray['api_key']; $apiSettings = backupbuddy_remote_api::key_to_array($apiKey); if (false === ($response = backupbuddy_remote_api::remoteCall($apiSettings, 'confirmDeployment', array('serial' => $serial), 10, null, null, null, null, null, null, null, $returnRaw = true))) { $message = 'Error #2378378324. Unable to confirm remote deployment with serial `' . $serial . '` via remote API.'; pb_backupbuddy::status('error', $message); die($message); } else { if (false === ($response = json_decode($response, true))) { $message = 'Error #239872373. Unable to decode remote deployment response with serial `' . $serial . '` via remote API. Remote server response: `' . print_r($response) . '`.'; pb_backupbuddy::status('error', $message); die($message); } if (true === $response['success']) { die('1'); } else { $message = 'Error #839743. Unable to confirm remote deployment with serial `' . $serial . '` via remote API. Server response: `' . print_r($response) . '`.'; pb_backupbuddy::status('error', $message); die($message);
public static function send($settings = array(), $files = array(), $send_id = '', $delete_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); } self::$_timeStart = microtime(true); if (count($files) > 1) { $message = 'Error #84545894585: This destination currently only supports one file per send.'; pb_backupbuddy::status('error', $message); global $pb_backupbuddy_destination_errors; $pb_backupbuddy_destination_errors[] = $message; return false; } require_once pb_backupbuddy::plugin_path() . '/classes/remote_api.php'; $apiSettings = backupbuddy_remote_api::key_to_array($settings['api_key']); if (site_url() == $apiSettings['siteurl']) { $message = 'Error #4389843. You are trying to use this site\'s own API key. You must use the API key from the remote destination site.'; pb_backupbuddy::status('error', $message); global $pb_backupbuddy_destination_errors; $pb_backupbuddy_destination_errors[] = $message; return false; } $apiURL = $apiSettings['siteurl']; $file = $files[0]; $filePath = ''; if ('' != $settings['sendFilePath']) { $filePath = $settings['sendFilePath']; } $maxPayload = $settings['max_payload'] * 1024 * 1024; // Convert to bytes. $encodeReducedPayload = floor(($settings['max_payload'] - $settings['max_payload'] * 0.37) * 1024 * 1024); // Take into account 37% base64 encoding overhead. Convert to bytes. Remove any decimals down via floor. // Open file for reading. if (FALSE === ($fs = @fopen($file, 'r'))) { pb_backupbuddy::status('error', 'Error #438934894: Unable to open file `' . $file . '` for reading.'); return false; } // If chunked resuming then seek to the correct place in the file. if ('' != $settings['resume_point'] && $settings['resume_point'] > 0) { // Resuming send of a partially transferred file. if (0 !== fseek($fs, $settings['resume_point'])) { // Returns 0 on success. pb_backupbuddy::status('error', 'Error #327834783: Failed to seek file to resume point `' . $settings['resume_point'] . '` via fseek().'); return false; } $prevPointer = $settings['resume_point']; } else { // New file send. $size = filesize($file); $encodedSize = $size * 0.37 + $size; pb_backupbuddy::status('details', 'File size of file to send: ' . pb_backupbuddy::$format->file_size($size) . '. After encoding overhead: ' . pb_backupbuddy::$format->file_size($encodedSize)); if ($encodedSize > $maxPayload) { $settings['chunks_total'] = ceil($encodedSize / $maxPayload); // $maxPayload ); pb_backupbuddy::status('details', 'This file + encoding exceeds the maximum per-chunk payload size so will be read in and sent in chunks of ' . $settings['max_payload'] . 'MB (' . $maxPayload . ' bytes) totaling approximately ' . $settings['chunks_total'] . ' chunks.'); } else { pb_backupbuddy::status('details', 'This file + encoding does not exceed per-chunk payload size of ' . $settings['max_payload'] . 'MB (' . $maxPayload . ' bytes) so sending in one pass.'); } $prevPointer = 0; } pb_backupbuddy::status('details', 'Reading in `' . $encodeReducedPayload . '` bytes at a time to send.'); $dataRemains = true; //$loopCount = 0; //$loopTimeSum = 0; // Used for average send time per chunk. while (TRUE === $dataRemains && FALSE !== ($fileData = fread($fs, $encodeReducedPayload))) { // Grab one chunk of data at a time. pb_backupbuddy::status('details', 'Read in file data.'); if (feof($fs)) { pb_backupbuddy::status('details', 'Read to end of file (feof true). No more chunks left after this send.'); $dataRemains = false; } $isFileTest = false; if (false !== stristr(basename($file), 'remote-send-test.php')) { $isFileTest = true; $settings['sendType'] = 'test'; } if (true === $dataRemains) { $isFileDone = false; } else { $isFileDone = true; } if (!isset($size)) { $size = ''; } pb_backupbuddy::status('details', 'Connecting to remote server to send data.'); $response = backupbuddy_remote_api::remoteCall($apiSettings, 'sendFile_' . $settings['sendType'], array(), $settings['max_time'], $file, $fileData, $prevPointer, $isFileTest, $isFileDone, $size, $filePath); unset($fileData); // Free up memory. $settings['chunks_sent']++; if (true === $dataRemains) { // More chunks remain. pb_backupbuddy::status('details', 'Connection finished sending part ' . $settings['chunks_sent'] . ' of ~' . $settings['chunks_total'] . '.'); } else { // No more chunks remain. pb_backupbuddy::status('details', 'Connection finished sending final part ' . $settings['chunks_sent'] . '.'); } if (false === $response) { echo implode(', ', backupbuddy_remote_api::getErrors()) . ' '; pb_backupbuddy::status('error', 'Errors encountered details: ' . implode(', ', backupbuddy_remote_api::getErrors())); global $pb_backupbuddy_destination_errors; $pb_backupbuddy_destination_errors[] = backupbuddy_remote_api::getErrors(); return false; //implode( ', ', backupbuddy_remote_api::getErrors() ); } if (FALSE === ($prevPointer = ftell($fs))) { pb_backupbuddy::status('error', 'Error #438347844: Unable to get ftell pointer of file handle for passing to prevPointer.'); @fclose($fs); return false; } else { pb_backupbuddy::status('details', 'File pointer: `' . $prevPointer . '`.'); } if (true === $dataRemains) { // 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... if (microtime(true) - self::$_timeStart + self::TIME_WIGGLE_ROOM >= $settings['max_time']) { pb_backupbuddy::status('message', 'Approaching limit of available PHP chunking time of `' . $settings['max_time'] . '` sec. Ran for ' . round(microtime(true) - self::$_timeStart, 3) . ' sec. Proceeding to use chunking.'); @fclose($fs); // Tells next chunk where to pick up. $settings['resume_point'] = $prevPointer; // 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, pb_backupbuddy::cron_tag('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 time limit.'); } } else { pb_backupbuddy::status('details', 'No more data remains (eg for chunking) so finishing up.'); } } // end while data remains in file. // Update fileoptions stats. pb_backupbuddy::status('details', 'About to load fileoptions data.'); require_once pb_backupbuddy::plugin_path() . '/classes/fileoptions.php'; pb_backupbuddy::status('details', 'Fileoptions instance #20.'); $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.279327. Unable to access fileoptions data.', 'it-l10n-backupbuddy') . ' Error: ' . $result); return false; } pb_backupbuddy::status('details', 'Fileoptions data loaded.'); $fileoptions =& $fileoptions_obj->options; $fileoptions['finish_time'] = microtime(true); $fileoptions['status'] = 'success'; $fileoptions['_multipart_status'] = 'Sent all parts.'; if (isset($uploaded_speed)) { $fileoptions['write_speed'] = $uploaded_speed; } $fileoptions_obj->save(); unset($fileoptions); // Made it this far so completed! pb_backupbuddy::status('message', 'Finished sending file. Took ' . round(microtime(true) - self::$_timeStart, 3) . ' seconds this round.'); pb_backupbuddy::status('deployFileSent', 'File sent.'); return true; }
public function deploy_push_renderImportBuddy($state) { $timeout = 10; pb_backupbuddy::status('details', 'Tell remote server to render importbuddy & place our settings file.'); require_once pb_backupbuddy::plugin_path() . '/classes/deploy.php'; $deploy = new backupbuddy_deploy($state['destinationSettings'], $state); if (false === ($response = backupbuddy_remote_api::remoteCall($state['destination'], 'renderImportBuddy', array('backupFile' => basename($this->_backup['archive_file'])), $state['minimumExecutionTime']))) { pb_backupbuddy::status('error', 'Error #4448985: Unable to render importbuddy via remote API.'); return false; } pb_backupbuddy::status('details', 'Render importbuddy result: `' . print_r($response, true) . '`.'); // Calculate importbuddy URL. $importbuddyPassword = md5(md5($state['destination']['key_public'])); // Double md5 like a rainbow. $importbuddyURLRoot = $state['destination']['siteurl'] . '/importbuddy-' . $response['importFileSerial'] . '.php'; $importbuddyLogURL = $importbuddyURLRoot . '?ajax=getDeployLog&v=' . $importbuddyPassword . '&deploy=true'; //$state['destination']['siteurl'] . '/importbuddy/'?ajax=2&v=' . $importbuddyPassword . '&deploy=true; //status-' . $response['importFileSerial'] . '.txt'; $importbuddyURL = $importbuddyURLRoot . '?ajax=2&v=' . $importbuddyPassword . '&deploy=true&direction=push&file=' . basename($this->_backup['archive_file']); pb_backupbuddy::status('details', 'Load importbuddy at `' . $importbuddyURLRoot . '` with verifier `' . $importbuddyPassword . '`.'); pb_backupbuddy::status('loadImportBuddy', json_encode(array('url' => $importbuddyURL, 'logurl' => $importbuddyLogURL))); // Calculate undo URL. $undoDeployURL = $state['destination']['siteurl'] . '/backupbuddy_deploy_undo-' . $this->_backup['serial'] . '.php'; pb_backupbuddy::status('details', 'To undo deployment of database contents go to the URL: ' . $undoDeployURL); pb_backupbuddy::status('undoDeployURL', $undoDeployURL); $this->_backup_options->options['deployment_log'] = $importbuddyLogURL; $this->_backup_options->save(); pb_backupbuddy::status('details', 'Inserting deploy step to run importbuddy steps on remote server.'); $newStep = array('function' => 'deploy_runningImportBuddy', 'args' => array($state), 'start_time' => 0, 'finish_time' => 0, 'attempts' => 0); $this->insert_next_step($newStep); return true; }
} else { if ('200' == $response['response']['code']) { //error_log( print_r( $response, true ) ); echo $response['body']; } elseif ('404' == $response['response']['code']) { // do nothing } else { pb_backupbuddy::status('error', 'Error retrieving remote deployment log. Response code: `' . $response['response']['code'] . '`.', $serial); } } } elseif ('pull' == $backup['deployment_direction']) { // *** PULL if (false === strpos($backup['deployment_log'], 'http')) { // Get log via API using serial. require_once pb_backupbuddy::plugin_path() . '/classes/remote_api.php'; if (false === ($response = backupbuddy_remote_api::remoteCall($backup['deployment_destination'], 'getBackupStatus', array('serial' => $backup['deployment_log']), 10, null, null, null, null, null, null, null, $returnRaw = true))) { pb_backupbuddy::status('error', 'Error #783283378. Unable to get remove backup status log with serial `' . $backup['deployment_log'] . '` via remote API.', $serial); } else { echo $response; // Check if remote backup has reported it finished. If so then we need to set it locally that it is done. if (false !== strpos($response, 'finish_deploymentPullBackup')) { set_transient('backupbuddy_deployPullBackup_finished', $backup['deployment_log'], time() + 120); // Set transient storing this completion so backup process can check for this in subsequent run. Touching fileoptions would be not recommended at this point due to possible collissions. } } } else { // get log from URL $response = wp_remote_get($backup['deployment_log'], array('method' => 'GET', 'timeout' => 10, 'redirection' => 5, 'httpversion' => '1.0', 'blocking' => true, 'headers' => array(), 'body' => null, 'cookies' => array())); if (is_wp_error($response)) { // Loopback failed. Some kind of error. $error = $response->get_error_message();