array(), 'onedrive' => array(), 'googledrive' => array(), 'googlecloud' => array()); private $php_versions = array('5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0'); private $storage_service_without_settings; private $storage_service_with_partial_settings; /** * Constructor */ public function __construct() { $this->admin_init(); } /** * Get the path to the UI templates directory * * @return String - a filesystem directory path */ public function get_templates_dir() { return apply_filters('updraftplus_templates_dir', UpdraftPlus_Manipulation_Functions::wp_normalize_path(UPDRAFTPLUS_DIR.'/templates')); } private function register_template_directories() { $template_directories = array(); $templates_dir = $this->get_templates_dir(); if ($dh = opendir($templates_dir)) { while (($file = readdir($dh)) !== false) { if ('.' == $file || '..' == $file) continue; if (is_dir($templates_dir.'/'.$file)) { $template_directories[$file] = $templates_dir.'/'.$file; } } closedir($dh); } // This is the optimal hook for most extensions to hook into $this->template_directories = apply_filters('updraftplus_template_directories', $template_directories); } /** * Output, or return, the results of running a template (from the 'templates' directory, unless a filter over-rides it). Templates are run with $updraftplus, $updraftplus_admin and $wpdb set. * * @param String $path - path to the template * @param Boolean $return_instead_of_echo - by default, the template is echo-ed; set this to instead return it * @param Array $extract_these - variables to inject into the template's run context * * @return Void|String */ public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) { if ($return_instead_of_echo) ob_start(); if (preg_match('#^([^/]+)/(.*)$#', $path, $matches)) { $prefix = $matches[1]; $suffix = $matches[2]; if (isset($this->template_directories[$prefix])) { $template_file = $this->template_directories[$prefix].'/'.$suffix; } } if (!isset($template_file)) $template_file = UPDRAFTPLUS_DIR.'/templates/'.$path; $template_file = apply_filters('updraftplus_template', $template_file, $path); do_action('updraftplus_before_template', $path, $template_file, $return_instead_of_echo, $extract_these); if (!file_exists($template_file)) { error_log("UpdraftPlus: template not found: $template_file"); echo __('Error:', 'updraftplus').' '.__('template not found', 'updraftplus')." ($path)"; } else { extract($extract_these); global $updraftplus, $wpdb;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $updraftplus_admin = $this;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable include $template_file; } do_action('updraftplus_after_template', $path, $template_file, $return_instead_of_echo, $extract_these); if ($return_instead_of_echo) return ob_get_clean(); } /** * Add actions for any needed dashboard notices for remote storage services * * @param String|Array $services - a list of services, or single service */ private function setup_all_admin_notices_global($services) { global $updraftplus; if ('googledrive' === $services || (is_array($services) && in_array('googledrive', $services))) { $settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('googledrive'); if (is_wp_error($settings)) { if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = ''; $this->storage_module_option_errors .= "Google Drive (".$settings->get_error_code()."): ".$settings->get_error_message(); add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options')); $updraftplus->log_wp_error($settings, true, true); } elseif (!empty($settings['settings'])) { foreach ($settings['settings'] as $instance_id => $storage_options) { if ((defined('UPDRAFTPLUS_CUSTOM_GOOGLEDRIVE_APP') && UPDRAFTPLUS_CUSTOM_GOOGLEDRIVE_APP) || !empty($storage_options['clientid'])) { if (!empty($storage_options['clientid'])) { $clientid = $storage_options['clientid']; $token = empty($storage_options['token']) ? '' : $storage_options['token']; } if (!empty($clientid) && '' == $token) { if (!in_array($instance_id, $this->auth_instance_ids['googledrive'])) $this->auth_instance_ids['googledrive'][] = $instance_id; if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_googledrive'))) add_action('all_admin_notices', array($this, 'show_admin_warning_googledrive')); } unset($clientid); unset($token); } else { if (empty($storage_options['user_id'])) { if (!in_array($instance_id, $this->auth_instance_ids['googledrive'])) $this->auth_instance_ids['googledrive'][] = $instance_id; if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_googledrive'))) add_action('all_admin_notices', array($this, 'show_admin_warning_googledrive')); } } } } } if ('googlecloud' === $services || (is_array($services) && in_array('googlecloud', $services))) { $settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('googlecloud'); if (is_wp_error($settings)) { if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = ''; $this->storage_module_option_errors .= "Google Cloud (".$settings->get_error_code()."): ".$settings->get_error_message(); add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options')); $updraftplus->log_wp_error($settings, true, true); } elseif (!empty($settings['settings'])) { foreach ($settings['settings'] as $instance_id => $storage_options) { $clientid = $storage_options['clientid']; $token = (empty($storage_options['token'])) ? '' : $storage_options['token']; if (!empty($clientid) && empty($token)) { if (!in_array($instance_id, $this->auth_instance_ids['googlecloud'])) $this->auth_instance_ids['googlecloud'][] = $instance_id; if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_googlecloud'))) add_action('all_admin_notices', array($this, 'show_admin_warning_googlecloud')); } } } } if ('dropbox' === $services || (is_array($services) && in_array('dropbox', $services))) { $settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('dropbox'); if (is_wp_error($settings)) { if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = ''; $this->storage_module_option_errors .= "Dropbox (".$settings->get_error_code()."): ".$settings->get_error_message(); add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options')); $updraftplus->log_wp_error($settings, true, true); } elseif (!empty($settings['settings'])) { foreach ($settings['settings'] as $instance_id => $storage_options) { if (empty($storage_options['tk_access_token'])) { if (!in_array($instance_id, $this->auth_instance_ids['dropbox'])) $this->auth_instance_ids['dropbox'][] = $instance_id; if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_dropbox'))) add_action('all_admin_notices', array($this, 'show_admin_warning_dropbox')); } } } } if ('onedrive' === $services || (is_array($services) && in_array('onedrive', $services))) { $settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('onedrive'); if (is_wp_error($settings)) { if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = ''; $this->storage_module_option_errors .= "OneDrive (".$settings->get_error_code()."): ".$settings->get_error_message(); add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options')); $updraftplus->log_wp_error($settings, true, true); } elseif (!empty($settings['settings'])) { foreach ($settings['settings'] as $instance_id => $storage_options) { if ((defined('UPDRAFTPLUS_CUSTOM_ONEDRIVE_APP') && UPDRAFTPLUS_CUSTOM_ONEDRIVE_APP)) { if (!empty($storage_options['clientid']) && !empty($storage_options['secret']) && empty($storage_options['refresh_token'])) { if (!in_array($instance_id, $this->auth_instance_ids['onedrive'])) $this->auth_instance_ids['onedrive'][] = $instance_id; if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_onedrive'))) add_action('all_admin_notices', array($this, 'show_admin_warning_onedrive')); } elseif (empty($storage_options['refresh_token'])) { if (!in_array($instance_id, $this->auth_instance_ids['onedrive'])) $this->auth_instance_ids['onedrive'][] = $instance_id; if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_onedrive'))) add_action('all_admin_notices', array($this, 'show_admin_warning_onedrive')); } } else { if (empty($storage_options['refresh_token'])) { if (!in_array($instance_id, $this->auth_instance_ids['onedrive'])) $this->auth_instance_ids['onedrive'][] = $instance_id; if (false === has_action('all_admin_notices', array($this, 'show_admin_warning_onedrive'))) add_action('all_admin_notices', array($this, 'show_admin_warning_onedrive')); } } } } } if ('updraftvault' === $services || (is_array($services) && in_array('updraftvault', $services))) { $settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('updraftvault'); if (is_wp_error($settings)) { if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = ''; $this->storage_module_option_errors .= "UpdraftVault (".$settings->get_error_code()."): ".$settings->get_error_message(); add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options')); $updraftplus->log_wp_error($settings, true, true); } elseif (!empty($settings['settings'])) { foreach ($settings['settings'] as $instance_id => $storage_options) { if (empty($storage_options['token']) && empty($storage_options['email'])) { add_action('all_admin_notices', array($this, 'show_admin_warning_updraftvault')); } } } } if ($this->disk_space_check(1048576*35) === false) add_action('all_admin_notices', array($this, 'show_admin_warning_diskspace')); $all_services = UpdraftPlus_Storage_Methods_Interface::get_enabled_storage_objects_and_ids($updraftplus->get_canonical_service_list()); $this->storage_service_without_settings = array(); $this->storage_service_with_partial_settings = array(); foreach ($all_services as $method => $sinfo) { if (empty($sinfo['object']) || empty($sinfo['instance_settings']) || !is_callable(array($sinfo['object'], 'options_exist'))) continue; foreach ($sinfo['instance_settings'] as $opt) { if (!$sinfo['object']->options_exist($opt)) { if (isset($opt['CSRF'])) { $this->storage_service_with_partial_settings[$method] = $updraftplus->backup_methods[$method]; } else { $this->storage_service_without_settings[] = $updraftplus->backup_methods[$method]; } } } } if (!empty($this->storage_service_with_partial_settings)) { add_action('all_admin_notices', array($this, 'show_admin_warning_if_remote_storage_with_partial_setttings')); } if (!empty($this->storage_service_without_settings)) { add_action('all_admin_notices', array($this, 'show_admin_warning_if_remote_storage_settting_are_empty')); } if ($updraftplus->is_restricted_hosting('only_one_backup_per_month')) { add_action('all_admin_notices', array($this, 'show_admin_warning_one_backup_per_month')); } } private function setup_all_admin_notices_udonly($service, $override = false) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Filter use global $updraftplus; if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) { @ini_set('display_errors', 1);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged if (defined('E_DEPRECATED')) { @error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, PHPCompatibility.Constants.NewConstants.e_deprecatedFound -- Ok to ignore } else { @error_reporting(E_ALL & ~E_NOTICE);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } add_action('all_admin_notices', array($this, 'show_admin_debug_warning')); } if (null === UpdraftPlus_Options::get_updraft_option('updraft_interval')) { add_action('all_admin_notices', array($this, 'show_admin_nosettings_warning')); $this->no_settings_warning = true; } // Avoid false positives, by attempting to raise the limit (as happens when we actually do a backup) @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged $max_execution_time = (int) @ini_get('max_execution_time');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged if ($max_execution_time>0 && $max_execution_time<20) { add_action('all_admin_notices', array($this, 'show_admin_warning_execution_time')); } // LiteSpeed has a generic problem with terminating cron jobs if (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false) { if (!is_file(ABSPATH.'.htaccess') || !preg_match('/noabort/i', file_get_contents(ABSPATH.'.htaccess'))) { add_action('all_admin_notices', array($this, 'show_admin_warning_litespeed')); } } if (version_compare($updraftplus->get_wordpress_version(), '3.2', '<')) add_action('all_admin_notices', array($this, 'show_admin_warning_wordpressversion')); // DreamObjects west cluster shutdown warning if ('dreamobjects' === $service || (is_array($service) && in_array('dreamobjects', $service))) { $settings = UpdraftPlus_Storage_Methods_Interface::update_remote_storage_options_format('dreamobjects'); if (is_wp_error($settings)) { if (!isset($this->storage_module_option_errors)) $this->storage_module_option_errors = ''; $this->storage_module_option_errors .= "DreamObjects (".$settings->get_error_code()."): ".$settings->get_error_message(); add_action('all_admin_notices', array($this, 'show_admin_warning_multiple_storage_options')); $updraftplus->log_wp_error($settings, true, true); } elseif (!empty($settings['settings'])) { foreach ($settings['settings'] as $storage_options) { if ('objects-us-west-1.dream.io' == $storage_options['endpoint']) { add_action('all_admin_notices', array($this, 'show_admin_warning_dreamobjects')); } } } } // If the plugin was not able to connect to a UDC account due to lack of licences if (isset($_GET['udc_connect']) && 0 == $_GET['udc_connect']) { add_action('all_admin_notices', array($this, 'show_admin_warning_udc_couldnt_connect')); } } /** * Used to output the information for the next scheduled backup. * moved to function for the ajax saves */ public function next_scheduled_backups_output() { // UNIX timestamp $next_scheduled_backup = wp_next_scheduled('updraft_backup'); if ($next_scheduled_backup) { // Convert to GMT $next_scheduled_backup_gmt = gmdate('Y-m-d H:i:s', $next_scheduled_backup); // Convert to blog time zone $next_scheduled_backup = get_date_from_gmt($next_scheduled_backup_gmt, 'D, F j, Y H:i'); // $next_scheduled_backup = date_i18n('D, F j, Y H:i', $next_scheduled_backup); } else { $next_scheduled_backup = __('Nothing currently scheduled', 'updraftplus'); $files_not_scheduled = true; } $next_scheduled_backup_database = wp_next_scheduled('updraft_backup_database'); if (UpdraftPlus_Options::get_updraft_option('updraft_interval_database', UpdraftPlus_Options::get_updraft_option('updraft_interval')) == UpdraftPlus_Options::get_updraft_option('updraft_interval')) { if (isset($files_not_scheduled)) { $next_scheduled_backup_database = $next_scheduled_backup; $database_not_scheduled = true; } else { $next_scheduled_backup_database = __("At the same time as the files backup", 'updraftplus'); $next_scheduled_backup_database_same_time = true; } } else { if ($next_scheduled_backup_database) { // Convert to GMT $next_scheduled_backup_database_gmt = gmdate('Y-m-d H:i:s', $next_scheduled_backup_database); // Convert to blog time zone $next_scheduled_backup_database = get_date_from_gmt($next_scheduled_backup_database_gmt, 'D, F j, Y H:i'); // $next_scheduled_backup_database = date_i18n('D, F j, Y H:i', $next_scheduled_backup_database); } else { $next_scheduled_backup_database = __('Nothing currently scheduled', 'updraftplus'); $database_not_scheduled = true; } } if (isset($files_not_scheduled) && isset($database_not_scheduled)) { ?> : : '.$next_scheduled_backup.''; } else { echo ''.$next_scheduled_backup.''; } if ($return_instead_of_echo) return ob_get_clean(); } /** * Used to output the information for the next scheduled database backup. * moved to function for the ajax saves * * @param Boolean $return_instead_of_echo Whether to return or echo the results. N.B. More than just the results to echo will be returned * @return Void|String If $return_instead_of_echo parameter is true, It returns html string */ public function next_scheduled_database_backups_output($return_instead_of_echo = false) { if ($return_instead_of_echo) ob_start(); $next_scheduled_backup_database = wp_next_scheduled('updraft_backup_database'); if ($next_scheduled_backup_database) { // Convert to GMT $next_scheduled_backup_database_gmt = gmdate('Y-m-d H:i:s', $next_scheduled_backup_database); // Convert to blog time zone $next_scheduled_backup_database = get_date_from_gmt($next_scheduled_backup_database_gmt, 'D, F j, Y H:i'); $database_not_scheduled = false; } else { $next_scheduled_backup_database = __('Nothing currently scheduled', 'updraftplus'); $database_not_scheduled = true; } if ($database_not_scheduled) { echo ''.$next_scheduled_backup_database.''; } else { echo ''.$next_scheduled_backup_database.''; } if ($return_instead_of_echo) return ob_get_clean(); } /** * Run upon the WP admin_init action */ private function admin_init() { add_action('admin_init', array($this, 'maybe_download_backup_from_email')); add_action('core_upgrade_preamble', array($this, 'core_upgrade_preamble')); add_action('admin_action_upgrade-plugin', array($this, 'admin_action_upgrade_pluginortheme')); add_action('admin_action_upgrade-theme', array($this, 'admin_action_upgrade_pluginortheme')); add_action('admin_head', array($this, 'admin_head')); add_filter((is_multisite() ? 'network_admin_' : '').'plugin_action_links', array($this, 'plugin_action_links'), 10, 2); add_action('wp_ajax_updraft_download_backup', array($this, 'updraft_download_backup')); add_action('wp_ajax_updraft_ajax', array($this, 'updraft_ajax_handler')); add_action('wp_ajax_updraft_ajaxrestore', array($this, 'updraft_ajaxrestore')); add_action('wp_ajax_nopriv_updraft_ajaxrestore', array($this, 'updraft_ajaxrestore')); add_action('wp_ajax_updraft_ajaxrestore_continue', array($this, 'updraft_ajaxrestore')); add_action('wp_ajax_nopriv_updraft_ajaxrestore_continue', array($this, 'updraft_ajaxrestore')); add_action('wp_ajax_plupload_action', array($this, 'plupload_action')); add_action('wp_ajax_plupload_action2', array($this, 'plupload_action2')); add_action('wp_before_admin_bar_render', array($this, 'wp_before_admin_bar_render')); // Add a new Ajax action for saving settings add_action('wp_ajax_updraft_savesettings', array($this, 'updraft_ajax_savesettings')); // Ajax for settings import and export add_action('wp_ajax_updraft_importsettings', array($this, 'updraft_ajax_importsettings')); add_filter('heartbeat_received', array($this, 'process_status_in_heartbeat'), 10, 2); // UpdraftPlus templates $this->register_template_directories(); global $updraftplus, $pagenow; add_filter('updraftplus_dirlist_others', array($updraftplus, 'backup_others_dirlist')); add_filter('updraftplus_dirlist_uploads', array($updraftplus, 'backup_uploads_dirlist')); // First, the checks that are on all (admin) pages: $service = UpdraftPlus_Options::get_updraft_option('updraft_service'); if (UpdraftPlus_Options::user_can_manage()) { $this->print_restore_in_progress_box_if_needed(); // Main dashboard page advert // Since our nonce is printed, make sure they have sufficient credentials if ('index.php' == $pagenow && current_user_can('update_plugins') && (!file_exists(UPDRAFTPLUS_DIR.'/udaddons') || (defined('UPDRAFTPLUS_FORCE_DASHNOTICE') && UPDRAFTPLUS_FORCE_DASHNOTICE))) { $dismissed_until = UpdraftPlus_Options::get_updraft_option('updraftplus_dismisseddashnotice', 0); $backup_dir = $updraftplus->backups_dir_location(); // N.B. Not an exact proxy for the installed time; they may have tweaked the expert option to move the directory $installed = @filemtime($backup_dir.'/index.html');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged $installed_for = time() - $installed; if (($installed && time() > $dismissed_until && $installed_for > 28*86400 && !defined('UPDRAFTPLUS_NOADS_B')) || (defined('UPDRAFTPLUS_FORCE_DASHNOTICE') && UPDRAFTPLUS_FORCE_DASHNOTICE)) { add_action('all_admin_notices', array($this, 'show_admin_notice_upgradead')); } } // Moved out for use with Ajax saving $this->setup_all_admin_notices_global($service); } if (!class_exists('Updraft_Dashboard_News')) include_once(UPDRAFTPLUS_DIR.'/includes/class-updraft-dashboard-news.php'); $news_translations = array( 'product_title' => 'UpdraftPlus', 'item_prefix' => __('UpdraftPlus', 'updraftplus'), 'item_description' => __('UpdraftPlus News', 'updraftplus'), 'dismiss_tooltip' => __('Dismiss all UpdraftPlus news', 'updraftplus'), 'dismiss_confirm' => __('Are you sure you want to dismiss all UpdraftPlus news forever?', 'updraftplus'), ); add_filter('woocommerce_in_plugin_update_message', array($this, 'woocommerce_in_plugin_update_message')); new Updraft_Dashboard_News('https://feeds.feedburner.com/updraftplus/', 'https://updraftplus.com/news/', $news_translations); // New-install admin tour if ((!defined('UPDRAFTPLUS_ENABLE_TOUR') || UPDRAFTPLUS_ENABLE_TOUR) && (!defined('UPDRAFTPLUS_THIS_IS_CLONE') || !UPDRAFTPLUS_THIS_IS_CLONE)) { include_once(UPDRAFTPLUS_DIR.'/includes/updraftplus-tour.php'); } if ('index.php' == $GLOBALS['pagenow'] && UpdraftPlus_Options::user_can_manage()) { add_action('admin_print_footer_scripts', array($this, 'admin_index_print_footer_scripts')); } // Next, the actions that only come on the UpdraftPlus page if (UpdraftPlus_Options::admin_page() != $pagenow || empty($_REQUEST['page']) || 'updraftplus' != $_REQUEST['page']) return; $this->setup_all_admin_notices_udonly($service); global $updraftplus_checkout_embed; if (!class_exists('Updraft_Checkout_Embed')) include_once UPDRAFTPLUS_DIR.'/includes/checkout-embed/class-udp-checkout-embed.php'; // Create an empty list (usefull for testing, thanks to the filter bellow) $checkout_embed_products = array(); // get products from JSON file. $checkout_embed_product_file = UPDRAFTPLUS_DIR.'/includes/checkout-embed/products.json'; if (file_exists($checkout_embed_product_file)) { $checkout_embed_products = json_decode(file_get_contents($checkout_embed_product_file)); } $checkout_embed_products = apply_filters('updraftplus_checkout_embed_products', $checkout_embed_products); if (!empty($checkout_embed_products)) { $updraftplus_checkout_embed = new Updraft_Checkout_Embed( 'updraftplus', // plugin name UpdraftPlus_Options::admin_page_url().'?page=updraftplus', // return url $checkout_embed_products, // products list UPDRAFTPLUS_URL.'/includes' // base_url ); } add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'), 99999); $udp_saved_version = UpdraftPlus_Options::get_updraft_option('updraftplus_version'); if (!$udp_saved_version || $udp_saved_version != $updraftplus->version) { if (!$udp_saved_version) { // udp was newly installed, or upgraded from an older version do_action('updraftplus_newly_installed', $updraftplus->version); } else { // udp was updated or downgraded do_action('updraftplus_version_changed', UpdraftPlus_Options::get_updraft_option('updraftplus_version'), $updraftplus->version); } UpdraftPlus_Options::update_updraft_option('updraftplus_version', $updraftplus->version); } if (isset($_POST['action']) && 'updraft_wipesettings' == $_POST['action'] && isset($_POST['nonce']) && UpdraftPlus_Options::user_can_manage()) { if (wp_verify_nonce($_POST['nonce'], 'updraftplus-wipe-setting-nonce')) $this->wipe_settings(); } } /** * Runs upon the WP action woocommerce_in_plugin_update_message * * @param String $msg - the message that WooCommerce will print * * @return String - filtered value */ public function woocommerce_in_plugin_update_message($msg) { if (time() < UpdraftPlus_Options::get_updraft_option('dismissed_clone_wc_notices_until', 0)) return $msg; return '
'.$msg; } /** * Runs upon the WP action admin_print_footer_scripts if an entitled user is on the main WP dashboard page */ public function admin_index_print_footer_scripts() { if (time() < UpdraftPlus_Options::get_updraft_option('dismissed_clone_php_notices_until', 0)) return; ?> admin_enqueue_scripts(); ?>'.__('This file does not appear to be an UpdraftPlus backup archive (such files are .zip or .gz files which have a name like: backup_(time)_(site name)_(code)_(type).(zip|gz)).', 'updraftplus').'
'.apply_filters('updraftplus_if_foreign_then_premium_message', ''), 'makesure' => __('(make sure that you were trying to upload a zip file previously created by UpdraftPlus)', 'updraftplus'), 'uploaderror' => __('Upload error:', 'updraftplus'), 'notdba' => __('This file does not appear to be an UpdraftPlus encrypted database archive (such files are .gz.crypt files which have a name like: backup_(time)_(site name)_(code)_db.crypt.gz).', 'updraftplus'), 'uploaderr' => __('Upload error', 'updraftplus'), 'followlink' => __('Follow this link to attempt decryption and download the database file to your computer.', 'updraftplus'), 'thiskey' => __('This decryption key will be attempted:', 'updraftplus'), 'unknownresp' => __('Unknown server response:', 'updraftplus'), 'ukrespstatus' => __('Unknown server response status:', 'updraftplus'), 'uploaded' => __('The file was uploaded.', 'updraftplus'), // One of the translators has erroneously changed "Backup" into "Back up" (which means, "reverse" !) 'backupnow' => str_ireplace('Back Up', 'Backup', __('Backup Now', 'updraftplus')), 'cancel' => __('Cancel', 'updraftplus'), 'deletebutton' => __('Delete', 'updraftplus'), 'createbutton' => __('Create', 'updraftplus'), 'uploadbutton' => __('Upload', 'updraftplus'), 'youdidnotselectany' => __('You did not select any components to restore. Please select at least one, and then try again.', 'updraftplus'), 'proceedwithupdate' => __('Proceed with update', 'updraftplus'), 'close' => __('Close', 'updraftplus'), 'restore' => __('Restore', 'updraftplus'), 'downloadlogfile' => __('Download log file', 'updraftplus'), 'automaticbackupbeforeupdate' => __('Automatic backup before update', 'updraftplus'), 'unsavedsettings' => __('You have made changes to your settings, and not saved.', 'updraftplus'), 'saving' => __('Saving...', 'updraftplus'), 'connect' => __('Connect', 'updraftplus'), 'connecting' => __('Connecting...', 'updraftplus'), 'disconnect' => __('Disconnect', 'updraftplus'), 'disconnecting' => __('Disconnecting...', 'updraftplus'), 'counting' => __('Counting...', 'updraftplus'), 'updatequotacount' => __('Update quota count', 'updraftplus'), 'addingsite' => __('Adding...', 'updraftplus'), 'addsite' => __('Add site', 'updraftplus'), // 'resetting' => __('Resetting...', 'updraftplus'), 'creating_please_allow' => __('Creating...', 'updraftplus').(function_exists('openssl_encrypt') ? '' : ' ('.__('your PHP install lacks the openssl module; as a result, this can take minutes; if nothing has happened by then, then you should either try a smaller key size, or ask your web hosting company how to enable this PHP module on your setup.', 'updraftplus').')'), 'sendtosite' => __('Send to site:', 'updraftplus'), 'checkrpcsetup' => sprintf(__('You should check that the remote site is online, not firewalled, does not have security modules that may be blocking access, has UpdraftPlus version %s or later active and that the keys have been entered correctly.', 'updraftplus'), '2.10.3'), 'pleasenamekey' => __('Please give this key a name (e.g. indicate the site it is for):', 'updraftplus'), 'key' => __('Key', 'updraftplus'), 'nokeynamegiven' => sprintf(__("Failure: No %s was given.", 'updraftplus'), __('key name', 'updraftplus')), 'deleting' => __('Deleting...', 'updraftplus'), 'enter_mothership_url' => __('Please enter a valid URL', 'updraftplus'), 'delete_response_not_understood' => __("We requested to delete the file, but could not understand the server's response", 'updraftplus'), 'testingconnection' => __('Testing connection...', 'updraftplus'), 'send' => __('Send', 'updraftplus'), 'migratemodalheight' => class_exists('UpdraftPlus_Addons_Migrator') ? 555 : 300, 'migratemodalwidth' => class_exists('UpdraftPlus_Addons_Migrator') ? 770 : 500, 'download' => _x('Download', '(verb)', 'updraftplus'), 'browse_download_link' => apply_filters('updraftplus_browse_download_link', ''.__("With UpdraftPlus Premium, you can directly download individual files from here.", "updraftplus").''), 'unsavedsettingsbackup' => __('You have made changes to your settings, and not saved.', 'updraftplus')."\n".__('You should save your changes to ensure that they are used for making your backup.', 'updraftplus'), 'unsaved_settings_export' => __('You have made changes to your settings, and not saved.', 'updraftplus')."\n".__('Your export file will be of your displayed settings, not your saved ones.', 'updraftplus'), 'dayselector' => $day_selector, 'mdayselector' => $mday_selector, 'day' => __('day', 'updraftplus'), 'inthemonth' => __('in the month', 'updraftplus'), 'days' => __('day(s)', 'updraftplus'), 'hours' => __('hour(s)', 'updraftplus'), 'weeks' => __('week(s)', 'updraftplus'), 'forbackupsolderthan' => __('For backups older than', 'updraftplus'), 'ud_url' => UPDRAFTPLUS_URL, 'processing' => __('Processing...', 'updraftplus'), 'loading' => __('Loading...', 'updraftplus'), 'pleasefillinrequired' => __('Please fill in the required information.', 'updraftplus'), 'test_settings' => __('Test %s Settings', 'updraftplus'), 'testing_settings' => __('Testing %s Settings...', 'updraftplus'), 'settings_test_result' => __('%s settings test result:', 'updraftplus'), 'nothing_yet_logged' => __('Nothing yet logged', 'updraftplus'), 'import_select_file' => __('You have not yet selected a file to import.', 'updraftplus'), 'import_invalid_json_file' => __('Error: The chosen file is corrupt. Please choose a valid UpdraftPlus export file.', 'updraftplus'), 'updraft_settings_url' => UpdraftPlus_Options::admin_page_url().'?page=updraftplus', 'network_site_url' => network_site_url(), 'importing' => __('Importing...', 'updraftplus'), 'importing_data_from' => __('This will import data from:', 'updraftplus'), 'exported_on' => __('Which was exported on:', 'updraftplus'), 'continue_import' => __('Do you want to carry out the import?', 'updraftplus'), 'complete' => __('Complete', 'updraftplus'), 'backup_complete' => __('The backup has finished running', 'updraftplus'), 'backup_aborted' => __('The backup was aborted', 'updraftplus'), 'remote_delete_limit' => defined('UPDRAFTPLUS_REMOTE_DELETE_LIMIT') ? UPDRAFTPLUS_REMOTE_DELETE_LIMIT : 15, 'remote_files_deleted' => __('remote files deleted', 'updraftplus'), 'http_code' => __('HTTP code:', 'updraftplus'), 'makesure2' => __('The file failed to upload. Please check the following:', 'updraftplus')."\n\n - ".__('Any settings in your .htaccess or web.config file that affects the maximum upload or post size.', 'updraftplus')."\n - ".__('The available memory on the server.', 'updraftplus')."\n - ".__('That you are attempting to upload a zip file previously created by UpdraftPlus.', 'updraftplus')."\n\n".__('Further information may be found in the browser JavaScript console, and the server PHP error logs.', 'updraftplus'), 'zip_file_contents' => __('Browsing zip file', 'updraftplus'), 'zip_file_contents_info' => __('Select a file to view information about it', 'updraftplus'), 'search' => __('Search', 'updraftplus'), 'download_timeout' => __('Unable to download file. This could be caused by a timeout. It would be best to download the zip to your computer.', 'updraftplus'), 'loading_log_file' => __('Loading log file', 'updraftplus'), 'updraftplus_version' => $updraftplus->version, 'updraftcentral_wizard_empty_url' => __('Please enter the URL where your UpdraftCentral dashboard is hosted.'), 'updraftcentral_wizard_invalid_url' => __('Please enter a valid URL e.g http://example.com', 'updraftplus'), 'export_settings_file_name' => 'updraftplus-settings-'.sanitize_title(get_bloginfo('name')).'.json', // For remote storage handlebarsjs template 'remote_storage_options' => $remote_storage_options_and_templates['options'], 'remote_storage_templates' => $remote_storage_options_and_templates['templates'], 'remote_storage_methods' => $backup_methods, 'instance_enabled' => __('Currently enabled', 'updraftplus'), 'instance_disabled' => __('Currently disabled', 'updraftplus'), 'local_upload_started' => __('Local backup upload has started; please check the log file to see the upload progress', 'updraftplus'), 'local_upload_error' => __('You must select at least one remote storage destination to upload this backup set to.', 'updraftplus'), 'already_uploaded' => __('(already uploaded)', 'updraftplus'), 'onedrive_folder_url_warning' => __('Please specify the Microsoft OneDrive folder name, not the URL.', 'updraftplus'), 'updraftcentral_cloud' => __('UpdraftCentral Cloud', 'updraftplus'), 'udc_cloud_connected' => __('Connected. Requesting UpdraftCentral Key.', 'updraftplus'), 'udc_cloud_key_created' => __('Key created. Adding site to UpdraftCentral Cloud.', 'updraftplus'), 'login_successful' => __('Login successful.', 'updraftplus').' '.__('Please follow this link to open %s in a new window.', 'updraftplus'), 'login_successful_short' => __('Login successful; reloading information.', 'updraftplus'), 'registration_successful' => __('Registration successful.', 'updraftplus').' '.__('Please follow this link to open %s in a new window.', 'updraftplus'), 'username_password_required' => __('Both email and password fields are required.', 'updraftplus'), 'valid_email_required' => __('An email is required and needs to be in a valid format.', 'updraftplus'), 'trouble_connecting' => __('Trouble connecting? Try using an alternative method in the advanced security options.', 'updraftplus'), 'checking_tfa_code' => __('Verifying one-time password...', 'updraftplus'), 'perhaps_login' => __('Perhaps you would want to login instead.', 'updraftplus'), 'generating_key' => __('Please wait while the system generates and registers an encryption key for your website with UpdraftCentral Cloud.', 'updraftplus'), 'updraftcentral_cloud_redirect' => __('Please wait while you are redirected to UpdraftCentral Cloud.', 'updraftplus'), 'data_consent_required' => __('You need to read and accept the UpdraftCentral Cloud data and privacy policies before you can proceed.', 'updraftplus'), 'close_wizard' => __('You can also close this wizard.', 'updraftplus'), 'control_udc_connections' => __('For future control of all your UpdraftCentral connections, go to the "Advanced Tools" tab.', 'updraftplus'), 'main_tabs_keys' => array_keys($main_tabs), 'clone_version_warning' => __('Warning: you have selected a lower version than your currently installed version. This may fail if you have components that are incompatible with earlier versions.', 'updraftplus'), 'clone_backup_complete' => __('The clone has been provisioned, and its data has been sent to it. Once the clone has finished deploying it, you will receive an email.', 'updraftplus'), 'clone_backup_aborted' => __('The preparation of the clone data has been aborted.', 'updraftplus'), 'current_clean_url' => UpdraftPlus::get_current_clean_url(), 'exclude_rule_remove_conformation_msg' => __('Are you sure you want to remove this exclusion rule?', 'updraftplus'), 'exclude_select_file_or_folder_msg' => __('Please select a file/folder which you would like to exclude', 'updraftplus'), 'exclude_type_ext_msg' => __('Please enter a file extension, like zip', 'updraftplus'), 'exclude_ext_error_msg' => __('Please enter a valid file extension', 'updraftplus'), 'exclude_type_prefix_msg' => __('Please enter characters that begin the filename which you would like to exclude', 'updraftplus'), 'exclude_prefix_error_msg' => __('Please enter a valid file name prefix', 'updraftplus'), 'duplicate_exclude_rule_error_msg' => __('The exclusion rule which you are trying to add already exists', 'updraftplus'), 'clone_key_required' => __('UpdraftClone key is required.', 'updraftplus'), 'files_new_backup' => __('Include your files in the backup', 'updraftplus'), 'files_incremental_backup' => __('File backup options', 'updraftplus'), 'ajax_restore_invalid_response' => __('HTML was detected in the response. You may have a security module on your webserver blocking the restoration operation.', 'updraftplus'), 'emptyrestorepath' => __('You have not selected a restore path for your chosen backups', 'updraftplus'), 'updraftvault_info' => ''.__('UpdraftVault is our remote storage which works seamlessly with UpdraftPlus.', 'updraftplus') .' '.__('Find out more here.', 'updraftplus').'' .'
' .''.__('Try it - 1 month for $1!', 'updraftplus').'
', 'login_udc_no_licences_short' => __('No UpdraftCentral licences were available. Continuing to connect to account.'), 'credentials' => __('credentials', 'updraftplus'), 'username' => __('Username', 'updraftplus'), 'password' => __('Password', 'updraftplus'), 'last_activity' => __('last activity: %d seconds ago', 'updraftplus'), 'no_recent_activity' => __('no recent activity; will offer resumption after: %d seconds', 'updraftplus'), 'restore_files_progress' => __('Restoring %s1 files out of %s2', 'updraftplus'), 'restore_db_table_progress' => __('Restoring table: %s', 'updraftplus'), 'restore_db_stored_routine_progress' => __('Restoring stored routine: %s', 'updraftplus'), 'finished' => __('Finished', 'updraftplus'), 'begun' => __('Begun', 'updraftplus'), 'maybe_downloading_entities' => __('Downloading backup files if needed', 'updraftplus'), 'preparing_backup_files' => __('Preparing backup files', 'updraftplus'), 'ajax_restore_contact_failed' => __('Attempts by the browser to contact the website failed.', 'updraftplus'), 'ajax_restore_error' => __('Restore error:', 'updraftplus'), 'ajax_restore_404_detected' => ''. __('Warning:', 'updraftplus') . '
' . __('Attempts by the browser to access some pages have returned a "not found (404)" error. This could mean that your .htaccess file has incorrect contents, is missing, or that your webserver is missing an equivalent mechanism.', 'updraftplus'). '
'.__('Missing pages:', 'updraftplus').'
'.__('Backup directory could not be created', 'updraftplus').'...
';
echo '
'.__('Backup directory successfully created.', 'updraftplus').'
'.__('For even more features and personal support, check out ', 'updraftplus').'UpdraftPlus Premium.
' : ""; echo "'.sprintf(__('You have an unfinished restoration operation, begun %s ago.', 'updraftplus'), $time_ago).'
'; $html .= ''; if ($include_form_container) { $enter_credentials_end .= ''; } else { $enter_credentials_end .= ''; } $enter_credentials_end .= '' . __('Processing', 'updraftplus') . '...
'; $enter_credentials_end .= ''; $enter_credentials_end .= $include_form_container ? '' : '
|
|
'.__('Your WordPress install has old directories from its state before you restored/migrated (technical information: these are suffixed with -old). You should press this button to delete them as soon as you have verified that the restoration worked.', 'updraftplus').'
'; } ?> '; } /** * Return cron status information about a specified in-progress job * * @param Boolean|String $job_id - the job to get information about; or, if not specified, all jobs * * @return Array|Boolean - the requested information, or false if it was not found. Format differs depending on whether info on all jobs, or a single job, was requested. */ public function get_cron($job_id = false) { $cron = get_option('cron'); if (!is_array($cron)) $cron = array(); if (false === $job_id) return $cron; foreach ($cron as $time => $job) { if (!isset($job['updraft_backup_resume'])) continue; foreach ($job['updraft_backup_resume'] as $info) { if (isset($info['args'][1]) && $job_id == $info['args'][1]) { global $updraftplus; $jobdata = $updraftplus->jobdata_getarray($job_id); return is_array($jobdata) ? array($time, $jobdata) : false; } } } } /** * Gets HTML describing the active jobs * * @param Boolean $this_job_only A value for $this_job_only also causes something non-empty to always be returned (to allow detection of the job having started on the front-end) * * @return String - the HTML */ private function print_active_jobs($this_job_only = false) { $cron = $this->get_cron(); $ret = ''; foreach ($cron as $time => $job) { if (isset($job['updraft_backup_resume'])) { foreach ($job['updraft_backup_resume'] as $info) { if (isset($info['args'][1])) { $job_id = $info['args'][1]; if (false === $this_job_only || $job_id == $this_job_only) { $ret .= $this->print_active_job($job_id, false, $time, $info['args'][0]); } } } } } // A value for $this_job_only implies that output is required if (false !== $this_job_only && !$ret) { $ret = $this->print_active_job($this_job_only); if ('' == $ret) { global $updraftplus; $log_file = $updraftplus->get_logfile_name($this_job_only); // if the file exists, the backup was booted. Check if the information about completion is found in the log, or if it was modified at least 2 minutes ago. if (file_exists($log_file) && ($updraftplus->found_backup_complete_in_logfile($this_job_only) || (time() - filemtime($log_file)) > 120)) { // The presence of the exact ID matters to the front-end - indicates that the backup job has at least begun $ret = ''.__('Old directories successfully removed.', 'updraftplus').'
',__('Old directory removal failed for some reason. You may want to do this manually.', 'updraftplus').'
'.__('The folder was created, but we had to change its file permissions to 777 (world-writable) to be able to write to it. You should check with your hosting provider that this will not cause any problems', 'updraftplus').'
'; return true; } else { @$wp_filesystem->chmod($default_backup_dir, 0775);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged $show_dir = (0 === strpos($default_backup_dir, ABSPATH)) ? substr($default_backup_dir, strlen(ABSPATH)) : $default_backup_dir; return new WP_Error('writable_error', __('The folder exists, but your webserver does not have permission to write to it.', 'updraftplus').' '.__('You will need to consult with your web hosting provider to find out how to set permissions for a WordPress plugin to write to the directory.', 'updraftplus').' ('.$show_dir.')'); } } return true; } /** * scans the content dir to see if any -old dirs are present * * @param Boolean $print_as_comment Echo information in an HTML comment * @return Boolean */ private function scan_old_dirs($print_as_comment = false) { global $updraftplus; $dirs = scandir(untrailingslashit(WP_CONTENT_DIR)); if (!is_array($dirs)) $dirs = array(); $dirs_u = @scandir($updraftplus->backups_dir_location());// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged if (!is_array($dirs_u)) $dirs_u = array(); foreach (array_merge($dirs, $dirs_u) as $dir) { if (preg_match('/-old$/', $dir)) { if ($print_as_comment) echo ''; return true; } } // No need to scan ABSPATH - we don't backup there if (is_dir(untrailingslashit(WP_PLUGIN_DIR).'-old')) { if ($print_as_comment) echo ''; return true; } return false; } /** * Outputs html for a storage method using the parameters passed in, this version should be removed when all remote storages use the multi version * * @param String $method a list of methods to be used when * @param String $header the table header content * @param String $contents the table contents */ public function storagemethod_row($method, $header, $contents) { ?>$text
$text
'.__('Warning', 'updraftplus').': '.sprintf(__("Your web server's PHP/Curl installation does not support https access. Communications with %s will be unencrypted. Ask your web host to install Curl/SSL in order to gain the ability for encryption (via an add-on).", 'updraftplus'), $service).'
'; } else { $ret .= $this->show_double_warning(''.__('Warning', 'updraftplus').': '.sprintf(__("Your web server's PHP/Curl installation does not support https access. We cannot access %s without this support. Please contact your web hosting provider's support. %s requires Curl+https. Please do not file any support requests; there is no alternative.", 'updraftplus'), $service, $service).'
', $extraclass, false); } } else { $ret .= ''.sprintf(__("Good news: Your site's communications with %s can be encrypted. If you see any errors to do with encryption, then look in the 'Expert Settings' for more help.", 'updraftplus'), $service).'
'; } } if ($echo_instead_of_return) { echo $ret; } else { return $ret; } } /** * Get backup information in HTML format for a specific backup * * @param Array $backup_history all backups history * @param String $key backup timestamp * @param String $nonce backup nonce (job ID) * @param Array|Null $job_data if an array, then use this as the job data (if null, then it will be fetched directly) * * @return string HTML-formatted backup information */ public function raw_backup_info($backup_history, $key, $nonce, $job_data = null) { global $updraftplus; $backup = $backup_history[$key]; $only_remote_sent = !empty($backup['service']) && (array('remotesend') === $backup['service'] || 'remotesend' === $backup['service']); $pretty_date = get_date_from_gmt(gmdate('Y-m-d H:i:s', (int) $key), 'M d, Y G:i'); $rawbackup = "'; $backupable_entities = $updraftplus->get_backupable_file_entities(true, true); $checksums = $updraftplus->which_checksums(); foreach ($backupable_entities as $type => $info) { if (!isset($backup[$type])) continue; $rawbackup .= $updraftplus->printfile($info['description'], $backup, $type, $checksums, $job_data, true); } $total_size = 0; foreach ($backup as $ekey => $files) { if ('db' == strtolower(substr($ekey, 0, 2)) && '-size' != substr($ekey, -5, 5)) { $rawbackup .= $updraftplus->printfile(__('Database', 'updraftplus'), $backup, $ekey, $checksums, $job_data, true); } if (!isset($backupable_entities[$ekey]) && ('db' != substr($ekey, 0, 2) || '-size' == substr($ekey, -5, 5))) continue; if (is_string($files)) $files = array($files); foreach ($files as $findex => $file) { $size_key = (0 == $findex) ? $ekey.'-size' : $ekey.$findex.'-size'; $total_size = (false === $total_size || !isset($backup[$size_key]) || !is_numeric($backup[$size_key])) ? false : $total_size + $backup[$size_key]; } } $services = empty($backup['service']) ? array('none') : $backup['service']; if (!is_array($services)) $services = array('none'); $rawbackup .= ''.__('Uploaded to:', 'updraftplus').' '; $show_services = ''; foreach ($services as $serv) { if ('none' == $serv || '' == $serv) { $add_none = true; } elseif (isset($updraftplus->backup_methods[$serv])) { $show_services .= $show_services ? ', '.$updraftplus->backup_methods[$serv] : $updraftplus->backup_methods[$serv]; } else { $show_services .= $show_services ? ', '.$serv : $serv; } } if ('' == $show_services && $add_none) $show_services .= __('None', 'updraftplus'); $rawbackup .= $show_services; if (false !== $total_size) { $rawbackup .= '
'.__('Total backup size:', 'updraftplus').' '.UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($total_size).''; } $rawbackup .= '
'.print_r($backup, true).''; if (!empty($job_data) && is_array($job_data)) { $rawbackup .= '
'.htmlspecialchars(print_r($job_data, true)).''; } return esc_attr($rawbackup); } private function download_db_button($bkey, $key, $esc_pretty_date, $backup, $accept = array()) { if (!empty($backup['meta_foreign']) && isset($accept[$backup['meta_foreign']])) { $desc_source = $accept[$backup['meta_foreign']]['desc']; } else { $desc_source = __('unknown source', 'updraftplus'); } $ret = ''; if ('db' == $bkey) { $dbt = empty($backup['meta_foreign']) ? esc_attr(__('Database', 'updraftplus')) : esc_attr(sprintf(__('Database (created by %s)', 'updraftplus'), $desc_source)); } else { $dbt = __('External database', 'updraftplus').' ('.substr($bkey, 2).')'; } $ret .= $this->download_button($bkey, $key, 0, null, '', $dbt, $esc_pretty_date, '0'); return $ret; } /** * Go through each of the file entities * * @param Array $backup An array of meta information * @param Integer $key Backup timestamp (epoch time) * @param Array $accept An array of values to be accepted from vaules within $backup * @param String $entities Entities to be added * @param String $esc_pretty_date Whether the button needs to escape the pretty date format * @return String - the resulting HTML */ public function download_buttons($backup, $key, $accept, &$entities, $esc_pretty_date) { global $updraftplus; $ret = ''; $backupable_entities = $updraftplus->get_backupable_file_entities(true, true); $first_entity = true; foreach ($backupable_entities as $type => $info) { if (!empty($backup['meta_foreign']) && 'wpcore' != $type) continue; $ide = ''; if (empty($backup['meta_foreign'])) { $sdescrip = preg_replace('/ \(.*\)$/', '', $info['description']); if (strlen($sdescrip) > 20 && isset($info['shortdescription'])) $sdescrip = $info['shortdescription']; } else { $info['description'] = 'WordPress'; if (isset($accept[$backup['meta_foreign']])) { $desc_source = $accept[$backup['meta_foreign']]['desc']; $ide .= sprintf(__('Backup created by: %s.', 'updraftplus'), $accept[$backup['meta_foreign']]['desc']).' '; } else { $desc_source = __('unknown source', 'updraftplus'); $ide .= __('Backup created by unknown source (%s) - cannot be restored.', 'updraftplus').' '; } $sdescrip = (empty($accept[$backup['meta_foreign']]['separatedb'])) ? sprintf(__('Files and database WordPress backup (created by %s)', 'updraftplus'), $desc_source) : sprintf(__('Files backup (created by %s)', 'updraftplus'), $desc_source); } if (isset($backup[$type])) { if (!is_array($backup[$type])) $backup[$type] = array($backup[$type]); $howmanyinset = count($backup[$type]); $expected_index = 0; $index_missing = false; $set_contents = ''; $entities .= "/$type="; $whatfiles = $backup[$type]; ksort($whatfiles); foreach ($whatfiles as $findex => $bfile) { $set_contents .= ('' == $set_contents) ? $findex : ",$findex"; if ($findex != $expected_index) $index_missing = true; $expected_index++; } $entities .= $set_contents.'/'; if (!empty($backup['meta_foreign'])) { $entities .= '/plugins=0//themes=0//uploads=0//others=0/'; } $printing_first = true; $total_file_size = 0; foreach ($whatfiles as $findex => $bfile) { $pdescrip = ($findex > 0) ? $sdescrip.' ('.($findex+1).')' : $sdescrip; if ($printing_first) { $ide .= __('Press here to download or browse', 'updraftplus').' '.strtolower($info['description']); } else { $ret .= ' '; } else { $printing_first = false; } } $ret = str_replace('%UP_backups_total_file_size%', UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($total_file_size), $ret); } } return $ret; } public function date_label($pretty_date, $key, $backup, $jobdata, $nonce, $simple_format = false) { $pretty_date = $simple_format ? $pretty_date : '
'; $updraftplus->log_e('Restore successful!'); echo '
'; $updraftplus->log('Restore successful'); $s_val = 1; if (!empty($this->entities_to_restore) && is_array($this->entities_to_restore)) { foreach ($this->entities_to_restore as $v) { if ('db' != $v) $s_val = 2; } } $pval = $updraftplus->have_addons ? 1 : 0; echo '' . __('Actions', 'updraftplus') . ': ' . __('Return to UpdraftPlus configuration', 'updraftplus') . ''; return; } elseif (is_wp_error($backup_success)) { echo ''; $updraftplus->log_e('Restore failed...'); echo '
'; $updraftplus->log_wp_error($backup_success); $updraftplus->log('Restore failed'); echo ''; $updraftplus->log_e('Restore failed...'); echo '
'; $updraftplus->log("Restore failed"); echo ''. __('Warning: If you can still read these words after the page finishes loading, then there is a JavaScript or jQuery problem in the site.', 'updraftplus') .' '.__('This may prevent the restore procedure from being able to proceed.', 'updraftplus').''; echo ' '. __('Go here for more information.', 'updraftplus') .'
'; echo ''.sprintf(__('The restore operation has begun (%s). Do not close this page until it reports itself as having finished.', 'updraftplus'), $updraftplus->nonce).'
'; echo ''.__('This backup does not exist in the backup history - restoration aborted. Timestamp:', 'updraftplus')." $timestamp
'.__('ABORT: Could not find the information on which entities to restore.', 'updraftplus').'
'.__('If making a request for support, please include this information:', 'updraftplus').' '.count($restore_jobdata).' : '.htmlspecialchars(serialize($restore_jobdata)).'
'; return new WP_Error('missing_info', 'Backup information not found'); } // This is used in painting the admin page after a successful restore $this->entities_to_restore = $entities_to_restore; // This will be removed by Updraft_Restorer::post_restore_clean_up() set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT); // Set $restore_options, either from the continuation data, or from $_POST if (!empty($continuation_data['restore_options'])) { $restore_options = $continuation_data['restore_options']; } else { // Gather the restore options into one place - code after here should read the options $restore_options = $this->get_restore_options_from_jobdata(); $updraftplus->jobdata_set('restore_options', $restore_options); } add_action('updraftplus_restoration_title', array($this, 'restoration_title')); $updraftplus->log_restore_update(array('type' => 'state', 'stage' => 'started', 'data' => array())); // We use a single object for each entity, because we want to store information about the backup set $updraftplus_restorer = new Updraft_Restorer(new Updraft_Restorer_Skin, $backup_set, false, $restore_options, $continuation_data); $restore_result = $updraftplus_restorer->perform_restore($entities_to_restore, $restore_options); $updraftplus_restorer->post_restore_clean_up($restore_result); $pval = $updraftplus->have_addons ? 1 : 0; $sval = (true === $restore_result) ? 1 : 0; $pages = get_pages(array('number' => 2)); $page_urls = array( 'home' => get_home_url(), ); foreach ($pages as $page_info) { $page_urls[$page_info->post_name] = get_page_link($page_info->ID); } $updraftplus->log_restore_update( array( 'type' => 'state', 'stage' => 'finished', 'data' => array( 'actions' => array( __('Return to UpdraftPlus configuration', 'updraftplus') => UpdraftPlus_Options::admin_page_url() . '?page=updraftplus&updraft_restore_success=' . $sval . '&pval=' . $pval ), 'urls' => $page_urls, ) ) ); return $restore_result; } /** * Called when the restore process wants to print a title * * @param String $title - title */ public function restoration_title($title) { echo ''.__('No remote storage locations with valid options found.', 'updraftplus').'
'; } return ' (...)'; ob_start(); $history = UpdraftPlus_Backup_History::get_history(); var_dump($history); $response["html"] .= ob_get_clean(); $response['html'] .= ''; $response['html'] .= '
'; $updraft_dir = $updraftplus->backups_dir_location(); $raw_output = array(); $d = dir($updraft_dir); while (false !== ($entry = $d->read())) { $fp = $updraft_dir.'/'.$entry; $mtime = filemtime($fp); if (is_dir($fp)) { $size = ' d'; } elseif (is_link($fp)) { $size = ' l'; } elseif (is_file($fp)) { $size = sprintf("%8.1f", round(filesize($fp)/1024, 1)).' '.gmdate('r', $mtime); } else { $size = ' ?'; } if (preg_match('/^log\.(.*)\.txt$/', $entry, $lmatch)) $entry = ''.$entry.''; $raw_output[$mtime] = empty($raw_output[$mtime]) ? sprintf("%s %s\n", $size, $entry) : $raw_output[$mtime].sprintf("%s %s\n", $size, $entry); } @$d->close();// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged krsort($raw_output, SORT_NUMERIC); foreach ($raw_output as $line) { $response['html'] .= $line; } $response['html'] .= ''; $response['html'] .= '
'.htmlspecialchars($opt).' | '.htmlspecialchars(print_r(UpdraftPlus_Options::get_updraft_option($opt), true)).' | '; } // Get the option saved by yahnis-elsts/plugin-update-checker $response['html'] .= '
external_updates-updraftplus | '.htmlspecialchars(print_r(get_site_option('external_updates-updraftplus'), true)).' | ';
$response['html'] .= '
', '', $response['html']); $response['html'] = str_replace('', '', $response['html']); } return $response; } /** * This will call any wp_action * * @param Array|Null $data The array of data with the vaules for wpaction * @param Callable|Boolean $close_connection_callable A callable to call to close the browser connection, or true for a default suitable for internal use, or false for none * @return Array - results */ public function call_wp_action($data = null, $close_connection_callable = false) { global $updraftplus; ob_start(); $res = 'Request received: '; if (preg_match('/^([^:]+)+:(.*)$/', $data['wpaction'], $matches)) { $action = $matches[1]; if (null === ($args = json_decode($matches[2], true))) { $res .= "The parameters (should be JSON) could not be decoded"; $action = false; } else { if (is_string($args)) $args = array($args); $res .= "Will despatch action: ".htmlspecialchars($action).", parameters: ".htmlspecialchars(implode(',', $args)); } } else { $action = $data['wpaction']; $res .= "Will despatch action: ".htmlspecialchars($action).", no parameters"; } ob_get_clean(); // Need to add this as the close browser should only work for UDP if ($close_connection_callable) { if (is_callable($close_connection_callable)) { call_user_func($close_connection_callable, array('r' => $res)); } else { $updraftplus->close_browser_connection(json_encode(array('r' => $res))); } } if (!empty($action)) { if (!empty($args)) { ob_start(); $returned = do_action_ref_array($action, $args); $output = ob_get_clean(); $res .= " - do_action_ref_array Trigger "; } else { ob_start(); do_action($action); $output = ob_get_contents(); ob_end_clean(); $res .= " - do_action Trigger "; } } $response = array(); $response['response'] = $res; $response['log'] = $output; // Check if response is empty if (!empty($returned)) $response['status'] = $returned; return $response; } /** * Enqueue JSTree JavaScript and CSS, taking into account whether it is already enqueued, and current debug settings */ public function enqueue_jstree() { global $updraftplus; static $already_enqueued = false; if ($already_enqueued) return; $already_enqueued = true; $jstree_enqueue_version = $updraftplus->use_unminified_scripts() ? '3.3'.'.'.time() : '3.3'; $min_or_not = $updraftplus->use_unminified_scripts() ? '' : '.min'; wp_enqueue_script('jstree', UPDRAFTPLUS_URL.'/includes/jstree/jstree'.$min_or_not.'.js', array('jquery'), $jstree_enqueue_version); wp_enqueue_style('jstree', UPDRAFTPLUS_URL.'/includes/jstree/themes/default/style'.$min_or_not.'.css', array(), $jstree_enqueue_version); } /** * Detects byte-order mark at the start of common files and change waning message texts * * @return string|boolean BOM warning text or false if not bom characters detected */ public function get_bom_warning_text() { $files_to_check = array( ABSPATH.'wp-config.php', get_template_directory().DIRECTORY_SEPARATOR.'functions.php', ); if (is_child_theme()) { $files_to_check[] = get_stylesheet_directory().DIRECTORY_SEPARATOR.'functions.php'; } $corrupted_files = array(); foreach ($files_to_check as $file) { if (!file_exists($file)) continue; if (false === ($fp = fopen($file, 'r'))) continue; if (false === ($file_data = fread($fp, 8192))); fclose($fp); $substr_file_data = array(); for ($substr_length = 2; $substr_length <= 5; $substr_length++) { $substr_file_data[$substr_length] = substr($file_data, 0, $substr_length); } // Detect UTF-7, UTF-8, UTF-16 (BE), UTF-16 (LE), UTF-32 (BE) & UTF-32 (LE) Byte order marks (BOM) $bom_decimal_representations = array( array(43, 47, 118, 56), // UTF-7 (Hexadecimal: 2B 2F 76 38) array(43, 47, 118, 57), // UTF-7 (Hexadecimal: 2B 2F 76 39) array(43, 47, 118, 43), // UTF-7 (Hexadecimal: 2B 2F 76 2B) array(43, 47, 118, 47), // UTF-7 (Hexadecimal: 2B 2F 76 2F) array(43, 47, 118, 56, 45), // UTF-7 (Hexadecimal: 2B 2F 76 38 2D) array(239, 187, 191), // UTF-8 (Hexadecimal: 2B 2F 76 38 2D) array(254, 255), // UTF-16 (BE) (Hexadecimal: FE FF) array(255, 254), // UTF-16 (LE) (Hexadecimal: FF FE) array(0, 0, 254, 255), // UTF-32 (BE) (Hexadecimal: 00 00 FE FF) array(255, 254, 0, 0), // UTF-32 (LE) (Hexadecimal: FF FE 00 00) ); foreach ($bom_decimal_representations as $bom_decimal_representation) { $no_of_chars = count($bom_decimal_representation); array_unshift($bom_decimal_representation, 'C*'); $binary = call_user_func_array('pack', $bom_decimal_representation); if ($binary == $substr_file_data[$no_of_chars]) { $corrupted_files[] = $file; break; } } } if (empty($corrupted_files)) { return false; } else { $corrupted_files_count = count($corrupted_files); return ''.__('Warning', 'updraftplus').': '.sprintf(_n('The file %s has a "byte order mark" (BOM) at its beginning.', 'The files %s have a "byte order mark" (BOM) at their beginning.', $corrupted_files_count, 'updraftplus'), ''.implode(', ', $corrupted_files).'').' '.__('Follow this link for more information', 'updraftplus').''; } } /** * Gets an instance of the "UpdraftPlus_UpdraftCentral_Cloud" class which will be * used to login or register the user to the UpdraftCentral cloud * * @return object */ public function get_updraftcentral_cloud() { if (!class_exists('UpdraftPlus_UpdraftCentral_Cloud')) include_once(UPDRAFTPLUS_DIR.'/includes/updraftcentral.php'); return new UpdraftPlus_UpdraftCentral_Cloud(); } /** * This function will build and return the UpdraftPlus tempoaray clone ui widget * * @param boolean $include_testing_ui - a boolean to indicate if testing-only UI elements should be shown (N.B. they can only work if the user also has testing permissions) * @param array $supported_wp_versions - an array of supported WordPress versions * @param array $supported_packages - an array of supported clone packages * @param array $supported_regions - an array of supported clone regions * * @return string - the clone UI widget */ public function updraftplus_clone_ui_widget($include_testing_ui, $supported_wp_versions, $supported_packages, $supported_regions) { global $updraftplus; $output = '
'; $output .= ''.sprintf(__('%s version:', 'updraftplus'), 'PHP').' '; $output .= $this->output_select_data($this->php_versions, 'php'); $output .= '
'; $output .= ''; $output .= ' '.sprintf(__('%s version:', 'updraftplus'), 'WordPress').' '; $output .= $this->output_select_data($this->get_wordpress_versions($supported_wp_versions), 'wp'); $output .= '
'; $output .= ''; $output .= ' '.__('Clone region:', 'updraftplus').' '; $output .= $this->output_select_data($supported_regions, 'region'); $output .= '
'; $backup_history = UpdraftPlus_Backup_History::get_history(); foreach ($backup_history as $key => $backup) { $backup_complete = $this->check_backup_is_complete($backup, false, true, false); $remote_sent = !empty($backup['service']) && ((is_array($backup['service']) && in_array('remotesend', $backup['service'])) || 'remotesend' === $backup['service']); if (!$backup_complete || $remote_sent) unset($backup_history[$key]); } $output .= ''; $output .= ' '.__('Clone:', 'updraftplus').' '; $output .= ''; $output .= '
'; $output .= ''; $output .= ' '.__('Clone package:', 'updraftplus').' '; $output .= ''; $output .= '
'; if ((defined('UPDRAFTPLUS_UPDRAFTCLONE_DEVELOPMENT') && UPDRAFTPLUS_UPDRAFTCLONE_DEVELOPMENT) || $include_testing_ui) { $output .= ''; $output .= ' UpdraftClone Branch: '; $output .= ''; $output .= '
'; $output .= ''; $output .= ' UpdraftPlus Branch: '; $output .= ''; $output .= '
'; $output .= ''; } $output .= ''; $output .= ''; $output .= ''; $output .= '
'; $output = apply_filters('updraftplus_clone_additional_ui', $output); return $output; } /** * This function will output a select input using the passed in values. * * @param array $data - the keys and values for the select * @param string $name - the name of the items in the select input * @param string $selected - the value we want selected by default * * @return string - the output of the select input */ public function output_select_data($data, $name, $selected = '') { $name_version = empty($selected) ? $this->get_current_version($name) : $selected; $output = ''; return $output; } /** * This function will output the clones network information * * @param string $url - the clone URL * * @return string - the clone network information */ public function updraftplus_clone_info($url) { global $updraftplus; if (!empty($url)) { $content = '' . __('Your clone has started and will be available at the following URLs once it is ready.', 'updraftplus') . '
'; $content .= '' . __('Front page:', 'updraftplus') . ' ' . esc_html($url) . '
'; $content .= '' . __('Dashboard:', 'updraftplus') . ' ' . esc_html(trailingslashit($url)) . 'wp-admin
'; $content .= '' . __('Your clone has started, network information is not yet available but will be displayed here and at your updraftplus.com account once it is ready.', 'updraftplus') . '
'; $content .= ''; } return $content; } /** * This function will build and return an array of major WordPress versions, the array is built by calling the WordPress version API once every 24 hours and adding any new entires to our existing array of versions. * * @param array $supported_wp_versions - an array of supported WordPress versions * * @return array - an array of WordPress major versions */ private function get_wordpress_versions($supported_wp_versions) { if (empty($supported_wp_versions)) $supported_wp_versions[] = $this->get_current_version('wp'); $key = array_search($this->get_current_version('wp'), $supported_wp_versions); if ($key) { $supported_wp_versions = array_slice($supported_wp_versions, $key); } $version_array = $supported_wp_versions; return $version_array; } /** * This function will get the current version the server is running for the passed in item e.g WordPress or PHP * * @param string $name - the thing we want to get the version for e.g WordPress or PHP * * @return string - returns the current version of the passed in item */ public function get_current_version($name) { $version = ''; if ('php' == $name) { $parts = explode(".", PHP_VERSION); $version = $parts[0] . "." . $parts[1]; } elseif ('wp' == $name) { global $updraftplus; $wp_version = $updraftplus->get_wordpress_version(); $parts = explode(".", $wp_version); $version = $parts[0] . "." . $parts[1]; } return $version; } /** * Show which remote storage settings are partially setup error, or if manual auth is supported show the manual auth UI */ public function show_admin_warning_if_remote_storage_with_partial_setttings() { if ((isset($_REQUEST['page']) && 'updraftplus' == $_REQUEST['page']) || (defined('DOING_AJAX') && DOING_AJAX)) { $enabled_services = UpdraftPlus_Storage_Methods_Interface::get_enabled_storage_objects_and_ids(array_keys($this->storage_service_with_partial_settings)); foreach ($this->storage_service_with_partial_settings as $method => $method_name) { if (empty($enabled_services[$method]['object']) || empty($enabled_services[$method]['instance_settings']) || !$enabled_services[$method]['object']->supports_feature('manual_authentication')) { $this->show_admin_warning(sprintf(__('The following remote storage (%s) have only been partially configured, manual authorization is not supported with this remote storage, please try again and if the problem persists contact support.', 'updraftplus'), $method), 'error'); } else { $this->show_admin_warning($enabled_services[$method]['object']->get_manual_authorisation_template(), 'error'); } } } else { $this->show_admin_warning('UpdraftPlus: '.sprintf(__('The following remote storage (%s) have only been partially configured, if you are having problems you can try to manually authorise at the UpdraftPlus settings page.', 'updraftplus'), implode(', ', $this->storage_service_with_partial_settings)).' '.__('Return to UpdraftPlus configuration', 'updraftplus').'', 'error'); } } /** * Show remote storage settings are empty warning */ public function show_admin_warning_if_remote_storage_settting_are_empty() { if ((isset($_REQUEST['page']) && 'updraftplus' == $_REQUEST['page']) || (defined('DOING_AJAX') && DOING_AJAX)) { $this->show_admin_warning(sprintf(__('You have requested saving to remote storage (%s), but without entering any settings for that storage.', 'updraftplus'), implode(', ', $this->storage_service_without_settings)), 'error'); } else { $this->show_admin_warning('UpdraftPlus: '.sprintf(__('You have requested saving to remote storage (%s), but without entering any settings for that storage.', 'updraftplus'), implode(', ', $this->storage_service_without_settings)).' '.__('Return to UpdraftPlus configuration', 'updraftplus').'', 'error'); } } /** * Receive Heartbeat data and respond. * * Processes data received via a Heartbeat request, and returns additional data to pass back to the front end. * * @param array $response - Heartbeat response data to pass back to front end. * @param array $data - Data received from the front end (unslashed). */ public function process_status_in_heartbeat($response, $data) { if (!is_array($response) || empty($data['updraftplus'])) return $response; try { $response['updraftplus'] = $this->get_activejobs_list(UpdraftPlus_Manipulation_Functions::wp_unslash($data['updraftplus'])); } catch (Exception $e) { $log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during get active job list. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')'; error_log($log_message); $response['updraftplus'] = array( 'fatal_error' => true, 'fatal_error_message' => $log_message ); // @codingStandardsIgnoreLine } catch (Error $e) { $log_message = 'PHP Fatal error ('.get_class($e).') has occurred during get active job list. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')'; error_log($log_message); $response['updraftplus'] = array( 'fatal_error' => true, 'fatal_error_message' => $log_message ); } if (UpdraftPlus_Options::user_can_manage() && isset($data['updraftplus']['updraft_credentialtest_nonce'])) { if (!wp_verify_nonce($data['updraftplus']['updraft_credentialtest_nonce'], 'updraftplus-credentialtest-nonce')) { $response['updraftplus']['updraft_credentialtest_nonce'] = wp_create_nonce('updraftplus-credentialtest-nonce'); } } $response['updraftplus']['time_now'] = get_date_from_gmt(gmdate('Y-m-d H:i:s'), 'D, F j, Y H:i'); return $response; } /** * Show warning about restriction implied by the hosting company (can only perform a full backup once per month, incremental backup should not go above one per day) */ public function show_admin_warning_one_backup_per_month() { global $updraftplus; $hosting_company = $updraftplus->get_hosting_info(); $txt1 = __('Your website is hosted with %s (%s).', 'updraftplus'); $txt2 = __('%s permits UpdraftPlus to perform only one backup per month. Thus, we recommend you choose a full backup when performing a manual backup and to use that option when creating a scheduled backup.', 'updraftplus'); $txt3 = __('Due to the restriction, some settings can be automatically adjusted, disabled or not available.', 'updraftplus'); $this->show_plugin_page_admin_warning(''.__('Warning', 'updraftplus').': '.sprintf("$txt1 $txt2 $txt3", $hosting_company['name'], $hosting_company['website'], $hosting_company['name']), 'update-nag notice notice-warning', true); } /** * Find out if the current request is a backup download request, and proceed with the download if it is */ public function maybe_download_backup_from_email() { global $pagenow; if ((!defined('DOING_AJAX') || !DOING_AJAX) && UpdraftPlus_Options::admin_page() === $pagenow && isset($_REQUEST['page']) && 'updraftplus' === $_REQUEST['page'] && isset($_REQUEST['action']) && 'updraft_download_backup' === $_REQUEST['action']) { $findexes = empty($_REQUEST['findex']) ? array(0) : $_REQUEST['findex']; $timestamp = empty($_REQUEST['timestamp']) ? '' : $_REQUEST['timestamp']; $nonce = empty($_REQUEST['nonce']) ? '' : $_REQUEST['nonce']; $type = empty($_REQUEST['type']) ? '' : $_REQUEST['type']; if (empty($timestamp) || empty($nonce) || empty($type)) wp_die(__('The download link is broken, you may have clicked the link from untrusted source', 'updraftplus'), '', array('back_link' => true)); $backup_history = UpdraftPlus_Backup_History::get_history(); if (!isset($backup_history[$timestamp]['nonce']) || $backup_history[$timestamp]['nonce'] !== $nonce) wp_die(__("The download link is broken or the backup file is no longer available", 'updraftplus'), '', array('back_link' => true)); $this->do_updraft_download_backup($findexes, $type, $timestamp, 2, false, ''); exit; // we don't need anything else but an exit } } }