1109 lines
45 KiB
PHP
1109 lines
45 KiB
PHP
<?php
|
|
// @codingStandardsIgnoreStart
|
|
/*
|
|
Obtain and manage extra features for UpdraftPlus Backup
|
|
|
|
This plugin communicates with the mothership via encrypted HTTPS and falls back to HTTP if this fails; even over HTTP, nothing of significant value is thereby put at risk - see https://updraftplus.com/faqs/tell-me-about-my-updraftplus-com-account/
|
|
However, if your organisation has strong requirements for use of SSL, then add the following line to your wp-config.php to forbid any non-https communications:
|
|
|
|
define('UPDRAFTPLUS_ADDONS_SSL', true);
|
|
|
|
This plugin:
|
|
- over-rides the update mechanism for the UpdraftPlus plugin, so that we can get them from our site
|
|
- shows the user his installed and available add-ons
|
|
- also over-rides its own update mechanism
|
|
|
|
This directory should not be added to the wordpress.org SVN
|
|
*/
|
|
// @codingStandardsIgnoreEnd
|
|
|
|
define('UDADDONS2_DIR', dirname(realpath(__FILE__)));
|
|
define('UDADDONS2_URL', UPDRAFTPLUS_URL.'/udaddons');
|
|
define('UDADDONS2_SLUG', 'updraftplus-addons');
|
|
define('UDADDONS2_PAGESLUG', 'updraftplus');
|
|
|
|
$udaddons2_mothership = (defined('UPDRAFTPLUS_ADDONS_SSL') && !UPDRAFTPLUS_ADDONS_SSL) ? 'http://' : 'https://';
|
|
|
|
$udaddons2_mothership .= defined('UDADDONS2_TEST_MOTHERSHIP') ? UDADDONS2_TEST_MOTHERSHIP : 'updraftplus.com';
|
|
|
|
global $updraftplus_addons2; // Need to explicitly globalise the variable or WP-CLI won't recognise it https://github.com/wp-cli/wp-cli/issues/4019#issuecomment-297410839
|
|
|
|
$updraftplus_addons2 = new UpdraftPlusAddons2('updraftplus', $udaddons2_mothership);
|
|
|
|
class UpdraftPlusAddons2 {
|
|
|
|
public $slug;
|
|
|
|
public $url;
|
|
|
|
public $debug = false;
|
|
|
|
public $user_addons;
|
|
|
|
public $user_support;
|
|
|
|
public $available_addons;
|
|
|
|
public $remote_addons;
|
|
|
|
public $plug_updatechecker;
|
|
|
|
private $admin_notices = array();
|
|
|
|
private $saved_site_id;
|
|
|
|
private $plugin_file;
|
|
|
|
/**
|
|
* Not used anywhere, but it is set.
|
|
*
|
|
* @var UpdraftPlusAddOns_Options2
|
|
*/
|
|
private $options;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param String $slug - the plugin's slug
|
|
* @param String $url - the URL of the mothership that updates are checked at
|
|
*/
|
|
public function __construct($slug, $url) {
|
|
$this->slug = $slug;
|
|
$this->url = $url;
|
|
|
|
// Hide unwanted/user-hostile JetPack promotions, which cause genuine directory search results to be de-prioritised by default (if you use any of JetPack's 45 modules, then it promotes things from the others to the top of search results): https://wptavern.com/jetpack-7-1-adds-feature-suggestions-to-plugin-search-results. If using one JetPack module really does mean that you now automatically prefer all the others, then remove these lines, or add higher-priority filters to add them back.
|
|
add_filter('jetpack_show_promotions', '__return_false', 20);
|
|
add_filter('jetpack_just_in_time_msgs', '__return_false', 20);
|
|
|
|
// This needs to exact match PluginUpdateChecker's view
|
|
$this->plugin_file = plugin_basename($this->slug.'/'.$this->slug.'.php');
|
|
|
|
add_action('updraftplus_restore_db_pre', array($this, 'updraftplus_restore_db_pre'));
|
|
add_action('updraftplus_restored_db_is_migration', array($this, 'updraftplus_restored_db_is_migration'));
|
|
|
|
add_action('updraftplus_showrawinfo', array($this, 'updraftplus_showrawinfo'));
|
|
|
|
add_action((is_multisite() && class_exists('UpdraftPlusAddOn_MultiSite')) ? 'network_admin_menu' : 'admin_menu', array($this, 'admin_menu'));
|
|
|
|
add_action('wp_ajax_udaddons_claimaddon', array($this, 'ajax_udaddons_claimaddon'));
|
|
|
|
if (class_exists('UpdraftPlusAddons')) return;
|
|
|
|
// Prevent updates from wordpress.org showing in all circumstances. Run with lower than default priority, to allow later processes to add something.
|
|
add_filter('site_transient_update_plugins', array($this, 'site_transient_update_plugins'), 9);
|
|
|
|
// Over-ride update mechanism for the plugin
|
|
if (is_readable(UPDRAFTPLUS_DIR.'/vendor/yahnis-elsts/plugin-update-checker/plugin-update-checker.php')) {
|
|
|
|
updraft_try_include_file('vendor/yahnis-elsts/plugin-update-checker/plugin-update-checker.php', 'include_once');
|
|
|
|
add_filter('puc_check_now-'.$this->slug, array($this, 'puc_check_now'), 10, 3);
|
|
add_filter('puc_retain_fields-'.$this->slug, array($this, 'puc_retain_fields'));
|
|
add_filter('puc_request_info_options-'.$this->slug, array($this, 'puc_request_info_options'));
|
|
// Run after the PluginUpdateChecker has done its stuff
|
|
add_filter('site_transient_update_plugins', array($this, 'possibly_inject_translations'), 11);
|
|
// If https does not work, then try http
|
|
|
|
$plug_updatechecker = Puc_v4_Factory::buildUpdateChecker($this->url."/plugin-info/", WP_PLUGIN_DIR.'/'.$this->slug.'/'.$this->slug.'.php', $this->slug, 24);
|
|
|
|
// The null case is seen in HS#36382
|
|
if (null === $plug_updatechecker) {
|
|
error_log("UpdraftPlus: Puc_v4_Factory::buildUpdateChecker() return a null object");
|
|
} else {
|
|
$plug_updatechecker->addQueryArgFilter(array($this, 'updater_queryargs_plugin'));
|
|
if ($this->debug) $plug_updatechecker->debugMode = true;
|
|
|
|
$plug_updatechecker->addFilter('request_metadata_http_result', array($this, 'request_metadata_http_result'), 10, 3);
|
|
|
|
$this->plug_updatechecker = $plug_updatechecker;
|
|
}
|
|
|
|
$this->move_updraftplus_update_cron();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function is used to redistribute update check times; it is a control to help spread server load
|
|
*
|
|
* @return void
|
|
*/
|
|
private function move_updraftplus_update_cron() {
|
|
|
|
$cron_move_date = 1607558400; // 2020-12-10 00:00
|
|
$cleanup_date = 1607644800; // 2020-12-11 00:00
|
|
$option_name = 'updraftplus_move_update_cron_dec20';
|
|
|
|
$time_now = time();
|
|
$start_of_today = $time_now - ($time_now % 86400);
|
|
|
|
if ($start_of_today > $cleanup_date + 172800) return;
|
|
|
|
$moved_cron = get_site_option($option_name);
|
|
|
|
if ($cron_move_date == $start_of_today && !$moved_cron) {
|
|
$timestamp = wp_next_scheduled('puc_cron_check_updates-updraftplus');
|
|
$begintime1 = $cron_move_date + 3600 * 9; // 09:00
|
|
$endtime1 = $begintime1 + 3600 * 12;
|
|
// $begintime2 = 1588953600; // 2020-05-08 16:00
|
|
// $endtime2 = $begintime2 + 7 * 3600;
|
|
|
|
if ($timestamp >= $begintime1 && $timestamp <= $endtime1) {
|
|
wp_clear_scheduled_hook('puc_cron_check_updates-updraftplus');
|
|
wp_schedule_event($timestamp + 13 * 3600, 'daily', 'puc_cron_check_updates-updraftplus');
|
|
$this->update_option($option_name, true);
|
|
}
|
|
|
|
} elseif ($moved_cron && $start_of_today >= $cleanup_date) {
|
|
delete_site_option($option_name);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* WordPress filter, from plugins-updates-checker. We use it to fall back to http:// if https:// fails
|
|
*
|
|
* @param Mixed $result The result of the first HTTP request
|
|
* @param String $url The URL being fetched
|
|
* @param Array $options The options for the WP HTTP API
|
|
*
|
|
* @return Mixed - the result of the WP HTTP API call to use
|
|
*/
|
|
public function request_metadata_http_result($result, $url, $options) {
|
|
|
|
$url_non_ssl = preg_replace('/^https:/i', 'http:', $url);
|
|
|
|
if (is_wp_error($result) && $url != $url_non_ssl && (!defined('UPDRAFTPLUS_ADDONS_SSL') || !UPDRAFTPLUS_ADDONS_SSL)) {
|
|
|
|
$result = wp_remote_get(
|
|
$url_non_ssl,
|
|
$options
|
|
);
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
/**
|
|
* Inject our translation information into the updates object. Runs upon the WP filter site_transient_update_plugins .
|
|
*
|
|
* @param Object $updates
|
|
*
|
|
* @return Object
|
|
*/
|
|
public function possibly_inject_translations($updates) {
|
|
|
|
$slug = $this->slug;
|
|
|
|
$checker = is_object($this->plug_updatechecker) ? get_site_option($this->plug_updatechecker->optionName, null) : null;
|
|
|
|
if (!isset($checker->update->translations) || !is_array($checker->update->translations)) return $updates;
|
|
|
|
foreach ($checker->update->translations as $translation) {
|
|
|
|
// Remove any existing updates indicated for this slug/language - i.e. we want it over-ridden with the result from the server
|
|
if (isset($updates->translations) && is_array($updates->translations)) {
|
|
foreach ($updates->translations as $k => $translation) {
|
|
if ('plugin' == $translation['type'] && $translation['slug'] == $slug) unset($updates->translations[$k]);
|
|
}
|
|
|
|
} else {
|
|
$updates->translations = array();
|
|
}
|
|
|
|
// Add our translation onto the array
|
|
$translation_array = (array) $translation;
|
|
$translation_array['type'] = 'plugin';
|
|
$translation_array['slug'] = $slug;
|
|
|
|
$updates->translations[] = $translation_array;
|
|
|
|
}
|
|
|
|
return $updates;
|
|
}
|
|
|
|
public function puc_request_info_options($opts) {
|
|
if (is_array($opts)) $opts['timeout'] = 10;
|
|
return $opts;
|
|
}
|
|
|
|
/**
|
|
* Print out update URL information
|
|
*/
|
|
public function updraftplus_showrawinfo() {
|
|
echo "<p>Updates URL: ".esc_url($this->url)."</p>";
|
|
}
|
|
|
|
public function updraftplus_restore_db_pre() {
|
|
$this->saved_site_id = $this->siteid();
|
|
}
|
|
|
|
public function updraftplus_restored_db_is_migration() {
|
|
$option = UDADDONS2_SLUG.'_siteid';
|
|
if (!empty($this->saved_site_id)) {
|
|
global $updraftplus;
|
|
$updraftplus->log("Restored pre-migration site ID for this installation");
|
|
delete_site_option($option);
|
|
add_site_option($option, $this->saved_site_id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fields to be retained from the remote request
|
|
*
|
|
* @param Array $fields - list of fields
|
|
*
|
|
* @return Array - list after filtering
|
|
*/
|
|
public function puc_retain_fields($fields) {
|
|
$retain_these = array('translations', 'extraProperties');
|
|
foreach ($retain_these as $retain) {
|
|
if (!in_array($retain, $fields)) $fields[] = $retain;
|
|
}
|
|
return $fields;
|
|
}
|
|
|
|
public function admin_notices() {
|
|
foreach ($this->admin_notices as $key => $notice) {
|
|
$notice = '<span style="font-size: 115%;">'.$notice.'</span>';
|
|
if (is_numeric($key)) {
|
|
$this->show_admin_warning($notice);
|
|
} else {
|
|
$this->show_admin_warning($notice, 'error updraftupdatesnotice updraftupdatesnotice-'.$key);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Runs upon the WP action admin_menu or network_admin_menu
|
|
*/
|
|
public function admin_menu() {
|
|
global $pagenow, $updraftplus;
|
|
|
|
// Do we want to display a notice about the upcoming or past expiry of their UpdraftPlus subscription?
|
|
if (!empty($this->plug_updatechecker) && !empty($this->plug_updatechecker->optionName) && current_user_can('update_plugins')) {
|
|
// (!is_multisite() && 'options-general.php' == $pagenow) || (is_multisite() && 'settings.php' == $pagenow) ||
|
|
if ('plugins.php' == $pagenow || 'update-core.php' == $pagenow || (('options-general.php' == $pagenow || 'admin.php' == $pagenow) && !empty($_REQUEST['page']) && 'updraftplus' == $_REQUEST['page'])) {
|
|
$do_expiry_check = true;
|
|
$dismiss = '';
|
|
} elseif (is_admin()) {
|
|
$dismissed_until = UpdraftPlus_Options::get_updraft_option('updraftplus_dismissedexpiry', 0);
|
|
if ($dismissed_until <= time()) {
|
|
$do_expiry_check = true;
|
|
$dismiss = '<div style="float:right; position: relative; top:-24px;" class="ud-expiry-dismiss"><a href="#" onclick="jQuery(\'.ud-expiry-dismiss\').parent().slideUp(); jQuery.post(ajaxurl, {action: \'updraft_ajax\', subaction: \'dismissexpiry\', nonce: \''.wp_create_nonce('updraftplus-credentialtest-nonce').'\' })">'.sprintf(__('Dismiss from main dashboard (for %s weeks)', 'updraftplus'), 2).'</a></div>';
|
|
}
|
|
}
|
|
}
|
|
|
|
$oval = is_object($this->plug_updatechecker) ? get_site_option($this->plug_updatechecker->optionName, null) : null;
|
|
$updateskey = 'x-spm-expiry';
|
|
$supportkey = 'x-spm-support-expiry';
|
|
$metakey = 'x-spm-meta';
|
|
$subscription_activekey = 'x-spm-subscription-active';
|
|
|
|
$meta_info = (is_object($oval) && !empty($oval->update) && is_object($oval->update) && !empty($oval->update->extraProperties[$metakey])) ? (array) json_decode($oval->update->extraProperties[$metakey], true) : array();
|
|
|
|
$yourversionkey = 'x-spm-yourversion-tested';
|
|
|
|
if (is_object($oval) && !empty($oval->update) && is_object($oval->update) && !empty($oval->update->extraProperties[$yourversionkey]) && UpdraftPlus_Options::user_can_manage() && (!defined('UPDRAFTPLUS_DISABLECOMPATNOTICE') || true != UPDRAFTPLUS_DISABLECOMPATNOTICE)) {
|
|
|
|
// Prevent false-positives
|
|
if (file_exists(UPDRAFTPLUS_DIR.'/readme.txt') && $fp = fopen(UPDRAFTPLUS_DIR.'/readme.txt', 'r')) {
|
|
$file_data = fread($fp, 1024);
|
|
if (preg_match("/Tested up to: (\d+(\.\d+)+)/", $file_data, $matches)) {
|
|
$readme_says = $matches[1];
|
|
}
|
|
fclose($fp);
|
|
}
|
|
|
|
$wp_version = $updraftplus->get_wordpress_version();
|
|
$compare_wp_version = (preg_match('/^(\d+\.\d+)\..*$/', $wp_version, $wmatches)) ? $wmatches[1] : $wp_version;
|
|
$compare_tested_version = $oval->update->extraProperties[$yourversionkey];
|
|
if (!empty($readme_says) && version_compare($readme_says, $compare_tested_version, '>')) $compare_tested_version = $readme_says;
|
|
if (version_compare($compare_wp_version, $compare_tested_version, '>')) {
|
|
$this->admin_notices['yourversiontested'] = '<strong>'.__('Warning', 'updraftplus').':</strong> '.sprintf(__('The installed version of UpdraftPlus Backup/Restore has not been tested on your version of WordPress (%s).', 'updraftplus'), $wp_version).' '.sprintf(__('It has been tested up to version %s.', 'updraftplus'), $compare_tested_version).' <a href="https://teamupdraft.com/documentation/updraftplus/topics/general/troubleshooting/seeing-warning-versions-wordpress-updraftplus-tested/?utm_source=udp-plugin&utm_medium=referral&utm_campaign=paac&utm_content=unknown&utm_creative_format=unknown">'.__('You should update UpdraftPlus to make sure that you have a version that has been tested for compatibility.', 'updraftplus').'</a>';
|
|
}
|
|
}
|
|
|
|
if (!empty($do_expiry_check) && is_object($oval) && !empty($oval->update) && is_object($oval->update) && !empty($oval->update->extraProperties[$updateskey])) {
|
|
if (preg_match('/(^|)expired_?(\d+)?(,|$)/', $oval->update->extraProperties[$updateskey], $matches)) {
|
|
if (empty($matches[2])) {
|
|
$message = __('Your paid access to UpdraftPlus updates for this site has expired.', 'updraftplus').' '.__('You will no longer receive updates to UpdraftPlus.', 'updraftplus').' <a href="https://teamupdraft.com/documentation/account-management/orders-and-subscriptions/why-should-i-renew-my-updraftplus-wp-optimize-or-aios-licence-and-how-do-i-do-that/?utm_source=udp-plugin&utm_medium=referral&utm_campaign=paac&utm_content=to-regain-access&utm_creative_format=notice">'.__('To regain access to updates (including future features and compatibility with future WordPress releases) and support, please renew.', 'updraftplus').'</a>';
|
|
if ($updraftplus->have_addons > 14 && !empty($meta_info['indirect'])) {
|
|
$message .= ' <br>'.sprintf(__('If you have already renewed, then you need to allocate a licence to this site - %s', 'updraftplus'), '<a href="'.UpdraftPlus_Options::admin_page().'?page=updraftplus&tab=addons">'.__('go here', 'updraftplus').'</a>');
|
|
}
|
|
$this->admin_notices['updatesexpired'] = $message.$dismiss;
|
|
} else {
|
|
$this->admin_notices['updatesexpired'] = sprintf(__('Your paid access to UpdraftPlus updates for %s add-ons on this site has expired.', 'updraftplus'), $matches[2]).' <a href="https://teamupdraft.com/documentation/account-management/orders-and-subscriptions/why-should-i-renew-my-updraftplus-wp-optimize-or-aios-licence-and-how-do-i-do-that/?utm_source=udp-plugin&utm_medium=referral&utm_campaign=paac&utm_content=to-regain-access&utm_creative_format=notice">'.__('To regain access to updates (including future features and compatibility with future WordPress releases) and support, please renew.', 'updraftplus').'</a>'.$dismiss;
|
|
}
|
|
}
|
|
$subscription_status = apply_filters('udmupdater_subscription_active', isset($oval->update->extraProperties[$subscription_activekey]) ? $oval->update->extraProperties[$subscription_activekey] : false);
|
|
if (empty($subscription_status)) {
|
|
if (preg_match('/(^|,)soonpartial_(\d+)_(\d+)($|,)/', $oval->update->extraProperties[$updateskey], $matches)) {
|
|
$this->admin_notices['updatesexpiringsoon'] = sprintf(__('Your paid access to UpdraftPlus updates for %s of the %s add-ons on this site will soon expire.', 'updraftplus'), $matches[2], $matches[3]).' <a href="https://updraftplus.com/renewing-updraftplus-purchase/">'.__('To retain your access, and maintain access to updates (including future features and compatibility with future WordPress releases) and support, please renew.', 'updraftplus').'</a>'.$dismiss;
|
|
} elseif (preg_match('/(^|,)soon($|,)/', $oval->update->extraProperties[$updateskey])) {
|
|
$message = __('Your paid access to UpdraftPlus updates for this site will soon expire.', 'updraftplus').' <a href="https://updraftplus.com/renewing-updraftplus-purchase/">'.__('To retain your access, and maintain access to updates (including future features and compatibility with future WordPress releases) and support, please renew.', 'updraftplus').'</a>';
|
|
if ($updraftplus->have_addons > 14 && !empty($meta_info['indirect'])) {
|
|
$message .= ' <br>'.sprintf(__('If you have already renewed, then you need to allocate a licence to this site - %s', 'updraftplus'), '<a href="'.UpdraftPlus_Options::admin_page().'?page=updraftplus&tab=addons">'.__('go here', 'updraftplus').'</a>');
|
|
}
|
|
$this->admin_notices['updatesexpiringsoon'] = $message.$dismiss;
|
|
}
|
|
}
|
|
} elseif (!empty($do_expiry_check) && is_object($oval) && !empty($oval->update) && is_object($oval->update) && !empty($oval->update->extraProperties[$supportkey])) {
|
|
if ('expired' == $oval->update->extraProperties[$supportkey]) {
|
|
$this->admin_notices['supportexpired'] = __('Your paid access to UpdraftPlus support has expired.', 'updraftplus').' <a href="https://updraftplus.com/renewing-updraftplus-purchase/">'.__('To regain your access, please renew.', 'updraftplus').'</a>'.$dismiss;
|
|
} elseif ('soon' == $oval->update->extraProperties[$supportkey]) {
|
|
$this->admin_notices['supportsoonexpiring'] = __('Your paid access to UpdraftPlus support will soon expire.', 'updraftplus').' <a href="https://updraftplus.com/renewing-updraftplus-purchase/">'.__('To maintain your access to support, please renew.', 'updraftplus').'</a>'.$dismiss;
|
|
}
|
|
}
|
|
add_action('all_admin_notices', array($this, 'admin_notices'));
|
|
|
|
if (!function_exists('is_plugin_active')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
|
|
if (is_plugin_active('updraftplus-addons/updraftplus-addons.php')) {
|
|
deactivate_plugins('updraftplus-addons/updraftplus-addons.php');
|
|
if (('options-general.php' == $pagenow || 'settings.php' == $pagenow) && !empty($_REQUEST['page']) && 'updraftplus-addons' == $_REQUEST['page']) {
|
|
wp_redirect($this->addons_admin_url());
|
|
exit;
|
|
}
|
|
// Do nothing more this time to avoid duplication
|
|
return;
|
|
} elseif (is_dir(WP_PLUGIN_DIR.'/updraftplus-addons') && current_user_can('delete_plugins')) {
|
|
// Exists, but not active - nag them
|
|
if ((!is_multisite() && 'options-general.php' == $pagenow) || (is_multisite() && 'settings.php' == $pagenow) || 'plugins.php' == $pagenow) add_action('all_admin_notices', array($this, 'deinstall_udaddons'));
|
|
}
|
|
|
|
if (class_exists('UpdraftPlusAddons')) return;
|
|
|
|
// Refresh, if specifically requested
|
|
if ((('options-general.php' == $pagenow) || (is_multisite() && 'settings.php' == $pagenow)) && !empty($_GET['udm_refresh'])) {
|
|
if ($this->plug_updatechecker) $this->plug_updatechecker->checkForUpdates();
|
|
}
|
|
|
|
include_once(UDADDONS2_DIR.'/options.php');
|
|
$this->options = new UpdraftPlusAddOns_Options2($this->slug, __('UpdraftPlus Addons', 'updraftplus'), $this->url);
|
|
|
|
}
|
|
|
|
public function addons_admin_url() {
|
|
return UpdraftPlus_Options::admin_page().'?page='.UDADDONS2_PAGESLUG.'&tab=addons';
|
|
}
|
|
|
|
/**
|
|
* Funnelling through here a) allows for future flexibility and b) allows us to migrate elegantly from the previous non-MU-friendly setup
|
|
*
|
|
* @param string $option
|
|
* @return array
|
|
*/
|
|
public function get_option($option) {
|
|
$val = get_site_option($option);
|
|
// On multisite, migrate options into the site options
|
|
if (false === $val && is_multisite()) {
|
|
$blog_id = get_current_blog_id();
|
|
if ($blog_id>1) {
|
|
$val = get_option($option);
|
|
if (false !== $val) {
|
|
delete_option($option);
|
|
update_site_option($option, $val);
|
|
return $val;
|
|
}
|
|
}
|
|
// $val is still false
|
|
switch_to_blog(1);
|
|
$val = get_option($option);
|
|
if (false !== $val) {
|
|
delete_option($option);
|
|
update_site_option($option, $val);
|
|
}
|
|
restore_current_blog();
|
|
}
|
|
return $val;
|
|
}
|
|
|
|
/**
|
|
* Remove and update a site option
|
|
*
|
|
* @param String $option
|
|
* @param Mixed $val
|
|
*
|
|
* @return Boolean - true if the option was successfully set; otherwise false
|
|
*/
|
|
public function update_option($option, $val) {
|
|
delete_site_option($option);
|
|
return update_site_option($option, $val);
|
|
}
|
|
|
|
public function deinstall_udaddons() {
|
|
$del = '<a href="' . wp_nonce_url('plugins.php?action=delete-selected&checked[]=updraftplus-addons/updraftplus-addons.php&plugin_status=all&paged=1&s=', 'bulk-plugins') . '" title="' . esc_attr__('Delete plugin') . '" class="delete">' . 'delete the UpdraftPlus Addons Manager plugin' . '</a>';
|
|
$this->show_admin_warning('You can '.$del.' - it is obsolete (all of its functions, including your add-ons, are now included in the main UpdraftPlus plugin obtained from updraftplus.com).');
|
|
}
|
|
|
|
public function show_admin_warning($message, $class = "updated") {
|
|
echo '<div class="updraftmessage '.esc_attr($class).'"><p>'.$message.'</p></div>';// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- needs to be presented in html
|
|
}
|
|
|
|
/**
|
|
* Remove any existing updates detected
|
|
*
|
|
* @param array $updates
|
|
* @return array
|
|
*/
|
|
public function site_transient_update_plugins($updates) {
|
|
if (!is_object($updates) || empty($this->plugin_file)) return $updates;
|
|
if (isset($updates, $updates->response, $updates->response[$this->plugin_file]))
|
|
unset($updates->response[$this->plugin_file]);
|
|
return $updates;
|
|
}
|
|
|
|
/**
|
|
* We want to lessen the number of automatic checks if an update is already known to be available
|
|
*
|
|
* @param string $shouldcheck Should check if there are updates
|
|
* @param string $lastcheck Last update check
|
|
* @param string $checkperiod Period to check
|
|
* @return boolean
|
|
*/
|
|
public function puc_check_now($shouldcheck, $lastcheck, $checkperiod) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Filter use
|
|
|
|
// Skip checks immediately after a WP upgrade. This action has existed since WP 4.4. Since we're just trying to reduce server load spikes when WP core automatic security upgrades happen, that is adequate.
|
|
if (did_action('pre_auto_update')) return false;
|
|
|
|
global $wp_current_filter;
|
|
|
|
/*
|
|
* Return without any changes if no check was going to happen anyway; or, if it was, if any of these conditions match:
|
|
* - We have no checker object
|
|
* - There hasn't been a last check
|
|
* - We're on the update-core.php page
|
|
* - We're not in a cron context
|
|
*/
|
|
if (true !== $shouldcheck || empty($this->plug_updatechecker) || 0 == $lastcheck || (is_array($wp_current_filter) && in_array('load-update-core.php', $wp_current_filter)) || !defined('DOING_CRON')) return $shouldcheck;
|
|
|
|
// i.e. return unchanged result (i.e. do check if you were going to) if no update is available
|
|
if (null === $this->plug_updatechecker->getUpdate()) return $shouldcheck;
|
|
|
|
// So, now we know an update is available. In this situation, we reduce checks.
|
|
|
|
$days_since_check = max(round((time() - $lastcheck)/86400), 1);
|
|
if ($days_since_check > 10000) return true;
|
|
|
|
// Suppress checks on days 2, 4, 5, 7 and then every day except multiples of 7.
|
|
if (2 == $days_since_check || 4 == $days_since_check || 5 == $days_since_check || 7 == $days_since_check || ($days_since_check >= 7 && 0 != $days_since_check % 7)) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Send a licence claim to the licensing server
|
|
*
|
|
* @param String $key - the add-on being claimed
|
|
*
|
|
* @return WP_Error|Array - body as returned by wp_remote_post(), after JSON-decoding
|
|
*/
|
|
private function claim_addon($key) {
|
|
|
|
$options = $this->get_option(UDADDONS2_SLUG.'_options');
|
|
|
|
$post_array = array(
|
|
'e' => $options['email'],
|
|
'sid' => $this->siteid(),
|
|
'sn' => base64_encode(get_bloginfo('name')),
|
|
'su' => base64_encode(home_url()),
|
|
'key' => $key,
|
|
'si2' => json_encode($this->get_site_info()),
|
|
'response_format' => 'json'
|
|
);
|
|
|
|
$result = wp_remote_post($this->url.'/plugin-info/?udm_action=claimaddon',
|
|
array(
|
|
'timeout' => 15,
|
|
'body' => $post_array
|
|
)
|
|
);
|
|
|
|
if (!is_wp_error($result) && isset($result['body']) && null !== ($response = json_decode($result['body'])) && is_object($response) && !empty($response->code) && 'OK' === $response->code) {
|
|
// Remove the password from the stored settings, for security. We have confirmed that we can authenticate via token (SID) - which is valid for approx. a week (the user can re-enter the password if he needs to)
|
|
unset($options['password']);
|
|
$this->update_option(UDADDONS2_SLUG.'_options', $options);
|
|
} else {
|
|
|
|
// Try again with password (old-style protocol)
|
|
// The 'password' encoded here is the updraftplus.com password. See here: https://updraftplus.com/faqs/tell-me-about-my-updraftplus-com-account/
|
|
if (!empty($options['password'])) {
|
|
|
|
$post_array['p'] = base64_encode($options['password']);
|
|
|
|
$result = wp_remote_post($this->url.'/plugin-info/?udm_action=claimaddon',
|
|
array(
|
|
'timeout' => 15,
|
|
'body' => $post_array
|
|
)
|
|
);
|
|
|
|
if (!is_wp_error($result) && isset($result['body'])) $response = json_decode($result['body']);
|
|
}
|
|
}
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
/**
|
|
* Called by the WP action wp_ajax_udaddons_claimaddon
|
|
*/
|
|
public function ajax_udaddons_claimaddon() {
|
|
|
|
$nonce = empty($_REQUEST['nonce']) ? '' : $_REQUEST['nonce'];
|
|
if (!wp_verify_nonce($nonce, 'udmanager-nonce') || empty($_POST['key'])) die('Security check');
|
|
|
|
$key = $_POST['key'];
|
|
|
|
$result = $this->claim_addon($key);
|
|
|
|
if (is_wp_error($result)) {
|
|
echo esc_html__('Errors occurred:', 'updraftplus').'<br>';
|
|
show_message($result);
|
|
} elseif (is_object($result)) {
|
|
|
|
if ((!defined('UPDRAFTPLUS_ADDONS_QUICK_INSTALL') || !UPDRAFTPLUS_ADDONS_QUICK_INSTALL) && !empty($result->data->files)) {
|
|
|
|
$all_addons = array();
|
|
|
|
if (is_dir(UPDRAFTPLUS_DIR.'/addons') && $dir_handle = opendir(UPDRAFTPLUS_DIR.'/addons')) {
|
|
while (false !== ($e = readdir($dir_handle))) {
|
|
if (is_file(UPDRAFTPLUS_DIR.'/addons/'.$e) && preg_match('/\.php$/', $e)) {
|
|
$all_addons[] = $e;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($result->data->files as $file => $data) {
|
|
if (false !== strpos($file, '..')) continue;
|
|
if (preg_match('#^addons/(.*\.php)$#', $file, $matches)) {
|
|
$all_addons[] = $matches[1];
|
|
}
|
|
}
|
|
|
|
$all_addons = array_unique($all_addons);
|
|
|
|
$new_sub_version = ('all' == $key || count($all_addons) > 15 ) ? count($all_addons) + 1 : count($all_addons);
|
|
|
|
foreach ($result->data->files as $file => $data) {
|
|
|
|
if (false !== strpos($file, '..')) continue;
|
|
|
|
if ('updraftplus.php' != $file && !preg_match('#^addons/.*\.php$#', $file)) continue;
|
|
|
|
if (false == ($decompressed = gzuncompress(base64_decode($data)))) continue;
|
|
|
|
// Check the basic sanity of the incoming data
|
|
$start = substr($decompressed, 0, 128);
|
|
|
|
if ('updraftplus.php' == $file && false === strpos($start, 'Plugin Name: UpdraftPlus')) continue;
|
|
|
|
if (preg_match('#^addons/.*\.php$#', $file) && false === strpos($start, 'UpdraftPlus Addon:')) continue;
|
|
|
|
if ('updraftplus.php' == $file) $decompressed = preg_replace('/\nVersion: \d+\.(\d+\.\d+)/', "\n".'Version: 2.$1.'.$new_sub_version, $decompressed, 1);
|
|
|
|
if (false == file_put_contents(UPDRAFTPLUS_DIR.'/'.$file, $decompressed)) {
|
|
$addons_written = false;
|
|
break;
|
|
}
|
|
|
|
$addons_written = true;
|
|
}
|
|
}
|
|
|
|
$result->check_updates = true;
|
|
|
|
if (!empty($addons_written)) $result->addons_written = true;
|
|
|
|
// If the results included update information, then store that
|
|
if (!empty($result->data) && !empty($result->data->plugin_info) && !empty($this->plug_updatechecker)) {
|
|
|
|
// e.g. Puc_v4p9_Plugin_UpdateChecker
|
|
$checker_class = get_class($this->plug_updatechecker);
|
|
|
|
// Hopefully take off the 'Checker'. The setUpdate() call below wants a compatible version.
|
|
$plugin_update_class = substr($checker_class, 0, strlen($checker_class)-7);
|
|
|
|
if (class_exists($plugin_update_class) && is_callable(array($plugin_update_class, 'fromObject'))) {
|
|
|
|
// $plugin_update_class::fromObject() is invalid syntax on PHP 5.2
|
|
$plugin_update = call_user_func(array($plugin_update_class, 'fromObject'), $result->data->plugin_info);
|
|
|
|
$update_checker = $this->plug_updatechecker;
|
|
|
|
$installed_version = $update_checker->getInstalledVersion();
|
|
|
|
if (null !== $installed_version) {
|
|
|
|
$state = $update_checker->getUpdateState();
|
|
$state->setLastCheckToNow()->setCheckedVersion($installed_version);
|
|
$state->setUpdate($plugin_update);
|
|
$state->save();
|
|
|
|
$result->check_updates = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
// Removed only because it is unnecessary
|
|
unset($result->data);
|
|
|
|
echo json_encode($result);
|
|
} else {
|
|
echo esc_html(__('Errors occurred:', 'updraftplus').' '.serialize($result));
|
|
}
|
|
|
|
die;
|
|
|
|
}
|
|
|
|
/**
|
|
* Return a reasonably unique ID for the site
|
|
*
|
|
* @return String
|
|
*/
|
|
public function siteid() {
|
|
$sid = get_site_option(UDADDONS2_SLUG.'_siteid');
|
|
if (!is_string($sid) || empty($sid)) {
|
|
$sid = md5(rand().microtime(true).home_url());
|
|
update_site_option(UDADDONS2_SLUG.'_siteid', $sid);
|
|
}
|
|
return $sid;
|
|
}
|
|
|
|
/**
|
|
* Return site information
|
|
*
|
|
* @return Array - which can be json_encode()-ed.
|
|
*/
|
|
private function get_site_info() {
|
|
|
|
global $wp_version, $updraftplus;
|
|
|
|
include(ABSPATH.WPINC.'/version.php');
|
|
|
|
$site_info = array(
|
|
'wp' => $wp_version,
|
|
'php' => PHP_VERSION,
|
|
'multi' => is_multisite() ? 1 : 0,
|
|
'mem' => ini_get('memory_limit'),
|
|
'lang' => (string) get_locale()
|
|
);
|
|
|
|
// Since 3.7.0
|
|
if (function_exists('wp_get_installed_translations')) {
|
|
$all_translations = wp_get_installed_translations('plugins');
|
|
if (isset($all_translations[$this->slug])) {
|
|
foreach ($all_translations[$this->slug] as $locale => $tinfo) {
|
|
$found_existing = false;
|
|
if (isset($tinfo['PO-Revision-Date'])) {
|
|
$found_existing = strtotime($tinfo['PO-Revision-Date']);
|
|
}
|
|
$site_info['trans'][$locale]['d'] = $found_existing;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_a($updraftplus, 'UpdraftPlus') && isset($updraftplus->version)) {
|
|
$site_info['ud'] = $updraftplus->version;
|
|
if (class_exists('UpdraftPlus_Options')) $site_info['service'] = json_encode(UpdraftPlus_Options::get_updraft_option('updraft_service'));
|
|
}
|
|
|
|
return $site_info;
|
|
}
|
|
|
|
/**
|
|
* Modifies the query arguments on the updates request
|
|
*
|
|
* @param Array $args - unfiltered arguments
|
|
*
|
|
* @return Array - filtered arguments
|
|
*/
|
|
public function updater_queryargs_plugin($args) {
|
|
if (!is_array($args)) return $args;
|
|
|
|
$options = $this->get_option(UDADDONS2_SLUG.'_options');
|
|
$email = isset($options['email']) ? $options['email'] : '';
|
|
$args['udm_action'] = 'updateinfo';
|
|
|
|
$args['sid'] = $this->siteid();
|
|
$args['su'] = urlencode(base64_encode(home_url()));
|
|
$args['sn'] = urlencode(base64_encode(get_bloginfo('name')));
|
|
$args['slug'] = urlencode($this->slug);
|
|
$args['e'] = urlencode($email);
|
|
|
|
if (defined('UPDRAFTPLUS_ADDONS_SSL') && UPDRAFTPLUS_ADDONS_SSL == true) $args['ssl'] = 1;
|
|
|
|
// Some information on the server calling. This can be used - e.g. if they have an old version of PHP/WordPress, then this may affect what update version they should be offered
|
|
$args['si2'] = urlencode(base64_encode(json_encode($this->get_site_info())));
|
|
|
|
// Unset a couple of values set by version 4.0+ of plugin-updates-checker
|
|
unset($args['php']);
|
|
unset($args['locale']);
|
|
|
|
return $args;
|
|
}
|
|
|
|
/**
|
|
* This function, if ever changed, should be kept in sync with the same function in udmanager.php
|
|
*
|
|
* @param String $file
|
|
* @return Boolean|Array
|
|
*/
|
|
private function get_addon_info($file) {
|
|
if ($f = fopen($file, 'r')) {
|
|
$key = "";
|
|
$name = "";
|
|
$description = "";
|
|
$version = "";
|
|
$shopurl = "";
|
|
$latestchange = null;
|
|
$lines_read = 0;
|
|
while ($lines_read<10 && $line = @fgets($f)) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
|
|
if ("" == $key && preg_match('/Addon: ([^:]+):(.*)$/i', $line, $lmatch)) {
|
|
$key = $lmatch[1];
|
|
$name = $lmatch[2];
|
|
} elseif ("" == $description && preg_match('/Description: (.*)$/i', $line, $lmatch)) {
|
|
$description = $lmatch[1];
|
|
} elseif ("" == $version && preg_match('/Version: (.*)$/i', $line, $lmatch)) {
|
|
$version = $lmatch[1];
|
|
} elseif ("" == $shopurl && preg_match('/Shop: (.*)$/i', $line, $lmatch)) {
|
|
$shopurl = $lmatch[1];
|
|
} elseif ("" == $latestchange && preg_match('/Latest Change: (.*)$/i', $line, $lmatch)) {
|
|
$latestchange = $lmatch[1];
|
|
}
|
|
$lines_read++;
|
|
}
|
|
fclose($f);
|
|
if ($key && $name && $description && $version) {
|
|
return array('key' => $key, 'name' => $name, 'description' => $description, 'installedversion' => $version, 'shopurl' => $shopurl, 'latestchange' => $latestchange);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private function get_default_addons() {
|
|
return array(
|
|
'noadverts' => array(
|
|
'name' => 'Remove adverts',
|
|
'description' => 'Removes all adverts from the control panel and emails',
|
|
'shopurl' => '/shop/updraftplus-premium/'
|
|
),
|
|
'all' => array(
|
|
'name' => 'All addons',
|
|
'description' => 'Access to all UpdraftPlus add-ons',
|
|
'shopurl' => '/shop/updraftplus-premium/'
|
|
),
|
|
'multisite' => array(
|
|
'name' => 'WordPress Network (multisite) support',
|
|
'description' => 'Adds support for WordPress Network (multisite) installations, allowing secure backup by the super-admin only',
|
|
'shopurl' => '/shop/updraftplus-premium/'
|
|
),
|
|
'fixtime' => array(
|
|
'name' => 'Fix Time',
|
|
'description' => 'Allows you to specify the exact time at which backups will run',
|
|
'shopurl' => '/shop/updraftplus-premium/'
|
|
),
|
|
'morefiles' => array(
|
|
'name' => 'More Files',
|
|
'description' => 'Allows you to backup WordPress core, and other files in your web space',
|
|
'shopurl' => '/shop/updraftplus-premium/'
|
|
),
|
|
'sftp' => array(
|
|
'name' => 'SFTP and FTPS and SCP',
|
|
'description' => 'Allows SFTP and SCP as a cloud backup method, and encrypted FTP',
|
|
'shopurl' => '/shop/updraftplus-premium/'
|
|
),
|
|
'dropbox-folders' => array(
|
|
'name' => 'Dropbox Folders',
|
|
'description' => 'Allows you to organise your backups into Dropbox sub-folders',
|
|
'shopurl' => '/shop/updraftplus-premium/'
|
|
),
|
|
'morestorage' => array(
|
|
'name' => 'Multiple storage destinations',
|
|
'description' => 'Allows you to send a single backup to multiple destinations (e.g. Dropbox and Google Drive and Amazon)',
|
|
'shopurl' => '/shop/updraftplus-premium/'
|
|
),
|
|
'webdav' => array(
|
|
'name' => 'WebDAV support',
|
|
'description' => 'Allows you to use the WebDAV and encrypted WebDAV protocols for remote backups',
|
|
'shopurl' => '/shop/updraftplus-premium/'
|
|
)
|
|
);
|
|
}
|
|
|
|
private function get_local_addons($long_form = true) {
|
|
|
|
$plugin_dir = WP_PLUGIN_DIR.'/'.$this->slug;
|
|
|
|
if (!is_dir($plugin_dir.'/addons')) return array();
|
|
$local_addons = array();
|
|
if ($dir_handle = @opendir($plugin_dir.'/addons')) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
|
|
while (false !== ($e = readdir($dir_handle))) {
|
|
if (is_file($plugin_dir.'/addons/'.$e) && preg_match('/^(.*)\.php$/i', $e, $matches)) {
|
|
$addon = $this->get_addon_info($plugin_dir.'/addons/'.$e);
|
|
if (is_array($addon)) {
|
|
$key = $addon['key'];
|
|
if ($long_form) {
|
|
$local_addons[$key] = $addon;
|
|
} else {
|
|
$local_addons[] = $key;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $local_addons;
|
|
|
|
}
|
|
|
|
/**
|
|
* Get a list of available add-ons
|
|
*
|
|
* @return Array
|
|
*/
|
|
public function get_available_addons() {
|
|
|
|
// Cached in this object?
|
|
if (is_array($this->available_addons)) return $this->available_addons;
|
|
|
|
// The remote list may be cached in a site transient
|
|
$potential_array = get_site_transient('upaddons_remote');
|
|
if (false == $this->debug && is_array($potential_array) && isset($potential_array['all'])) {
|
|
$this->remote_addons = $potential_array;
|
|
$remote_addons = $potential_array;
|
|
} else {
|
|
|
|
$url = $this->url.'/plugin-info/?udm_action=listaddons&response_format=json';
|
|
|
|
$result = wp_remote_get($url, array('timeout' => 15));
|
|
|
|
if (!is_wp_error($result) & false !== $result) {
|
|
$response = json_decode($result['body'], true);
|
|
|
|
$remote_addons = array();
|
|
|
|
if (is_array($response) && isset($response['addons'])) {
|
|
$addons = $response['addons'];
|
|
// One more sanity check
|
|
if (isset($addons['all'])) {
|
|
$remote_addons = $addons;
|
|
// Cache it
|
|
$this->remote_addons = $addons;
|
|
set_site_transient('upaddons_remote', $addons, 14400);
|
|
}
|
|
}
|
|
} else {
|
|
// Populate with default
|
|
$remote_addons = $this->get_default_addons();
|
|
}
|
|
|
|
}
|
|
|
|
// Perhaps we have some installed that have been obsoleted/removed upstream
|
|
|
|
$installed_addons = $this->get_local_addons();
|
|
|
|
$all_addons = array();
|
|
foreach ($remote_addons as $key => $addon) {
|
|
// Can then get over-ridden
|
|
$addon['installed'] = false;
|
|
$all_addons[$key] = $addon;
|
|
}
|
|
|
|
foreach ($installed_addons as $key => $addon) {
|
|
if (isset($all_addons[$key])) {
|
|
// The remote info over-writes all else
|
|
$newaddon = $all_addons[$key];
|
|
$newaddon['installed'] = true;
|
|
$newaddon['installedversion'] = $addon['installedversion'];
|
|
|
|
} else {
|
|
$newaddon = $addon;
|
|
if (!empty($newaddon['installedversion'])) $newaddon['installed'] = true;
|
|
}
|
|
$all_addons[$key] = $newaddon;
|
|
}
|
|
|
|
$this->available_addons = $all_addons;
|
|
return $all_addons;
|
|
|
|
}
|
|
|
|
/**
|
|
* This function will get the connection status
|
|
*
|
|
* @return boolean|WP_Error - returns true if successful
|
|
*/
|
|
public function connection_status() {
|
|
|
|
$options = $this->get_option(UDADDONS2_SLUG.'_options');
|
|
|
|
$try_siteid = false;
|
|
|
|
$oval = is_object($this->plug_updatechecker) ? get_site_option($this->plug_updatechecker->optionName, null) : null;
|
|
// Detect the case where the password has been removed
|
|
if (is_object($oval) && !empty($oval->lastCheck) && time()-$oval->lastCheck < 86400*8) {
|
|
$try_siteid = $this->siteid();
|
|
}
|
|
|
|
// Username and password set up?
|
|
if (empty($options['email']) || (empty($options['password']) && false == $try_siteid)) return new WP_Error('blank_details', __('You need to supply both an email address and a password', 'updraftplus'));
|
|
|
|
// Hash will change if the account changes (password change is handled by the options filter)
|
|
$ehash = substr(md5($options['email']), 0, 23);
|
|
$trans = get_site_transient('udaddons_connect_'.$ehash);
|
|
|
|
// In debug mode, we don't cache
|
|
if (true !== $this->debug && empty($_GET['udm_refresh']) && is_array($trans)) {
|
|
if (isset($trans['myaddons']) && is_array($trans['myaddons'])) {
|
|
$this->user_addons = $trans['myaddons'];
|
|
}
|
|
if (isset($trans['availableaddons']) && is_array($trans['availableaddons'])) {
|
|
$this->remote_addons = $trans['availableaddons'];
|
|
}
|
|
if (isset($trans['support']) && is_array($trans['support'])) {
|
|
$this->user_support = $trans['support'];
|
|
}
|
|
return true;
|
|
}
|
|
|
|
$password = isset($options['password']) ? $options['password'] : '';
|
|
|
|
$connect = $this->connect($options['email'], $password);
|
|
|
|
if (is_wp_error($connect)) return $connect;
|
|
if (false === $connect) return new WP_Error('failed_connection', __('We failed to successfully connect to UpdraftPlus.Com', 'updraftplus'));
|
|
|
|
if (!is_bool($connect)) return new WP_Error('bad_response', __('UpdraftPlus.Com responded, but we did not understand the response', 'updraftplus'));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns either true (in which case the add-ons array is populated), or a WP_Error
|
|
*
|
|
* @param string $email Email for the remote post array
|
|
* @param string $password Password for the remote post array
|
|
* @return boolean
|
|
*/
|
|
private function connect($email, $password) {
|
|
|
|
global $updraftplus;
|
|
|
|
// Use previous response, if available
|
|
if (is_array($this->user_addons) && count($this->user_addons) > 0) return true;
|
|
|
|
$url = $this->url.'/plugin-info/?udm_action=connect';
|
|
|
|
// The 'password' encoded here is the updraftplus.com password. See here: https://updraftplus.com/faqs/tell-me-about-my-updraftplus-com-account/. Note - it may be empty if the user removed their password.
|
|
$result = wp_remote_post($url,
|
|
array(
|
|
'timeout' => 15,
|
|
'body' => array(
|
|
'e' => $email,
|
|
'p' => base64_encode($password),
|
|
'sid' => $this->siteid(),
|
|
'sn' => base64_encode(get_bloginfo('name')),
|
|
'su' => base64_encode(home_url()),
|
|
'f' => 2
|
|
)
|
|
)
|
|
);
|
|
|
|
if (is_wp_error($result) || false === $result) return $result;
|
|
|
|
$code = wp_remote_retrieve_response_code($result);
|
|
|
|
if ($code >= 400) {
|
|
|
|
$message = __('An error response was received; HTTP code:', 'updraftplus').' '.$code;
|
|
|
|
$headers = wp_remote_retrieve_headers($result);
|
|
|
|
if (!empty($headers['cf-ray'])) {
|
|
$message .= ' CF-Ray: '.$headers['cf-ray'];
|
|
}
|
|
|
|
if (403 == $code) {
|
|
$ip_addr = $updraftplus->get_outgoing_ip_address(true);
|
|
if (false !== $ip_addr && false !== filter_var($ip_addr, FILTER_VALIDATE_IP)) {
|
|
$message .= ' IP: '.htmlspecialchars($ip_addr);
|
|
|
|
$message .= '<br>'.__('This most likely means that you share a webserver with a hacked website that has been used in previous attacks.', 'updraftplus').'<br> <a href="https://updraftplus.com/unblock-ip-address/" target="_blank">'.__('To remove any block, please go here.', 'updraftplus').'</a> '.__('Your IP address:', 'updraftplus').' '.htmlspecialchars($ip_addr);
|
|
|
|
}
|
|
}
|
|
|
|
return new WP_Error('error_response', $message, $result);
|
|
}
|
|
|
|
$response = json_decode($result['body'], true);
|
|
|
|
if (!is_array($response) || !isset($response['updraftpluscom']) || !isset($response['loggedin'])) {
|
|
$ser_resp = htmlspecialchars(serialize($response));
|
|
if (preg_match('/has banned your IP address \(([\.:0-9a-f]+)\)/', $response, $matches)) {
|
|
return new WP_Error('banned_ip', sprintf(__("UpdraftPlus.com has responded with 'Access Denied'.", 'updraftplus').'<br>'.__("It appears that your web server's IP Address (%s) is blocked.", 'updraftplus').' '.__('This most likely means that you share a webserver with a hacked website that has been used in previous attacks.', 'updraftplus').'<br> <a href="https://updraftplus.com/unblock-ip-address/" target="_blank">'.__('To remove any block, please go here.', 'updraftplus').'</a> ', $matches[1]));
|
|
} else {
|
|
if (null === $ser_resp) {
|
|
return new WP_Error('unknown_response', __('No response data was received.', 'updraftplus').' '.__('This usually indicates a network connectivity issue (e.g. an outgoing firewall or overloaded network) between this site and UpdraftPlus.com.', 'updraftplus'));
|
|
} else {
|
|
return new WP_Error('unknown_response', sprintf(__('UpdraftPlus.Com returned a response which we could not understand (data: %s)', 'updraftplus'), $ser_resp));
|
|
}
|
|
}
|
|
}
|
|
|
|
switch ($response['loggedin']) {
|
|
case 'connected':
|
|
if (isset($response['myaddons']) && is_array($response['myaddons'])) {
|
|
$this->user_addons = $response['myaddons'];
|
|
}
|
|
if (isset($response['availableaddons']) && is_array($response['availableaddons'])) {
|
|
$this->remote_addons = $response['availableaddons'];
|
|
set_site_transient('upaddons_remote', $this->remote_addons, 14400);
|
|
}
|
|
if (isset($response['support']) && is_array($response['support'])) {
|
|
$this->user_support = $response['support'];
|
|
}
|
|
$ehash = substr(md5($email), 0, 23);
|
|
|
|
set_site_transient('udaddons_connect_'.$ehash, $response, 7200);
|
|
|
|
// Now, trigger an update check, since things may have changed
|
|
if ($this->plug_updatechecker) $this->plug_updatechecker->checkForUpdates();
|
|
break;
|
|
|
|
case 'authfailed':
|
|
$ehash = substr(md5($email), 0, 23);
|
|
delete_site_transient('udaddons_connect_'.$ehash);
|
|
if (!empty($response['authproblem'])) {
|
|
if ('invalidpassword' == $response['authproblem']) {
|
|
$authfail_error = new WP_Error('authfailed', __("Your email is valid, but your password wasn't recognised.", 'updraftplus').'<br>');
|
|
if (time() < strtotime('2026-01-01 00:00:00')) $authfail_error->add('authfailed', __('Some users were asked to reset their passwords as part of a recent website migration.', 'updraftplus').'<br>');
|
|
// translators: %s: The reset password link
|
|
$authfail_error->add('authfailed', sprintf(__('Try again, or %s before connecting again.', 'updraftplus'), '<a href="'.$updraftplus->get_url('lost-password').'">'.__('reset your password', 'updraftplus').'</a>'));
|
|
return $authfail_error;
|
|
} elseif ('invaliduser' == $response['authproblem']) {
|
|
return new WP_Error('authfailed', __('You entered an email address that was not recognised by UpdraftPlus.Com', 'updraftplus'));
|
|
}
|
|
}
|
|
return new WP_Error('authfailed', __('Your email address and password were not recognised by UpdraftPlus.Com', 'updraftplus'));
|
|
break;
|
|
|
|
default:
|
|
return new WP_Error('unknown_response', __('UpdraftPlus.Com returned a response, but we could not understand it', 'updraftplus'));
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
}
|