/** * The main "automatic backup" event. * @access public */ public function run_automatic_backup() { $this->revisr->git = new Revisr_Git(); $this->revisr->db = new Revisr_DB(); $date = date("F j, Y"); $files = $this->revisr->git->status(); $backup_type = ucfirst($this->revisr->options['automatic_backups']); $commit_msg = sprintf(__('%s backup - %s', 'revisr'), $backup_type, $date); // In case there are no files to commit. if ($files == false) { $files = array(); } $this->revisr->git->stage_files($files); $this->revisr->git->commit($commit_msg); $post = array('post_title' => $commit_msg, 'post_content' => '', 'post_type' => 'revisr_commits', 'post_status' => 'publish'); $post_id = wp_insert_post($post); add_post_meta($post_id, 'branch', $this->revisr->git->branch); add_post_meta($post_id, 'commit_hash', $this->revisr->git->current_commit()); add_post_meta($post_id, 'files_changed', count($files)); add_post_meta($post_id, 'committed_files', $files); $this->revisr->db->backup(); add_post_meta($post_id, 'db_hash', $this->revisr->git->current_commit()); $log_msg = sprintf(__('The %s backup was successful.', 'revisr'), $this->revisr->options['automatic_backups']); Revisr_Admin::log($log_msg, 'backup'); }
/** * Sends a new HTTP request to the live site. * @access public */ public function send_request() { $body = array('action' => 'revisr_update'); $args = array('method' => 'POST', 'timeout' => '30', 'redirection' => '5', 'httpversion' => '1.0', 'blocking' => true, 'headers' => array(), 'body' => $body); // Get the URL and send the request. $get_url = revisr()->git->get_config('revisr', 'webhook-url'); if ($get_url !== false) { $webhook = urldecode($get_url); $request = wp_remote_post($webhook, $args); if (is_wp_error($request)) { Revisr_Admin::log(__('Error contacting webhook URL.', 'revisr'), 'error'); } else { Revisr_Admin::log(__('Sent update request to the webhook.', 'revisr'), 'push'); } } }
/** * The main "automatic backup" event. * @access public */ public function run_automatic_backup() { revisr()->git = new Revisr_Git(); revisr()->db = new Revisr_DB(); $backup_type = revisr()->git->get_config('revisr', 'automatic-backups') ? revisr()->git->get_config('revisr', 'automatic-backups') : 'none'; // Make sure backups have been enabled for this environment. if ('none' !== $backup_type) { // Defaults. $date = date("F j, Y"); $files = revisr()->git->status() ? revisr()->git->status() : array(); $commit_msg = sprintf(__('%s backup - %s', 'revisr'), ucfirst($backup_type), $date); // Stage the files and commit. revisr()->git->stage_files($files); revisr()->git->commit($commit_msg); // Backup the DB. revisr()->db->backup(); // Log result - TODO: improve error handling as necessary. $log_msg = sprintf(__('The %s backup was successful.', 'revisr'), $backup_type); Revisr_Admin::log($log_msg, 'backup'); } }
/** * Returns if a push failed. * @access public */ public function null_push($output = '', $args = '') { $msg = __('Error pushing to the remote repository. The remote repository could be ahead, or there may be an authentication issue.', 'revisr'); Revisr_Admin::alert($msg, true); Revisr_Admin::log(__('Error pushing changes to the remote repository.', 'revisr'), 'error'); return; }
/** * Restores the database to an earlier version if it exists. * @access public * @param boolean $restore_branch True if restoring the database from another branch. */ public function restore($restore_branch = false) { if (isset($_GET['revert_db_nonce']) && wp_verify_nonce($_GET['revert_db_nonce'], 'revert_db')) { $branch = $_GET['branch']; if ($branch != $this->branch) { $this->git->checkout($branch); } if ($this->verify_backup() === false) { wp_die(__('The backup file does not exist or has been corrupted.', 'revisr')); } clearstatcache(); $this->backup(); $commit = escapeshellarg($_GET['db_hash']); $current_temp = Revisr_Git::run("log --pretty=format:'%h' -n 1"); $checkout = Revisr_Git::run("checkout {$commit} {$this->upload_dir['basedir']}/{$this->sql_file}", true); if ($checkout !== 1) { exec("{$this->path}mysql {$this->conn} < {$this->sql_file}"); Revisr_Git::run("checkout {$this->branch} {$this->upload_dir['basedir']}/{$this->sql_file}"); if (is_array($current_temp)) { $current_commit = str_replace("'", "", $current_temp); $undo_nonce = wp_nonce_url(admin_url("admin-post.php?action=revert_db&db_hash={$current_commit[0]}&branch={$_GET['branch']}"), 'revert_db', 'revert_db_nonce'); $msg = sprintf(__('Reverted the database to a previous commit. <a href="%s">Undo</a>', 'revisr'), $undo_nonce); Revisr_Admin::log($msg, 'revert'); $redirect = get_admin_url() . "admin.php?page=revisr&revert_db=success&prev_commit={$current_commit[0]}"; wp_redirect($redirect); } else { wp_die(__('Something went wrong. Check your settings and try again.', 'revisr')); } } else { wp_die(__('Failed to revert the database to an earlier commit.', 'revisr')); } } else { if ($restore_branch === true) { exec("{$this->path}mysql {$this->conn} < {$this->sql_file}"); } else { wp_die(__('You are not authorized to perform this action.', 'revisr')); } } }
/** * Processes the request to revert to an earlier commit. * @access public */ public function revert_files($redirect = true) { Revisr_Admin::verify_nonce($_REQUEST['revisr_revert_nonce'], 'revisr_revert_nonce'); $commit = $_REQUEST['commit_hash']; $commit_msg = sprintf(__('Reverted to commit: #%s.', 'revisr'), $commit); revisr()->git->reset('--hard', 'HEAD', true); revisr()->git->reset('--hard', $commit); revisr()->git->reset('--soft', 'HEAD@{1}'); revisr()->git->run('add', array('-A')); revisr()->git->commit($commit_msg); revisr()->git->auto_push(); $commit_url = get_admin_url() . 'admin.php?page=revisr_view_commit&commit=' . $commit; $msg = sprintf(__('Reverted to commit <a href="%s">#%s</a>.', 'revisr'), $commit_url, $commit); $email_msg = sprintf(__('%s was reverted to commit #%s', 'revisr'), get_bloginfo(), $commit); Revisr_Admin::log($msg, 'revert'); Revisr_Admin::notify(get_bloginfo() . __(' - Commit Reverted', 'revisr'), $email_msg); if (true === $redirect) { Revisr_Admin::redirect(); } }
/** * Processes the results and alerts the user as necessary. * @access public * @param array $args An array containing the results of the backup. * @return boolean */ public function callback($args) { if (in_array(false, $args)) { $msg = __('Error backing up the database.', 'revisr'); Revisr_Admin::alert($msg, true); Revisr_Admin::log($msg, 'error'); } else { $msg = __('Successfully backed up the database.', 'revisr'); Revisr_Admin::alert($msg); Revisr_Admin::log($msg, 'backup'); return true; } return false; }
/** * Stages the array of files passed through the New Commit screen. * @access public * @param array $staged_files The files to add/remove */ public function stage_files($staged_files) { $errors = array(); foreach ($staged_files as $result) { $file = substr($result, 3); $status = Revisr_Git::get_status(substr($result, 0, 2)); if ($status == __('Deleted', 'revisr')) { if ($this->run("rm {$file}") === false) { $errors[] = $file; } } else { if ($this->run("add {$file}") === false) { $errors[] = $file; } } } if (!empty($errors)) { $msg = __('There was an error staging the files. Please check the settings and try again.', 'revisr'); Revisr_Admin::alert($msg, true); Revisr_Admin::log(__('Error staging files.', 'revisr'), 'error'); } }
/** * Stages the array of files passed through the New Commit screen. * @access public * @param array $staged_files An array of files to add/remove. * @param boolean $stage_all If set to true, skip the loop and add -A. * @return boolean */ public function stage_files($staged_files, $stage_all = false) { // An empty array for errors. $errors = array(); if (true === $stage_all) { if ($this->run('add', array('-A')) === false) { $errors[] = $staged_files; } } else { foreach ($staged_files as $result) { $file = substr($result, 3); $status = self::get_status(substr($result, 0, 2)); if ($status == __('Deleted', 'revisr')) { if ($this->run('rm', array($file)) === false) { $errors[] = $file; } } else { if ($this->run('add', array($file)) === false) { $errors[] = $file; } } } } if (!empty($errors)) { $msg = __('There was an error staging the files. Please check the settings and try again.', 'revisr'); Revisr_Admin::alert($msg, true); Revisr_Admin::log(__('Error staging files.', 'revisr'), 'error'); return false; } return true; }
/** * Processes the request to revert to an earlier commit. * @access public */ public function process_revert_files($redirect = true) { if (!wp_verify_nonce($_REQUEST['revisr_revert_nonce'], 'revisr_revert_nonce')) { wp_die(__('Cheatin’ uh?', 'revisr')); } $branch = $_REQUEST['branch']; $commit = $_REQUEST['commit_hash']; $commit_msg = sprintf(__('Reverted to commit: #%s.', 'revisr'), $commit); if ($branch != $this->revisr->git->branch) { $this->revisr->git->checkout($branch); } $this->revisr->git->reset('--hard', 'HEAD', true); $this->revisr->git->reset('--hard', $commit); $this->revisr->git->reset('--soft', 'HEAD@{1}'); $this->revisr->git->run('add', array('-A')); $this->revisr->git->commit($commit_msg); $this->revisr->git->auto_push(); $post_url = get_admin_url() . "post.php?post=" . $_REQUEST['post_id'] . "&action=edit"; $msg = sprintf(__('Reverted to commit <a href="%s">#%s</a>.', 'revisr'), $post_url, $commit); $email_msg = sprintf(__('%s was reverted to commit #%s', 'revisr'), get_bloginfo(), $commit); Revisr_Admin::log($msg, 'revert'); Revisr_Admin::notify(get_bloginfo() . __(' - Commit Reverted', 'revisr'), $email_msg); if (true === $redirect) { $redirect = get_admin_url() . "admin.php?page=revisr"; wp_safe_redirect($redirect); } }
/** * Runs an import of all tracked tables, importing any new tables * if tracking all_tables, or providing a link to import new tables * if necessary. * @access public * @param array $tables The tables to import. * @return boolean */ public function import($tables = array()) { // The tables currently being tracked. $tracked_tables = $this->get_tracked_tables(); // Tables that have import files but aren't in the database. $new_tables = $this->get_tables_not_in_db(); // All tables. $all_tables = array_unique(array_merge($new_tables, $tracked_tables)); // The URL to replace during import. $replace_url = $this->revisr->git->get_config('revisr', 'dev-url') ? $this->revisr->git->get_config('revisr', 'dev-url') : ''; if (empty($tables)) { if (!empty($new_tables)) { // If there are new tables that were imported. if (isset($this->revisr->options['db_tracking']) && $this->revisr->options['db_tracking'] == 'all_tables') { // If the user is tracking all tables, import all tables. $import = $this->run('import', $all_tables, $replace_url); } else { // Import only tracked tables, but provide a warning and import link. $import = $this->run('import', $tracked_tables, $replace_url); $url = wp_nonce_url(get_admin_url() . 'admin-post.php?action=import_tables_form&TB_iframe=true&width=350&height=200', 'import_table_form', 'import_nonce'); $msg = sprintf(__('New database tables detected. <a class="thickbox" title="Import Tables" href="%s">Click here</a> to view and import.', 'revisr'), $url); Revisr_Admin::log($msg, 'db'); } } else { // If there are no new tables, go ahead and import the tracked tables. $import = $this->run('import', $tracked_tables, $replace_url); } } else { // Import the provided tables. $import = $this->run('import', $tables, $replace_url); } return $import; }
/** * Adapated from interconnect/it's search/replace script. * * @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/ * * Take a serialised array and unserialise it replacing elements as needed and * unserialising any subordinate arrays and performing the replace on those too. * * @access private * @param string $from String we're looking to replace. * @param string $to What we want it to be replaced with. * @param array $data Used to pass any subordinate arrays back to in. * @param bool $serialised Does the array passed via $data need serialising. * * @return string|array The original array with all elements replaced as needed. */ private function recursive_unserialize_replace($from = '', $to = '', $data = '', $serialised = false) { try { if (is_string($data) && ($unserialized = @unserialize($data)) !== false) { $data = $this->recursive_unserialize_replace($from, $to, $unserialized, true); } elseif (is_array($data)) { $_tmp = array(); foreach ($data as $key => $value) { $_tmp[$key] = $this->recursive_unserialize_replace($from, $to, $value, false); } $data = $_tmp; unset($_tmp); } elseif (is_object($data)) { // $data_class = get_class( $data ); $_tmp = $data; // new $data_class( ); $props = get_object_vars($data); foreach ($props as $key => $value) { $_tmp->{$key} = $this->recursive_unserialize_replace($from, $to, $value, false); } $data = $_tmp; unset($_tmp); } else { if (is_string($data)) { $data = str_replace($from, $to, $data); } } if ($serialised) { return serialize($data); } } catch (Exception $error) { Revisr_Admin::log($error, 'error'); } return $data; }
/** * Processes the request to revert to an earlier commit. * @access public */ public function process_revert() { if (isset($_GET['revert_nonce']) && wp_verify_nonce($_GET['revert_nonce'], 'revert')) { $branch = $_GET['branch']; $commit = $_GET['commit_hash']; $commit_msg = sprintf(__('Reverted to commit: #%s.', 'revisr'), $commit); if ($branch != $this->git->branch) { $this->git->checkout($branch); } $this->git->reset('--hard', 'HEAD', true); $this->git->reset('--hard', $commit); $this->git->reset('--soft', 'HEAD@{1}'); $this->git->run('add -A'); $this->git->commit($commit_msg); $this->git->auto_push(); $post_url = get_admin_url() . "post.php?post=" . $_GET['post_id'] . "&action=edit"; $msg = sprintf(__('Reverted to commit <a href="%s">#%s</a>.', 'revisr'), $post_url, $commit); $email_msg = sprintf(__('%s was reverted to commit #%s', 'revisr'), get_bloginfo(), $commit); Revisr_Admin::log($msg, 'revert'); Revisr_Admin::notify(get_bloginfo() . __(' - Commit Reverted', 'revisr'), $email_msg); $redirect = get_admin_url() . "admin.php?page=revisr"; wp_redirect($redirect); } else { wp_die(__('You are not authorized to access this page.', 'revisr')); } }
/** * Reverts to a specified commit. * @access public */ public function revert() { if (isset($_GET['revert_nonce']) && wp_verify_nonce($_GET['revert_nonce'], 'revert')) { $branch = $_GET['branch']; if ($branch != $this->branch) { $this->checkout($branch); } $commit = $_GET['commit_hash']; $esc_commit = escapeshellarg($commit); $commit_msg = escapeshellarg("Reverted to commit: #{$commit}"); Revisr_Git::run('reset --hard HEAD'); Revisr_Git::run('clean -f -d'); Revisr_Git::run("reset --hard {$esc_commit}"); Revisr_Git::run("reset --soft HEAD@{1}"); Revisr_Git::run("add -A"); Revisr_Git::run("commit -am {$commit_msg}"); $this->auto_push(); $post_url = get_admin_url() . "post.php?post=" . $_GET['post_id'] . "&action=edit"; $msg = sprintf(__('Reverted to commit <a href="%s">#%s</a>.', 'revisr'), $post_url, $commit); $email_msg = sprintf(__('%s was reverted to commit #%s', 'revisr'), get_bloginfo(), $commit); Revisr_Admin::log($msg, 'revert'); Revisr_Admin::notify(get_bloginfo() . __(' - Commit Reverted', 'revisr'), $email_msg); $redirect = get_admin_url() . "admin.php?page=revisr&revert=success&commit={$commit}&id=" . $_GET['post_id']; wp_redirect($redirect); } else { wp_die(__('You are not authorized to access this page.', 'revisr')); } }