Phase 6: AIOS security plugin with conservative login lockdown config (10 attempts)
This commit is contained in:
Vendored
Executable
+17
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="UpdraftPlus">
|
||||
<!-- How to run on Commandline: vendor/bin/phpcs -p -s -d memory_limit=150M \-\-standard=CI/php-compatibility.xml src/ \-\-report-full \-\-extensions=php -->
|
||||
<description>UpdraftPlus PHP Compatibility Check</description>
|
||||
<!-- Set Memory Limit -->
|
||||
<ini name="memory_limit" value="150M"/>
|
||||
<!-- CI Cache -->
|
||||
<arg name="cache" value="../CI/phpcs-cache-compatibility"/>
|
||||
<!-- Check up to 4 files simultanously. -->
|
||||
<arg name="parallel" value="4"/>
|
||||
<!-- Only Test for PHP 5.2+ -->
|
||||
<config name="testVersion" value="5.2-"/>
|
||||
<!-- Ignoring Folders As they are part of Vendor packages -->
|
||||
<!-- <exclude-pattern>src/tools/customer-tools/vendor</exclude-pattern> -->
|
||||
<!-- PHPCompatibility -->
|
||||
<rule ref="PHPCompatibility"/>
|
||||
</ruleset>
|
||||
Vendored
Executable
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="UpdraftPlus">
|
||||
<description>UpdraftPlus PHP Syntax Check</description>
|
||||
<!-- Set Memory Limit -->
|
||||
<ini name="memory_limit" value="150M"/>
|
||||
<!-- CI Cache -->
|
||||
<arg name="cache" value="../CI/phpcs-cache-syntax-check"/>
|
||||
<!-- Check up to 4 files simultanously. -->
|
||||
<arg name="parallel" value="4"/>
|
||||
<!-- Check for PHP syntax errors -->
|
||||
<rule ref="Generic.PHP.Syntax"/>
|
||||
</ruleset>
|
||||
Vendored
Executable
+10
@@ -0,0 +1,10 @@
|
||||
# Common Libraries
|
||||
|
||||
This project contains many useful libraries that are currently used and can be reused across our projects. They are kept here for easy maintenance and also so that consumers get a uniform interface and things dont break across versions or on updates.
|
||||
|
||||
CHANGELOG
|
||||
* TWEAK: Port from previous semaphore classes to Updraft_Semaphore_3_0 in updraft-tasks
|
||||
* FIX: Wrong query value in `delete_task_meta` method
|
||||
* TWEAK: Make the logging format uniform
|
||||
* FIX: Wrong DB Schema reference
|
||||
* TWEAK: Logging on the semaphore
|
||||
wp-content/plugins/all-in-one-wp-security-and-firewall/vendor/team-updraft/common-libs/composer.json
Vendored
Executable
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "team-updraft/common-libs",
|
||||
"description": "These are the common libs used across all of our projects",
|
||||
"type": "library",
|
||||
"license": "GPL-3.0-only",
|
||||
"authors": [{
|
||||
"name": "Team Updraft",
|
||||
"email": "team.updraft@gmail.com"
|
||||
}],
|
||||
"config": {
|
||||
"platform-check": false
|
||||
},
|
||||
"require-dev": {
|
||||
"squizlabs/php_codesniffer": "3.6.*",
|
||||
"phpcompatibility/php-compatibility": "9.3.*",
|
||||
"wp-coding-standards/wpcs": "2.3.*",
|
||||
"sirbrillig/phpcs-variable-analysis": "2.11.*",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "0.7.*"
|
||||
},
|
||||
"prefer-stable" : true
|
||||
}
|
||||
Vendored
Executable
+220
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access allowed');
|
||||
|
||||
abstract class Updraft_Notices_1_2 {
|
||||
|
||||
protected $notices_content;
|
||||
|
||||
// These variables are just short-hands to be used in advert content.
|
||||
protected $dashboard_top = array('top');
|
||||
|
||||
protected $dashboard_top_or_report = array('top', 'report', 'report-plain');
|
||||
|
||||
protected $dashboard_bottom_or_report = array('bottom', 'report', 'report-plain');
|
||||
|
||||
protected $anywhere = array('top', 'bottom', 'report', 'report-plain');
|
||||
|
||||
protected $autobackup = array('autobackup');
|
||||
|
||||
protected $autobackup_bottom_or_report = array('autobackup', 'bottom', 'report', 'report-plain');
|
||||
|
||||
/**
|
||||
* Global adverts that appear in all products will be returned to the child to display
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function populate_notices_content() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method to setup the notices.
|
||||
*/
|
||||
abstract protected function notices_init();
|
||||
|
||||
/**
|
||||
* Checks if the plugin is installed and checks status if needed.
|
||||
*
|
||||
* @param null $product - Plugin to check
|
||||
* @param boolean $also_require_active - bool to indicate if active status is required or not
|
||||
*
|
||||
* @return boolean Returns true, if plugin is installed otherwise false
|
||||
*/
|
||||
protected function is_plugin_installed($product = null, $also_require_active = false) {
|
||||
if ($also_require_active) return class_exists($product);
|
||||
if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
|
||||
$plugins = get_plugins();
|
||||
foreach ($plugins as $value) {
|
||||
if ($value['TextDomain'] == $product) {
|
||||
// We have found the plugin so return false so that we do not display this advert.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if translation is needed or not
|
||||
*
|
||||
* @param string $plugin_base_dir - Base directory of plugin
|
||||
* @param string $product_name - Plugin name
|
||||
*
|
||||
* @return boolean Returns true if translation is needed, otherwise false
|
||||
*/
|
||||
protected function translation_needed($plugin_base_dir, $product_name) {
|
||||
$wplang = get_locale();
|
||||
if (strlen($wplang) < 1 || 'en_US' == $wplang || 'en_GB' == $wplang) return false;
|
||||
if (defined('WP_LANG_DIR') && is_file(WP_LANG_DIR.'/plugins/'.$product_name.'-'.$wplang.'.mo')) return false;
|
||||
if (is_file($plugin_base_dir.'/languages/'.$product_name.'-'.$wplang.'.mo')) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the start of a HTML URL
|
||||
*
|
||||
* @param boolean $html_allowed - indicates if HTML is allowed or not
|
||||
* @param string $url - the URL
|
||||
* @param boolean $https - the protocol to use
|
||||
* @param string $website_home - the product website name
|
||||
*
|
||||
* @return string returns a partial HTML URL
|
||||
*/
|
||||
protected function url_start($html_allowed, $url, $https = false, $website_home = null) {
|
||||
$proto = ($https) ? 'https' : 'http';
|
||||
if (strpos($url, $website_home) !== false) {
|
||||
return $html_allowed ? "<a href=".apply_filters(str_replace('.', '_', $website_home).'_link', $proto.'://'.$url).'>' : '';
|
||||
} else {
|
||||
return $html_allowed ? '<a href="'.$proto.'://'.$url.'">' : '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the end of a HTML URL
|
||||
*
|
||||
* @param boolean $html_allowed - indicates if HTML is allowed or not
|
||||
* @param string $url - the URL
|
||||
* @param boolean $https - the protocol to use
|
||||
*
|
||||
* @return string returns a partial HTML URL
|
||||
*/
|
||||
protected function url_end($html_allowed, $url, $https = false) {
|
||||
$proto = $https ? 'https' : 'http';
|
||||
return $html_allowed ? '</a>' : ' ('.$proto.'://'.$url.')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders notice
|
||||
*
|
||||
* @param mixed $notice - a specific notice to render or false
|
||||
* @param string $position - position of the notice
|
||||
* @param boolean $return_instead_of_echo - indicates if we should echo notice or return as string
|
||||
*
|
||||
* @return mixed Returns string or echos notice
|
||||
*/
|
||||
public function do_notice($notice = false, $position = 'top', $return_instead_of_echo = false) {
|
||||
|
||||
$this->notices_init();
|
||||
|
||||
if (false === $notice) $notice = apply_filters('updraft_notices_force_id', false, $this);
|
||||
|
||||
$notice_content = $this->get_notice_data($notice, $position);
|
||||
|
||||
if (false != $notice_content) {
|
||||
return $this->render_specified_notice($notice_content, $return_instead_of_echo, $position);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return a notice ready for display.
|
||||
*
|
||||
* @param boolean $notice - a specific notice to render or false
|
||||
* @param string $position - position of the notice
|
||||
*
|
||||
* @return array returns notice data
|
||||
*/
|
||||
protected function get_notice_data($notice = false, $position = 'top') {
|
||||
|
||||
// If a specific notice has been passed to this method then return that notice.
|
||||
if ($notice) {
|
||||
if (!isset($this->notices_content[$notice])) return false;
|
||||
|
||||
// Does the notice support the position specified?
|
||||
if (isset($this->notices_content[$notice]['supported_positions']) && !in_array($position, $this->notices_content[$notice]['supported_positions'])) return false;
|
||||
|
||||
// First check if the advert passed can be displayed and hasn't been dismissed, we do this by checking what dismissed value we should be checking.
|
||||
$dismiss_time = $this->notices_content[$notice]['dismiss_time'];
|
||||
|
||||
$dismiss = $this->check_notice_dismissed($dismiss_time);
|
||||
|
||||
if ($dismiss) return false;
|
||||
|
||||
// If the advert has a validity function, then require the advert to be valid
|
||||
if (!empty($this->notices_content[$notice]['validity_function']) && !call_user_func(array($this, $this->notices_content[$notice]['validity_function']))) return false;
|
||||
|
||||
return $this->notices_content[$notice];
|
||||
}
|
||||
|
||||
// Create an array to add non-seasonal adverts to so that if a seasonal advert can't be returned we can choose a random advert from this array.
|
||||
$available_notices = array();
|
||||
|
||||
// If Advert wasn't passed then next we should check to see if a seasonal advert can be returned.
|
||||
foreach ($this->notices_content as $notice_id => $notice_data) {
|
||||
// Does the notice support the position specified?
|
||||
if (isset($this->notices_content[$notice_id]['supported_positions']) && !in_array($position, $this->notices_content[$notice_id]['supported_positions'])) continue;
|
||||
|
||||
// If the advert has a validity function, then require the advert to be valid.
|
||||
if (!empty($notice_data['validity_function']) && !call_user_func(array($this, $notice_data['validity_function']))) continue;
|
||||
|
||||
|
||||
if (isset($notice_data['valid_from']) && isset($notice_data['valid_to'])) {
|
||||
if ($this->skip_seasonal_notices($notice_data)) return $notice_data;
|
||||
} else {
|
||||
$dismiss_time = $this->notices_content[$notice_id]['dismiss_time'];
|
||||
$dismiss = $this->check_notice_dismissed($dismiss_time);
|
||||
|
||||
if (!$dismiss) $available_notices[$notice_id] = $notice_data;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($available_notices)) return false;
|
||||
|
||||
// If a seasonal advert can't be returned then we will return a random advert.
|
||||
|
||||
// Here we give a 25% chance for the rate advert to be returned before selecting a random advert from the entire collection which also includes the rate advert
|
||||
if (0 == rand(0, 3) && isset($available_notices['rate'])) return $available_notices['rate'];
|
||||
|
||||
// Using shuffle here as something like rand which produces a random number and uses that as the array index fails, this is because in future an advert may not be numbered and could have a string as its key which will then cause errors.
|
||||
shuffle($available_notices);
|
||||
return $available_notices[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip seasonal notices
|
||||
*
|
||||
* @param array $notice_data - an array of data for the chosen notice
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function skip_seasonal_notices($notice_data) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns affiliate ID
|
||||
*
|
||||
* @return mixed Returns affiliate ID
|
||||
*/
|
||||
public function get_affiliate_id() {
|
||||
return $this->self_affiliate_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the notice has been dismissed
|
||||
*
|
||||
* @param string $dismiss_time - dismiss time
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function check_notice_dismissed($dismiss_time);
|
||||
}
|
||||
Vendored
Executable
+1127
File diff suppressed because it is too large
Load Diff
Vendored
Executable
+213
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
/**
|
||||
* Class Updraft_Semaphore_3_0
|
||||
*
|
||||
* This class is much simpler to use than the the previous series, as it has dropped support for complicated cases that were not being used. It also now only uses a single row in the options database, and takes care of creating it itself internally.
|
||||
*
|
||||
* Logging, though, may be noisier, unless your loggers are taking note of the log level and only registering what is required.
|
||||
*
|
||||
* Example of use (a lock that will expire if not released within 300 seconds)
|
||||
*
|
||||
* See test.php for a longer example (including logging).
|
||||
*
|
||||
* $my_lock = new Updraft_Semaphore_3_0('my_lock_name', 300);
|
||||
* // If getting the lock does not succeed first time, try again up to twice
|
||||
* if ($my_lock->lock(2)) {
|
||||
* try {
|
||||
* // do stuff ...
|
||||
* } catch (Exception $e) {
|
||||
* // We are making sure we release the lock in case of an error
|
||||
* } catch (Error $e) {
|
||||
* // We are making sure we release the lock in case of an error
|
||||
* }
|
||||
* $my_lock->release();
|
||||
* } else {
|
||||
* error_log("Sorry, could not get the lock");
|
||||
* }
|
||||
*/
|
||||
class Updraft_Semaphore_3_0 {
|
||||
|
||||
// Time after which the lock will expire (in seconds)
|
||||
protected $locked_for;
|
||||
|
||||
// Name for the lock in the WP options table
|
||||
protected $option_name;
|
||||
|
||||
// Lock status - a boolean
|
||||
protected $acquired = false;
|
||||
|
||||
// An array of loggers
|
||||
protected $loggers = array();
|
||||
|
||||
/**
|
||||
* Constructor. Instantiating does not lock anything, but sets up the details for future operations.
|
||||
*
|
||||
* @param String $name - a unique (across the WP site) name for the lock. Should be no more than 51 characters in length (because of the use of the WP options table, with some further characters used internally)
|
||||
* @param Integer $locked_for - time (in seconds) after which the lock will expire if not released. This needs to be positive if you don't want bad things to happen.
|
||||
* @param Array $loggers - an array of loggers
|
||||
*/
|
||||
public function __construct($name, $locked_for = 300, $loggers = array()) {
|
||||
$this->option_name = 'updraft_lock_'.$name;
|
||||
$this->locked_for = $locked_for;
|
||||
$this->loggers = $loggers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to make sure that the lock is set up in the database
|
||||
*
|
||||
* @return Integer - 0 means 'failed' (which could include that someone else concurrently created it); 1 means 'already existed'; 2 means 'exists, because we created it). The intention is that non-zero results mean that the lock exists.
|
||||
*/
|
||||
private function ensure_database_initialised() {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$sql = $wpdb->prepare("SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name = %s", $this->option_name);
|
||||
|
||||
if (1 === (int) $wpdb->get_var($sql)) {
|
||||
$this->log('Lock option ('.$this->option_name.', '.$wpdb->options.') already existed in the database', 'debug');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$sql = $wpdb->prepare("INSERT INTO {$wpdb->options} (option_name, option_value, autoload) VALUES(%s, '0', 'no');", $this->option_name);
|
||||
|
||||
$rows_affected = $wpdb->query($sql);
|
||||
|
||||
if ($rows_affected > 0) {
|
||||
$this->log('Lock option ('.$this->option_name.', '.$wpdb->options.') was created in the database', 'debug');
|
||||
} else {
|
||||
$this->log('Lock option ('.$this->option_name.', '.$wpdb->options.') failed to be created in the database (could already exist)', 'notice');
|
||||
}
|
||||
|
||||
return ($rows_affected > 0) ? 2 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to acquire the lock. If it was already acquired, then nothing extra will be done (the method will be a no-op).
|
||||
*
|
||||
* @param Integer $retries - how many times to retry (after a 1 second sleep each time)
|
||||
*
|
||||
* @return Boolean - whether the lock was successfully acquired or not
|
||||
*/
|
||||
public function lock($retries = 0) {
|
||||
|
||||
if ($this->acquired) return true;
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$time_now = time();
|
||||
$acquire_until = $time_now + $this->locked_for;
|
||||
|
||||
$sql = $wpdb->prepare("UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND option_value < %d", $acquire_until, $this->option_name, $time_now);
|
||||
|
||||
if (1 === $wpdb->query($sql)) {
|
||||
$this->log('Lock ('.$this->option_name.', '.$wpdb->options.') acquired', 'info');
|
||||
$this->acquired = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// See if the failure was caused by the row not existing (we check this only after failure, because it should only occur once on the site)
|
||||
if (!$this->ensure_database_initialised()) return false;
|
||||
|
||||
do {
|
||||
// Now that the row has been created, try again
|
||||
if (1 === $wpdb->query($sql)) {
|
||||
$this->log('Lock ('.$this->option_name.', '.$wpdb->options.') acquired after initialising the database', 'info');
|
||||
$this->acquired = true;
|
||||
return true;
|
||||
}
|
||||
$retries--;
|
||||
if ($retries >=0) {
|
||||
$this->log('Lock ('.$this->option_name.', '.$wpdb->options.') not yet acquired; sleeping', 'debug');
|
||||
sleep(1);
|
||||
// As a second has passed, update the time we are aiming for
|
||||
$time_now = time();
|
||||
$acquire_until = $time_now + $this->locked_for;
|
||||
$sql = $wpdb->prepare("UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND option_value < %d", $acquire_until, $this->option_name, $time_now);
|
||||
}
|
||||
} while ($retries >= 0);
|
||||
|
||||
$this->log('Lock ('.$this->option_name.', '.$wpdb->options.') could not be acquired (it is locked)', 'info');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the lock
|
||||
*
|
||||
* N.B. We don't attempt to unlock it unless we locked it. i.e. Lost locks are left to expire rather than being forced. (If we want to force them, we'll need to introduce a new parameter).
|
||||
*
|
||||
* @return Boolean - if it returns false, then the lock was apparently not locked by us (and the caller will most likely therefore ignore the result, whatever it is).
|
||||
*/
|
||||
public function release() {
|
||||
if (!$this->acquired) return false;
|
||||
global $wpdb;
|
||||
$sql = $wpdb->prepare("UPDATE {$wpdb->options} SET option_value = '0' WHERE option_name = %s", $this->option_name);
|
||||
|
||||
$this->log('Lock option ('.$this->option_name.', '.$wpdb->options.') released', 'info');
|
||||
|
||||
$result = (int) $wpdb->query($sql) === 1;
|
||||
|
||||
$this->acquired = false;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the DB of any residual data. This should not be used as part of ordinary unlocking; only as part of deinstalling, or if you otherwise know that the lock will not be used again. If calling this, it's redundant to first unlock (and a no-op to attempt to do so afterwards).
|
||||
*/
|
||||
public function delete() {
|
||||
$this->acquired = false;
|
||||
|
||||
global $wpdb;
|
||||
$wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->options} WHERE option_name = %s", $this->option_name));
|
||||
|
||||
$this->log('Lock option ('.$this->option_name.', '.$wpdb->options.') was deleted from the database');
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures and logs any given messages
|
||||
*
|
||||
* @param String $message - the error message
|
||||
* @param String $level - the message level (debug, notice, info, warning, error)
|
||||
*/
|
||||
public function log($message, $level = 'info') {
|
||||
if (isset($this->loggers)) {
|
||||
foreach ($this->loggers as $logger) {
|
||||
$logger->log($message, $level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of loggers for this instance (removing any others).
|
||||
*
|
||||
* @param Array $loggers - the loggers for this task
|
||||
*/
|
||||
public function set_loggers($loggers) {
|
||||
$this->loggers = array();
|
||||
foreach ($loggers as $logger) {
|
||||
$this->add_logger($logger);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a logger to loggers list
|
||||
*
|
||||
* @param Callable $logger - a logger (a method with a callable function 'log', taking string parameters $level $message)
|
||||
*/
|
||||
public function add_logger($logger) {
|
||||
$this->loggers[] = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current list of loggers
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public function get_loggers() {
|
||||
return $this->loggers;
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+56
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
Example usage:
|
||||
|
||||
php -a
|
||||
require 'wp-load.php';
|
||||
define('I_AM_TESTING', true);
|
||||
require 'test.php';
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
if (!defined('I_AM_TESTING') || !I_AM_TESTING) die('Please define I_AM_TESTING.');
|
||||
|
||||
require_once(dirname(__FILE__).'/class-updraft-semaphore.php');
|
||||
|
||||
class Test_Logger_1 {
|
||||
function log($message, $level) {
|
||||
echo "Test_Logger_1::log(level=$level, message=$message)\n";
|
||||
}
|
||||
}
|
||||
|
||||
class Test_Logger_2 {
|
||||
function log($message, $level) {
|
||||
echo "Test_Logger_2::log(level=$level, message=$message)\n";
|
||||
}
|
||||
}
|
||||
|
||||
$my_lock = new Updraft_Semaphore_3_0('my_test_lock_name', 4, array(new Test_Logger_1()));
|
||||
|
||||
if ($my_lock->lock()) {
|
||||
try {
|
||||
// do stuff ...
|
||||
$my_lock_again = new Updraft_Semaphore_3_0('my_test_lock_name', 4, array(new Test_Logger_2()));
|
||||
$time_now = microtime(true);
|
||||
if ($my_lock_again->lock(6)) {
|
||||
echo "Eventually got it after ".round(microtime(true) - $time_now, 3)." seconds\n";
|
||||
$my_lock_again->release();
|
||||
} else {
|
||||
echo("Sorry, could not get the second lock\n");
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
var_dump($e);
|
||||
// We are making sure we release the lock in case of an error
|
||||
} catch (Error $e) { // phpcs:ignore PHPCompatibility.Classes.NewClasses.errorFound
|
||||
var_dump($e);
|
||||
// We are making sure we release the lock in case of an error
|
||||
}
|
||||
|
||||
$my_lock->release();
|
||||
|
||||
} else {
|
||||
echo("Sorry, could not get the first lock\n");
|
||||
}
|
||||
Vendored
Executable
+188
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
/**
|
||||
* The AJAX Commands manager class
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) die('Access denied.');
|
||||
|
||||
if (!defined('Updraft_Task_Manager_Commands_1_0')) :
|
||||
|
||||
class Updraft_Task_Manager_Commands_1_0 {
|
||||
|
||||
protected $task_manager;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Updraft_Task_Manager_1_4 $task_manager The task manager instance
|
||||
*/
|
||||
public function __construct($task_manager) {
|
||||
$this->task_manager = $task_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of allowed commands via AJAX
|
||||
*
|
||||
* @return array - List of allowed commands
|
||||
*/
|
||||
public static function get_allowed_ajax_commands() {
|
||||
|
||||
$commands = array(
|
||||
'process_task',
|
||||
'get_task_status',
|
||||
'end_task',
|
||||
'process_queue',
|
||||
'get_active_tasks',
|
||||
'clean_up_old_tasks',
|
||||
);
|
||||
|
||||
return apply_filters('updraft_task_manager_allowed_ajax_commands', $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single task in the queue
|
||||
*
|
||||
* @param array $data data passed via AJAX
|
||||
* @return void|WP_Error status of the operation
|
||||
*/
|
||||
public function process_task($data) {
|
||||
|
||||
if (!isset($data['task_id']))
|
||||
return new WP_Error('id_missing', 'Task ID is missing or invalid');
|
||||
|
||||
$task_id = (int) $data['task_id'];
|
||||
|
||||
$response = apply_filters('updraft_task_manager_process_task_response', "Processing task: {$task_id}", $task_id);
|
||||
$this->close_browser_connection($response);
|
||||
$this->task_manager->process_task($task_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single task in the queue
|
||||
*
|
||||
* @param array $data data passed via AJAX
|
||||
* @return String - status of task or false if none found
|
||||
*/
|
||||
public function get_task_status($data) {
|
||||
|
||||
if (!isset($data['task_id']))
|
||||
return new WP_Error('id_missing', 'Task ID is missing or invalid');
|
||||
|
||||
$task_id = (int) $data['task_id'];
|
||||
|
||||
return $this->task_manager->get_task_status($task_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends a given task
|
||||
*
|
||||
* @param array $data data passed via AJAX
|
||||
* @return boolean - Status of the operation.
|
||||
*/
|
||||
public function end_task($data) {
|
||||
|
||||
if (!isset($data['task_id']))
|
||||
return new WP_Error('id_missing', 'Task ID is missing or invalid');
|
||||
|
||||
$task_id = (int) $data['task_id'];
|
||||
|
||||
$status = $this->task_manager->end_task($task_id);
|
||||
|
||||
if (!$status) return new WP_Error('end_task_failed', 'Task is already ended');
|
||||
|
||||
$response = apply_filters('updraft_task_manager_end_task_response', "Successfully ended task with id : {$task_id}", $task_id);
|
||||
$this->close_browser_connection($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of all active tasks
|
||||
*
|
||||
* @param array $data data passed via AJAX
|
||||
* @return Mixed - array of UpdraftPlus_Task ojects or NULL if none found
|
||||
*/
|
||||
public function get_active_tasks($data) {
|
||||
|
||||
if (!isset($data['type']))
|
||||
return new WP_Error('type_missing', 'Task type is missing or invalid');
|
||||
|
||||
$type = $data['type'];
|
||||
$tasks = $this->task_manager->get_active_tasks($type);
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($tasks) {
|
||||
foreach ($tasks as $task) {
|
||||
array_push($ids, $task->get_id());
|
||||
}
|
||||
}
|
||||
|
||||
$response = apply_filters('updraft_task_manager_get_active_tasks_response', $ids, $type);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans out all complete tasks from the DB.
|
||||
*
|
||||
* @param array $data data passed via AJAX
|
||||
* @return void|WP_Error status of the operation
|
||||
*/
|
||||
public function clean_up_old_tasks($data) {
|
||||
|
||||
if (!isset($data['type']))
|
||||
return new WP_Error('type_missing', 'Task type is missing or invalid');
|
||||
|
||||
$type = $data['type'];
|
||||
$status = $this->task_manager->clean_up_old_tasks($type);
|
||||
|
||||
if (!$status) return new WP_Error('clean_up_failed', 'Queue is already empty or the task type invalid');
|
||||
|
||||
$response = apply_filters('updraft_task_manager_clean_up_old_tasks_response', "Cleaned up old tasks of type : $type", $type);
|
||||
$this->close_browser_connection($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a queue of a specific type of task
|
||||
*
|
||||
* @param array $data data passed via AJAX
|
||||
* @return void|WP_Error status of the operation
|
||||
*/
|
||||
public function process_queue($data) {
|
||||
if (!isset($data['type']))
|
||||
return new WP_Error('type_missing', 'Task type is missing or invalid');
|
||||
|
||||
$type = $data['type'];
|
||||
|
||||
$response = apply_filters('updraft_task_manager_process_queue_response', "Processing queue of type {$type}", $type);
|
||||
|
||||
$this->close_browser_connection(json_encode($response));
|
||||
$status = $this->task_manager->process_queue($type);
|
||||
|
||||
if (!$status)
|
||||
return new WP_Error('process_queue_operation_failed', 'Failed to process the queue');
|
||||
}
|
||||
|
||||
/**
|
||||
* Close browser connection so that it can resume AJAX polling
|
||||
*
|
||||
* @param array $txt Response to browser
|
||||
* @return void
|
||||
*/
|
||||
public function close_browser_connection($txt = '') {
|
||||
header('Content-Length: '.((!empty($txt)) ? 5+strlen($txt) : '0'));
|
||||
header('Connection: close');
|
||||
header('Content-Encoding: none');
|
||||
if (session_id()) session_write_close();
|
||||
echo "\r\n\r\n";
|
||||
echo $txt;
|
||||
|
||||
$levels = ob_get_level();
|
||||
|
||||
for ($i = 0; $i < $levels; $i++) {
|
||||
ob_end_flush();
|
||||
}
|
||||
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
Vendored
Executable
+349
@@ -0,0 +1,349 @@
|
||||
<?php
|
||||
/**
|
||||
* A task manager that locks and processes the task queue
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) die('Access denied.');
|
||||
|
||||
if (!class_exists('Updraft_Task_Manager_1_4')) :
|
||||
|
||||
abstract class Updraft_Task_Manager_1_4 {
|
||||
|
||||
protected $loggers;
|
||||
|
||||
public $commands;
|
||||
|
||||
private $queue_semaphore;
|
||||
|
||||
/**
|
||||
* Set this to the number of seconds for the lock timeout, or 0 to not use a lock
|
||||
*/
|
||||
protected $use_per_task_lock = 0;
|
||||
|
||||
/**
|
||||
* The Task Manager constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
if (!class_exists('Updraft_Task_1_2')) require_once('class-updraft-task.php');
|
||||
if (!class_exists('Updraft_Task_Manager_Commands_1_0')) require_once('class-updraft-task-manager-commands.php');
|
||||
if (!class_exists('Updraft_Semaphore_3_0')) require_once(dirname(__FILE__).'/../updraft-semaphore/class-updraft-semaphore.php');
|
||||
if (!class_exists('Updraft_Tasks_Activation')) require_once(dirname(__FILE__).'/class-updraft-tasks-activation.php');
|
||||
|
||||
$this->commands = new Updraft_Task_Manager_Commands_1_0($this);
|
||||
|
||||
do_action('updraft_task_manager_loaded', $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single task in the queue
|
||||
*
|
||||
* @param int|Updraft_Task - $task Task ID or Updraft_Task object.
|
||||
* @return boolean|WP_Error - status of task or error if task not found
|
||||
*/
|
||||
public function process_task($task) {
|
||||
|
||||
if (!is_a($task, 'Updraft_Task_1_2')) {
|
||||
$task_id = (int) $task;
|
||||
$task = $this->get_task_instance($task_id);
|
||||
}
|
||||
|
||||
if (!$task) return new WP_Error('id_invalid', 'Task not found or ID is invalid');
|
||||
|
||||
return $task->attempt(apply_filters('updraft_task_lock_for', $this->use_per_task_lock, $this));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all tasks that matches the $status flag
|
||||
*
|
||||
* @param int|Updraft_Task - $task Task ID or Updraft_Task object.
|
||||
* @return String|WP_Error - status of task or error if task not found.
|
||||
*/
|
||||
public function get_task_status($task) {
|
||||
|
||||
if (!($task instanceof Updraft_Task_1_2)) {
|
||||
$task_id = (int) $task;
|
||||
$task = $this->get_task_instance($task_id);
|
||||
}
|
||||
|
||||
if (!$task) return new WP_Error('id_invalid', 'Task not found or ID is invalid');
|
||||
|
||||
return $task->get_status();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends a given task
|
||||
*
|
||||
* @param int|Updraft_Task - $task Task ID or Updraft_Task object.
|
||||
* @return boolean|WP_Error - Status of the operation or error if task not found.
|
||||
*/
|
||||
public function end_task($task) {
|
||||
|
||||
if (!($task instanceof Updraft_Task_1_2)) {
|
||||
$task_id = (int) $task;
|
||||
$task = $this->get_task_instance($task_id);
|
||||
}
|
||||
|
||||
if (!$task) return new WP_Error('id_invalid', 'Task not found or ID is invalid');
|
||||
|
||||
return $task->complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a the queue of a specifed task type
|
||||
*
|
||||
* @param string $type queue type to process
|
||||
* @return bool true on success, false otherwise
|
||||
*/
|
||||
public function process_queue($type) {
|
||||
|
||||
$task_list = $this->get_active_tasks($type);
|
||||
$total = is_array($task_list) ? count($task_list) : 0;
|
||||
|
||||
if (1 > $total) {
|
||||
$this->log(sprintf('The queue for tasks of type "%s" is empty. Aborting!', $type));
|
||||
return true;
|
||||
} else {
|
||||
$this->log(sprintf('A total of %d tasks of type %s found and will be processed in this iteration', $total, $type));
|
||||
}
|
||||
|
||||
$this->queue_semaphore = new Updraft_Semaphore_3_0($type);
|
||||
|
||||
// Prevent PHP warning which trigger from semaphore class set_loggers method if $this->loggers is empty
|
||||
if (!empty($this->loggers)) {
|
||||
$this->queue_semaphore->set_loggers($this->loggers);
|
||||
}
|
||||
|
||||
if (!$this->queue_semaphore->lock()) {
|
||||
|
||||
$this->log(sprintf('Failed to gain semaphore lock (%s) - another process is already processing the queue - aborting (if this is wrong - i.e. if the other process crashed without removing the lock, then another can be started after 1 minute', $type));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$done = 0;
|
||||
foreach ($task_list as $task) {
|
||||
$this->process_task($task);
|
||||
$done++;
|
||||
/**
|
||||
* Filters if the queue should be interrupted. Used after processing each task.
|
||||
*
|
||||
* @param boolean $interrupt_queue - If the queue should be interrupted. Default to FALSE
|
||||
* @param object $task - The current task object
|
||||
* @param object $task_manager - The task manager instance
|
||||
*/
|
||||
if (apply_filters('updraft_interrupt_tasks_queue_'.$type, false, $task, $this)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->queue_semaphore->release();
|
||||
$this->log(sprintf('Successfully processed the queue (%s). %d tasks were processed out of %d.', $type, $done, $total));
|
||||
$this->queue_semaphore->delete();
|
||||
|
||||
return $done == $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans out all complete tasks from the DB.
|
||||
*
|
||||
* @param String $type type of the task
|
||||
*/
|
||||
public function clean_up_old_tasks($type) {
|
||||
$completed_tasks = $this->get_completed_tasks($type);
|
||||
|
||||
if (!$completed_tasks) return false;
|
||||
|
||||
$this->log(sprintf('Cleaning up tasks of type (%s). A total of %d tasks will be deleted.', $type, count($completed_tasks)));
|
||||
|
||||
foreach ($completed_tasks as $task) {
|
||||
$task->delete_meta();
|
||||
$task->delete();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all tasks from queue.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return boolean|integer Number of rows deleted, or (boolean)false upon error
|
||||
*/
|
||||
public function delete_tasks($task_type) {
|
||||
global $wpdb;
|
||||
|
||||
$sql = "DELETE t, tm FROM `{$wpdb->base_prefix}tm_tasks` t LEFT JOIN `{$wpdb->base_prefix}tm_taskmeta` tm ON t.id = tm.task_id WHERE t.type = '{$task_type}'";
|
||||
|
||||
return $wpdb->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of completed and all tasks.
|
||||
*
|
||||
* @return array - [ ['complete_tasks' => , 'all_tasks' => ] ]
|
||||
*/
|
||||
public function get_status($task_type) {
|
||||
global $wpdb;
|
||||
|
||||
$query = $wpdb->prepare(
|
||||
"SELECT complete_tasks, all_tasks FROM (SELECT COUNT(*) AS complete_tasks FROM {$wpdb->base_prefix}tm_tasks WHERE `type` = %s AND `status` = %s) a, (SELECT COUNT(*) AS all_tasks FROM {$wpdb->base_prefix}tm_tasks WHERE `type` = %s) b",
|
||||
array(
|
||||
$task_type,
|
||||
'complete',
|
||||
$task_type,
|
||||
)
|
||||
);
|
||||
|
||||
$status = $wpdb->get_row($query, ARRAY_A);
|
||||
|
||||
if (empty($status)) {
|
||||
$status = array(
|
||||
'complete_tasks' => 0,
|
||||
'all_tasks' => 0,
|
||||
);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of all active tasks
|
||||
*
|
||||
* @param String $type type of the task
|
||||
* @return Mixed - array of Task ojects or NULL if none found
|
||||
*/
|
||||
public function get_active_tasks($type) {
|
||||
return $this->get_tasks('active', $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all completed tasks
|
||||
*
|
||||
* @param String $type type of the task
|
||||
* @return Mixed - array of Task ojects or NULL if none found
|
||||
*/
|
||||
public function get_completed_tasks($type) {
|
||||
return $this->get_tasks('complete', $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all tasks that matches the $status flag
|
||||
*
|
||||
* @param String $status - status of tasks to return, defaults to all tasks
|
||||
* @param String $type - type of task
|
||||
*
|
||||
* @return Mixed - array of Task objects or NULL if none found
|
||||
*/
|
||||
public function get_tasks($status, $type) {
|
||||
global $wpdb;
|
||||
|
||||
$tasks = array();
|
||||
|
||||
if (array_key_exists($status, Updraft_Task_1_2::get_allowed_statuses())) {
|
||||
$sql = $wpdb->prepare("SELECT * FROM {$wpdb->base_prefix}tm_tasks WHERE status = %s AND type = %s", $status, $type);
|
||||
} else {
|
||||
$sql = $wpdb->prepare("SELECT * FROM {$wpdb->base_prefix}tm_tasks WHERE type = %s", $type);
|
||||
}
|
||||
|
||||
$_tasks = $wpdb->get_results($sql);
|
||||
|
||||
if (!$_tasks) {
|
||||
// if we got an error then check if task manager tables are in the database
|
||||
// and recreate them if needed.
|
||||
if ($wpdb->last_error) {
|
||||
Updraft_Tasks_Activation::reinstall_if_needed();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
foreach ($_tasks as $_task) {
|
||||
$task = $this->get_task_instance($_task->id);
|
||||
if ($task) array_push($tasks, $task);
|
||||
}
|
||||
|
||||
return $tasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the task instance using its ID
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @global wpdb $wpdb WordPress database abstraction object.
|
||||
*
|
||||
* @param int $task_id Task ID.
|
||||
* @return Task|Boolean Task object, false otherwise.
|
||||
*/
|
||||
public function get_task_instance($task_id) {
|
||||
global $wpdb;
|
||||
|
||||
$task_id = (int) $task_id;
|
||||
if (!$task_id) return false;
|
||||
|
||||
$sql = $wpdb->prepare("SELECT * FROM {$wpdb->base_prefix}tm_tasks WHERE id = %d LIMIT 1", $task_id);
|
||||
$_task = $wpdb->get_row($sql);
|
||||
|
||||
if (!$_task)
|
||||
return false;
|
||||
|
||||
$class_identifier = $_task->class_identifier;
|
||||
|
||||
if (class_exists($class_identifier)) {
|
||||
$task_instance = new $class_identifier($_task);
|
||||
$task_instance->set_loggers($this->loggers);
|
||||
return $task_instance;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the logger for this instance.
|
||||
*
|
||||
* @param array $loggers - the loggers for this task
|
||||
*/
|
||||
public function set_loggers($loggers) {
|
||||
foreach ($loggers as $logger) {
|
||||
$this->add_logger($logger);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a logger to loggers list
|
||||
*
|
||||
* @param Object $logger - a logger for the instance
|
||||
*/
|
||||
public function add_logger($logger) {
|
||||
$this->loggers[] = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of loggers
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_loggers() {
|
||||
return $this->loggers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures and logs any interesting messages
|
||||
*
|
||||
* @param String $message - the error message
|
||||
* @param String $error_type - the error type
|
||||
*/
|
||||
public function log($message, $error_type = 'info') {
|
||||
if (isset($this->loggers)) {
|
||||
foreach ($this->loggers as $logger) {
|
||||
$logger->log($message, $error_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
endif;
|
||||
Vendored
Executable
+96
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* The DB handle class for the options framework
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) die('Access denied.');
|
||||
|
||||
if (!class_exists('Updraft_Task_Meta')) :
|
||||
|
||||
class Updraft_Task_Meta {
|
||||
|
||||
/**
|
||||
* This method gets data from the task meta table in the WordPress database
|
||||
*
|
||||
* @param int $id the instance id of the task
|
||||
* @param String $key the key to get
|
||||
*
|
||||
* @return Mixed The option from the database
|
||||
*/
|
||||
public static function get_task_meta($id, $key) {
|
||||
global $wpdb;
|
||||
|
||||
$id = (int) $id;
|
||||
if (!$id) return false;
|
||||
|
||||
$sql = $wpdb->prepare("SELECT meta_value FROM {$wpdb->base_prefix}tm_taskmeta WHERE task_id = %d AND meta_key = %s LIMIT 1", $id, $key);
|
||||
|
||||
$meta = $wpdb->get_var($sql);
|
||||
|
||||
if ($meta)
|
||||
return maybe_unserialize($meta);
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is used to update data stored in the WordPress database
|
||||
*
|
||||
* @param int $id the instance id of the task
|
||||
* @param String $key the key of the data to update
|
||||
* @param Mixed $value the value to save to the option
|
||||
*
|
||||
* @return Mixed the status of the update operation
|
||||
*/
|
||||
public static function update_task_meta($id, $key, $value) {
|
||||
global $wpdb;
|
||||
|
||||
$id = (int) $id;
|
||||
if (!$id) return false;
|
||||
|
||||
$value = maybe_serialize($value);
|
||||
|
||||
if (false !== self::get_task_meta($id, $key)) {
|
||||
$sql = $wpdb->prepare("UPDATE {$wpdb->base_prefix}tm_taskmeta SET meta_value = %s WHERE meta_key = %s AND task_id = %d", $value, $key, $id);
|
||||
} else {
|
||||
$sql = $wpdb->prepare("INSERT INTO {$wpdb->base_prefix}tm_taskmeta (task_id, meta_key, meta_value) VALUES (%d, %s, %s)", $id, $key, $value);
|
||||
}
|
||||
|
||||
return $wpdb->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to delete task data stored in the WordPress database
|
||||
*
|
||||
* @param int $id the instance id of the task
|
||||
* @param String $key the key to delete
|
||||
*
|
||||
* @return Mixed the status of the delete operation
|
||||
*/
|
||||
public static function delete_task_meta($id, $key) {
|
||||
global $wpdb;
|
||||
|
||||
$id = (int) $id;
|
||||
if (!$id) return false;
|
||||
|
||||
$sql = $wpdb->prepare("DELETE FROM {$wpdb->base_prefix}tm_taskmeta WHERE task_id = %d AND meta_key = %s LIMIT 1", $id, $key);
|
||||
return $wpdb->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk delete task
|
||||
*
|
||||
* @param int $id the instance id of the task
|
||||
*/
|
||||
public static function bulk_delete_task_meta($id) {
|
||||
global $wpdb;
|
||||
|
||||
$id = (int) $id;
|
||||
if (!$id) return false;
|
||||
|
||||
$sql = $wpdb->prepare("DELETE FROM {$wpdb->base_prefix}tm_taskmeta WHERE task_id = %d", $id);
|
||||
return $wpdb->query($sql);
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
Vendored
Executable
+127
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/**
|
||||
* The options framework for tasks
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) die('Access denied.');
|
||||
|
||||
if (!class_exists('Updraft_Task_Options')) :
|
||||
|
||||
class Updraft_Task_Options {
|
||||
|
||||
/**
|
||||
* This method gets an option from the task meta table in the WordPress database
|
||||
*
|
||||
* @param int $instance_id the instance id of the task
|
||||
* @param String $option the name of the option to get
|
||||
* @param Mixed $default a value to return if the option is not currently set
|
||||
*
|
||||
* @return Mixed The option from the database
|
||||
*/
|
||||
public static function get_task_option($instance_id, $option, $default = null) {
|
||||
|
||||
$tmp = Updraft_Task_Meta::get_task_meta($instance_id, 'task_options');
|
||||
|
||||
if (isset($tmp[$option])) {
|
||||
$value = $tmp[$option];
|
||||
} else {
|
||||
$value = $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the value of an existing option.
|
||||
*
|
||||
* The dynamic portion of the hook name, `$option`, refers to the option name.
|
||||
*/
|
||||
return apply_filters("ud_task_option_{$option}", maybe_unserialize($value), $option, $default, $instance_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to update a task option stored in the WordPress database
|
||||
*
|
||||
* @param int $instance_id the instance id of the task
|
||||
* @param String $option the name of the option to update
|
||||
* @param Mixed $value the value to save to the option
|
||||
*
|
||||
* @return Mixed the status of the update operation
|
||||
*/
|
||||
public static function update_task_option($instance_id, $option, $value) {
|
||||
|
||||
$option = trim($option);
|
||||
|
||||
if (empty($option)) return false;
|
||||
|
||||
$old_value = self::get_task_option($instance_id, $option);
|
||||
|
||||
/**
|
||||
* Filters a specific option before its value is (maybe) serialized and updated.
|
||||
*/
|
||||
$value = apply_filters("ud_pre_update_task_option_{$option}", $value, $old_value, $option, $instance_id);
|
||||
|
||||
$tmp = Updraft_Task_Meta::get_task_meta($instance_id, 'task_options');
|
||||
|
||||
if (!is_array($tmp)) $tmp = array();
|
||||
$tmp[$option] = maybe_serialize($value);
|
||||
|
||||
$result = Updraft_Task_Meta::update_task_meta($instance_id, 'task_options', $tmp);
|
||||
|
||||
if ($result) {
|
||||
|
||||
/**
|
||||
* Fires after the value of a specific option has been successfully updated.
|
||||
*/
|
||||
do_action("ud_update_task_option_{$option}", $value, $old_value, $option, $instance_id);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to delete a task option stored in the WordPress database
|
||||
*
|
||||
* @param int $instance_id the instance id of the task
|
||||
* @param String $option the option to delete
|
||||
*/
|
||||
public static function delete_task_option($instance_id, $option) {
|
||||
|
||||
/**
|
||||
* Fires immediately before an option is deleted.
|
||||
*/
|
||||
do_action("ud_before_delete_task_option", $option, $instance_id);
|
||||
|
||||
$tmp = Updraft_Task_Meta::get_task_meta($instance_id, 'task_options');
|
||||
|
||||
if (is_array($tmp)) {
|
||||
if (isset($tmp[$option])) unset($tmp[$option]);
|
||||
} else {
|
||||
$tmp = array();
|
||||
}
|
||||
|
||||
$result = Updraft_Task_Meta::update_task_meta($instance_id, 'task_options', $tmp);
|
||||
|
||||
if ($result) {
|
||||
|
||||
/**
|
||||
* Fires after a specific option has been successfully deleted.
|
||||
*/
|
||||
do_action("ud_delete_task_option_{$option}", $option);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets all options assoicated with a task
|
||||
*
|
||||
* @param int $instance_id the instance id of the task
|
||||
*
|
||||
* @return Mixed The options from the database
|
||||
*/
|
||||
public static function get_all_task_options($instance_id) {
|
||||
|
||||
$value = Updraft_Task_Meta::get_task_meta($instance_id, 'task_options');
|
||||
return apply_filters("ud_all_task_options", maybe_unserialize($value), $instance_id);
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
Vendored
Executable
+746
@@ -0,0 +1,746 @@
|
||||
<?php
|
||||
/**
|
||||
* The base class which must be extended to use the tasks library
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) die('Access denied.');
|
||||
|
||||
if (!class_exists('Updraft_Task_1_2')) :
|
||||
|
||||
if (!class_exists('Updraft_Task_Options')) require_once('class-updraft-task-options.php');
|
||||
if (!class_exists('Updraft_Task_Meta')) require_once('class-updraft-task-meta.php');
|
||||
|
||||
abstract class Updraft_Task_1_2 {
|
||||
|
||||
/**
|
||||
* A unique ID for the specific task
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* The user id of the creator of this task
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $user_id;
|
||||
|
||||
/**
|
||||
* A text description for the task
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* A type for the task
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* A timestamp indicating the time the task was created
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $time_created;
|
||||
|
||||
/**
|
||||
* The number of times this task was attempted
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $attempts;
|
||||
|
||||
/**
|
||||
* A text description describing the status of the task
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $status;
|
||||
|
||||
/**
|
||||
* An identifier indicating which child class created this instance
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $class_identifier;
|
||||
|
||||
/**
|
||||
* A logger object that can be used to capture interesting events / messages
|
||||
*
|
||||
* @var Object
|
||||
*/
|
||||
protected $_loggers;
|
||||
|
||||
/**
|
||||
* Additional dynamic properties, usually copied from the UpdraftPlus_Task object.
|
||||
*
|
||||
* @var array<string,mixed>
|
||||
*/
|
||||
protected $extra_properties = array();
|
||||
|
||||
/**
|
||||
* The Task constructor
|
||||
*
|
||||
* @param UpdraftPlus_Task|object $task UpdraftPlus_Task object.
|
||||
*/
|
||||
public function __construct($task) {
|
||||
foreach (get_object_vars($task) as $key => $value)
|
||||
$this->$key = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the instance ID.
|
||||
*
|
||||
* @param String $instance_id - the instance ID
|
||||
*/
|
||||
public function set_id($instance_id) {
|
||||
$this->id = $instance_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance ID.
|
||||
*
|
||||
* @return String the instance ID
|
||||
*/
|
||||
public function get_id() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description.
|
||||
*
|
||||
* @param String $description - the description of the task
|
||||
*/
|
||||
public function set_description($description) {
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the task description
|
||||
*
|
||||
* @return String $description - the description of the task
|
||||
*/
|
||||
public function get_description() {
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type.
|
||||
*
|
||||
* @param String $type - the type of the task
|
||||
*/
|
||||
public function set_type($type) {
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of times this task was attempted
|
||||
*
|
||||
* @return int $attempts - the count
|
||||
*/
|
||||
public function get_attempts() {
|
||||
return $this->attempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of times this task was attempted
|
||||
*
|
||||
* @param String $attempts - the count
|
||||
*/
|
||||
public function set_attempts($attempts) {
|
||||
if (is_numeric($attempts))
|
||||
$this->attempts = $attempts;
|
||||
else return false;
|
||||
|
||||
return $this->update_attempts($this->id, $this->attempts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the task type
|
||||
*
|
||||
* @return String $type - the type of the task
|
||||
*/
|
||||
public function get_type() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the task status.
|
||||
*
|
||||
* @param String $status - the status of the task
|
||||
*
|
||||
* @return Boolean - the result of the status update
|
||||
*/
|
||||
public function set_status($status) {
|
||||
|
||||
if (array_key_exists($status, self::get_allowed_statuses()))
|
||||
$this->status = $status;
|
||||
else return false;
|
||||
|
||||
return $this->update_status($this->id, $this->status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the task status
|
||||
*
|
||||
* @return String $status - the status of the task
|
||||
*/
|
||||
public function get_status() {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the logger for this task.
|
||||
*
|
||||
* @param array $loggers - the loggers for this task
|
||||
*/
|
||||
public function set_loggers($loggers) {
|
||||
if (is_array($loggers)) {
|
||||
foreach ($loggers as $logger) {
|
||||
$this->add_logger($logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a logger to loggers list
|
||||
*
|
||||
* @param Object $logger - a logger for the task
|
||||
*/
|
||||
public function add_logger($logger) {
|
||||
$this->_loggers[] = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of loggers
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_loggers() {
|
||||
return $this->_loggers;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initialisation function that accepts and processes any parameters needed before the task starts
|
||||
*
|
||||
* @param Array $options - array of options
|
||||
*
|
||||
* @uses update_option
|
||||
*/
|
||||
public function initialise($options = array()) {
|
||||
|
||||
do_action('ud_task_before_initialise', $this, $options);
|
||||
|
||||
/**
|
||||
* Parse incoming $options into an array and merge it with defaults
|
||||
*/
|
||||
$defaults = $this->get_default_options();
|
||||
$options = wp_parse_args($options, $defaults);
|
||||
|
||||
foreach ($options as $option => $value) {
|
||||
$this->update_option($option, $value);
|
||||
}
|
||||
|
||||
do_action('ud_task_initialise_complete', $this, $options);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to perform the task
|
||||
*
|
||||
* @param integer $lock_for - if greater than zero, then lock the task, and don't break until this number of seconds has passed
|
||||
*
|
||||
* @return boolean Status of the attempt
|
||||
*/
|
||||
public function attempt($lock_for = 0) {
|
||||
|
||||
$_task = $this->get_task_from_db($this->get_id());
|
||||
|
||||
if (!$_task) {
|
||||
$this->log("The task with id : {$this->get_id()}, and type '{$this->get_type()}' seems to have been deleted from the database.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ('complete' == $this->get_status()) {
|
||||
$this->log("Attempting already complete task with ID : {$this->get_id()}, and type '{$this->get_type()}'. Aborting !");
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($lock_for) {
|
||||
$try = 1;
|
||||
$locked = false;
|
||||
while ($try < 4) {
|
||||
if ($locked = $this->lock($this->get_id(), true, $lock_for)) break;
|
||||
$try ++;
|
||||
sleep(1);
|
||||
}
|
||||
if (!$locked) {
|
||||
$this->fail('could_not_lock', 'The task could not be locked');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$attempts = $this->get_attempts();
|
||||
|
||||
if ($attempts >= $this->get_max_attempts()) {
|
||||
$this->fail("max_attempts_exceeded", "Maximum attempts ($attempts) exceeded for task");
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->log("Processing task with ID : {$this->get_id()}, and type '{$this->get_type()}'");
|
||||
$this->set_attempts(++$attempts);
|
||||
$status = $this->run();
|
||||
|
||||
if ($status) {
|
||||
$this->complete();
|
||||
$this->log("Completed processing task with ID : {$this->get_id()}, and type '{$this->get_type()}'");
|
||||
}
|
||||
|
||||
if ($lock_for) $this->lock($this->get_id(), false);
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock or unlock a task
|
||||
*
|
||||
* @param Integer - $task_id - task identifier
|
||||
* @param Boolean - $lock - whether to lock or unlock
|
||||
* @param Integer - $lock_for - if already locked, how long after which to break the lock
|
||||
*
|
||||
* @return Boolean - whether the operation was successful
|
||||
*/
|
||||
public function lock($task_id, $lock = true, $lock_for = 60) {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
if (!$lock) {
|
||||
return $wpdb->update($wpdb->base_prefix.'tm_tasks', array('last_locked_at' => 0), array('id' => $task_id)) ? true : false;
|
||||
}
|
||||
|
||||
// Mode: lock. Attempt to set the lock
|
||||
$affected = $wpdb->update($wpdb->base_prefix.'tm_tasks', array('last_locked_at' => time()), array('id' => $task_id, 'last_locked_at' => 0));
|
||||
|
||||
// Success.
|
||||
if (1 == $affected) return true;
|
||||
|
||||
// Failed - something else already had it locked. Grab the lock if it had expired.
|
||||
$affected = $wpdb->update($wpdb->base_prefix.'tm_tasks', array('last_locked_at' => time()), array('id' => $task_id, 'last_locked_at' => 0));
|
||||
|
||||
$expires_at = time() - $lock_for;
|
||||
|
||||
$affected = $wpdb->query($wpdb->prepare("
|
||||
UPDATE {$wpdb->base_prefix}tm_tasks
|
||||
SET last_locked_at = %d
|
||||
WHERE id = %d
|
||||
AND last_locked_at <= %s
|
||||
", time(), $task_id, $expires_at));
|
||||
|
||||
return $affected ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called to allow for the task to perform a small chunk of work.
|
||||
* It should be written in a way that anticipates it being killed off at any time.
|
||||
*/
|
||||
abstract public function run();
|
||||
|
||||
/**
|
||||
* Any clean up code goes here.
|
||||
*/
|
||||
public function complete() {
|
||||
|
||||
do_action('ud_task_before_complete', $this);
|
||||
|
||||
$this->set_status('complete');
|
||||
|
||||
do_action('ud_task_completed', $this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires if the task fails, any clean up code and logging should go here
|
||||
*
|
||||
* @param String $error_code - A code for the failure
|
||||
* @param String $error_message - A description for the failure
|
||||
*/
|
||||
public function fail($error_code = "Unknown", $error_message = "Unknown") {
|
||||
|
||||
do_action('ud_task_before_failed', $this);
|
||||
|
||||
$this->set_status('failed');
|
||||
$this->log(sprintf("Task with ID %d and type (%s) failed with error code %s - %s", $this->id, $this->type, $error_code, $error_message));
|
||||
|
||||
$this->update_option("error_code", $error_code);
|
||||
$this->update_option("error_message", $error_message);
|
||||
|
||||
do_action('ud_task_failed', $this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints any information about the task that the UI can use on the front end for debugging
|
||||
* @param String $title the header to use in the report
|
||||
*
|
||||
* @return String The task report HTML
|
||||
*/
|
||||
public function print_task_report_widget($title = 'Task Summary') {
|
||||
|
||||
$ret = "";
|
||||
|
||||
$status = $this->get_status();
|
||||
$stage = $this->get_option('stage') ? $this->get_option('stage') : 'Unknown';
|
||||
$description = $this->get_status_description($status);
|
||||
|
||||
|
||||
$ret .= "<div class='task task-report task-{$this->type}' id='task-id-{$this->id}'>";
|
||||
$ret .= "<h4>Task Summary</h4>";
|
||||
$ret .= "<ul class='properties-list task-{$this->type}'>";
|
||||
|
||||
foreach ($this as $key => $value) {
|
||||
$ret .= sprintf("<li> %s : %s </li>", $key, $value);
|
||||
}
|
||||
$ret .='</ul>';
|
||||
|
||||
$ret .= "<h4> $title </h4>";
|
||||
$ret .= "<ul class='data-list task-{$this->type}'>";
|
||||
|
||||
foreach ($this->get_all_options() as $key => $value) {
|
||||
if (is_array(maybe_unserialize($value))) {
|
||||
$ret .= sprintf("<li> %s</li>", $key);
|
||||
$ret .= "<ul class='sub-list'>";
|
||||
foreach (maybe_unserialize($value) as $k => $v) {
|
||||
$ret .= sprintf("<li> %s => %s </li>", $k, $v);
|
||||
}
|
||||
$ret .= "</ul>";
|
||||
} else {
|
||||
$ret .= sprintf("<li> %s : %s </li>", $key, $value);
|
||||
}
|
||||
}
|
||||
$ret .='</ul>';
|
||||
$ret .='</div>';
|
||||
|
||||
return apply_filters('ud_print_task_report_widget', $ret, $this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets an option from the task options in the WordPress database if available,
|
||||
* otherwise returns the default for this task type
|
||||
*
|
||||
* @param String $option the name of the option to get
|
||||
* @param Mixed $default a value to return if the option is not currently set
|
||||
*
|
||||
* @return Mixed The option from the database
|
||||
*/
|
||||
public function get_option($option = null, $default = null) {
|
||||
return Updraft_Task_Options::get_task_option($this->id, $option, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to add a task option stored in the WordPress database
|
||||
*
|
||||
* @param String $option the name of the option to update
|
||||
* @param Mixed $value the value to save to the option
|
||||
*
|
||||
* @return Mixed the status of the add operation
|
||||
*/
|
||||
public function add_option($option, $value) {
|
||||
return Updraft_Task_Options::update_task_option($this->id, $option, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to update a task option stored in the WordPress database
|
||||
*
|
||||
* @param String $option the name of the option to update
|
||||
* @param Mixed $value the value to save to the option
|
||||
*
|
||||
* @return Mixed the status of the update operation
|
||||
*/
|
||||
public function update_option($option, $value) {
|
||||
return Updraft_Task_Options::update_task_option($this->id, $option, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to delete a task option stored in the WordPress database
|
||||
*
|
||||
* @param String $option the option to delete
|
||||
*
|
||||
* @return Boolean the result of the delete operation
|
||||
*/
|
||||
public function delete_option($option) {
|
||||
return Updraft_Task_Options::delete_task_option($this->id, $option);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets all options assoicated with a task
|
||||
*/
|
||||
public function get_all_options() {
|
||||
return Updraft_Task_Options::get_all_task_options($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve default options for this task.
|
||||
* This method should normally be over-ridden by the child.
|
||||
*
|
||||
* @return Array - an array of options
|
||||
*/
|
||||
public function get_default_options() {
|
||||
|
||||
$this->log(sprintf('The get_default_options() method was not over-ridden for the class : %s', $this->get_description()));
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique label for this instance that can be used as an identifier
|
||||
*
|
||||
* @return String - a unique label for this instance
|
||||
*/
|
||||
protected function get_unique_label() {
|
||||
return apply_filters('ud_task_unique_label', $this->id."-".$this->type, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the status of the given task in the DB
|
||||
*
|
||||
* @param String $id - the id of the task
|
||||
* @param String $status - the status of the task
|
||||
*
|
||||
* @return Boolean - the stauts of the update operation
|
||||
*/
|
||||
public function update_status($id, $status) {
|
||||
|
||||
if (!array_key_exists($status, self::get_allowed_statuses()))
|
||||
return false;
|
||||
|
||||
global $wpdb;
|
||||
$sql = $wpdb->prepare("UPDATE {$wpdb->base_prefix}tm_tasks SET status = %s WHERE id = %d", $status, $id);
|
||||
|
||||
return $wpdb->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the number of attempts made for the given task in the DB
|
||||
*
|
||||
* @param String $id - the id of the task
|
||||
* @param int $attempts - the status of the task
|
||||
*
|
||||
* @return Boolean - the stauts of the update operation
|
||||
*/
|
||||
public function update_attempts($id, $attempts) {
|
||||
|
||||
if (!is_numeric($attempts))
|
||||
return false;
|
||||
|
||||
global $wpdb;
|
||||
$sql = $wpdb->prepare("UPDATE {$wpdb->base_prefix}tm_tasks SET attempts = %s WHERE id = %d", $attempts, $id);
|
||||
|
||||
return $wpdb->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans out the given task from the DB
|
||||
*
|
||||
* @return Boolean - the status of the delete operation
|
||||
*/
|
||||
public function delete() {
|
||||
global $wpdb;
|
||||
|
||||
$sql = $wpdb->prepare("DELETE FROM {$wpdb->base_prefix}tm_tasks WHERE id = %d", $this->id);
|
||||
return $wpdb->query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans out the given task meta from the DB
|
||||
*
|
||||
* @return Boolean - the status of the delete operation
|
||||
*/
|
||||
public function delete_meta() {
|
||||
return Updraft_Task_Meta::bulk_delete_task_meta($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to convert object to array.
|
||||
*
|
||||
* @return array Object as array.
|
||||
*/
|
||||
public function to_array() {
|
||||
$task = get_object_vars($this);
|
||||
|
||||
foreach (array( 'task_options', 'task_data', 'task_logs', 'task_extras' ) as $key) {
|
||||
if ($this->__isset($key))
|
||||
$task[$key] = $this->__get($key);
|
||||
}
|
||||
|
||||
return $task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures and logs any interesting messages
|
||||
*
|
||||
* @param String $message - the error message
|
||||
* @param String $error_type - the error type
|
||||
*/
|
||||
public function log($message, $error_type = 'info') {
|
||||
|
||||
if (isset($this->_loggers)) {
|
||||
foreach ($this->_loggers as $logger) {
|
||||
$logger->log($message, $error_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all the supported task statuses.
|
||||
*
|
||||
* Tasks should have a limited set of valid status values, this method provides a
|
||||
* list of values and descriptions.
|
||||
*
|
||||
* @return array List of task statuses.
|
||||
*/
|
||||
public static function get_allowed_statuses() {
|
||||
$status = array(
|
||||
'initialised' => __('Initialised'),
|
||||
'active' => __('Active'),
|
||||
'paused' => __('Paused'),
|
||||
'complete' => __('Completed'),
|
||||
'failed' => __('Failed')
|
||||
);
|
||||
|
||||
return apply_filters('ud_allowed_task_statuses', $status);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the max attempts permitted for task type
|
||||
*
|
||||
* @return int Max attempts permitted for task type
|
||||
*/
|
||||
private function get_max_attempts() {
|
||||
return apply_filters('ud_max_attempts', 5, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the text description of the task status.
|
||||
*
|
||||
* @param String $status - The task status
|
||||
*
|
||||
* @return String Description of the task status.
|
||||
*/
|
||||
public static function get_status_description($status) {
|
||||
$list = self::get_allowed_statuses();
|
||||
|
||||
if (!array_key_exists($status, self::get_allowed_statuses()))
|
||||
return __('Unknown');
|
||||
|
||||
return apply_filters("ud_task_status_description_{$status}", $list[$status], $status, $list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new task instance and returns it
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @global wpdb $wpdb WordPress database abstraction object.
|
||||
*
|
||||
* @param String $type A identifier for the task
|
||||
* @param String $description A description of the task
|
||||
* @param Mixed $options A list of options to initialise the task
|
||||
* @param String $task_class Class name of task; only needed/used on PHP 5.2 (due to lack of late static binding)
|
||||
*
|
||||
* @return Updraft_Task|false Task object, false otherwise.
|
||||
*/
|
||||
public static function create_task($type, $description, $options = array(), $task_class = '') {
|
||||
global $wpdb;
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
$class_identifier = function_exists('get_called_class') ? get_called_class() : $task_class;// phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.get_called_classFound
|
||||
|
||||
$is_anonymous_user_allowed = isset($options['anonymous_user_allowed']) && $options['anonymous_user_allowed'];
|
||||
if (!$user_id && !$is_anonymous_user_allowed) return false;
|
||||
|
||||
$sql = $wpdb->prepare("INSERT INTO {$wpdb->base_prefix}tm_tasks (type, user_id, description, class_identifier, status) VALUES (%s, %d, %s, %s, %s)", $type, $user_id, $description, $class_identifier, 'active');
|
||||
|
||||
$wpdb->query($sql);
|
||||
|
||||
$task_id = $wpdb->insert_id;
|
||||
|
||||
if (!$task_id) return false;
|
||||
|
||||
$_task = $wpdb->get_row("SELECT * FROM {$wpdb->base_prefix}tm_tasks WHERE id = {$task_id} LIMIT 1");
|
||||
|
||||
$task = new $class_identifier($_task);
|
||||
|
||||
if (!$task) return false;
|
||||
|
||||
$task->initialise($options);
|
||||
|
||||
return $task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the current task from the database
|
||||
*
|
||||
* @param int $task_id - The task ID
|
||||
* @return object|false
|
||||
*/
|
||||
private function get_task_from_db($task_id) {
|
||||
global $wpdb;
|
||||
$sql = $wpdb->prepare("SELECT * FROM {$wpdb->base_prefix}tm_tasks WHERE id = %d LIMIT 1", $task_id);
|
||||
return $wpdb->get_row($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writing data to inaccessible/non-existing property
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __set($name, $value) {
|
||||
$this->extra_properties[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading data from inaccessible/non-existing property
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function __get($name) {
|
||||
return isset($this->extra_properties[$name]) ? $this->extra_properties[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when `isset` or `empty` are called on inaccessible/non-existing property
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name) {
|
||||
return isset($this->extra_properties[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when `unset` is called on inaccessible/non-existing property
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __unset($name) {
|
||||
unset($this->extra_properties[$name]);
|
||||
}
|
||||
}
|
||||
endif;
|
||||
Vendored
Executable
+303
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
/**
|
||||
* Initialise the tasks module and create the needed DB tables
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) die('Access denied.');
|
||||
|
||||
if (!class_exists('Updraft_Tasks_Activation')) :
|
||||
|
||||
class Updraft_Tasks_Activation {
|
||||
|
||||
private static $table_prefix;
|
||||
|
||||
/**
|
||||
* Format: key=<version>, value=array of method names to call
|
||||
* Example Usage:
|
||||
* private static $db_updates = array(
|
||||
* '1.0.1' => array(
|
||||
* 'update_101_add_new_column',
|
||||
* ),
|
||||
* );
|
||||
*
|
||||
* @var Mixed
|
||||
*/
|
||||
private static $db_updates = array(
|
||||
'0.0.1' => array('create_tables'),
|
||||
'1.0.1' => array('add_attempts_and_class_identifier'),
|
||||
'1.1' => array('add_lock_column'),
|
||||
);
|
||||
|
||||
|
||||
const UPDRAFT_TASKS_DB_VERSION = '1.1';
|
||||
|
||||
/**
|
||||
* Initialise the use of Task Manager library
|
||||
* Example Usage:
|
||||
* Updraft_Tasks_Activation::init(plugin_basename(__FILE__));
|
||||
* Updraft_Tasks_Activation::reinstall_if_needed();
|
||||
*
|
||||
* @param string $plugin_slug Plugin slug
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function init($plugin_slug) {
|
||||
$used_by_plugins = self::get_used_by_plugins();
|
||||
if (!in_array($plugin_slug, $used_by_plugins)) {
|
||||
self::update_used_by_plugins(array_merge($used_by_plugins, array($plugin_slug)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise this class
|
||||
*/
|
||||
public static function init_db() {
|
||||
self::$table_prefix = defined('UPDRAFT_TASKS_TABLE_PREFIX') ? UPDRAFT_TASKS_TABLE_PREFIX : 'tm_';
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the class entry point
|
||||
*/
|
||||
public static function install() {
|
||||
self::init_db();
|
||||
self::create_tables();
|
||||
// we need walk through all updates when install at first.
|
||||
self::check_updates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check needed tables in data base and if one of them doesn't exist force reinstall.
|
||||
*/
|
||||
public static function reinstall_if_needed() {
|
||||
static $done = false;
|
||||
|
||||
if ($done) return;
|
||||
|
||||
if (!self::check_if_tables_exist()) self::reinstall();
|
||||
|
||||
$done = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop database version variable from option from database and run install again.
|
||||
*/
|
||||
public static function reinstall() {
|
||||
self::delete_db_version_variable();
|
||||
self::install();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete database version variable from options table
|
||||
*/
|
||||
public static function delete_db_version_variable() {
|
||||
delete_site_option('updraft_task_manager_dbversion');
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop database tables and version variable from option from database
|
||||
*
|
||||
* @param string $plugin_slug Plugin slug
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall($plugin_slug) {
|
||||
self::delete_used_by_plugins($plugin_slug);
|
||||
$used_by_plugins = self::get_used_by_plugins();
|
||||
if (!empty($used_by_plugins)) return;
|
||||
self::delete_db_version_variable();
|
||||
if (empty(self::$table_prefix)) {
|
||||
self::init_db();
|
||||
}
|
||||
global $wpdb;
|
||||
$tables = array('tasks', 'taskmeta');
|
||||
foreach($tables as $table) {
|
||||
$table_name = $wpdb->prefix . self::$table_prefix . $table;
|
||||
$wpdb->query("DROP TABLE IF EXISTS $table_name");
|
||||
}
|
||||
self::delete_used_by_plugins();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if needed task manager tables exist.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function check_if_tables_exist() {
|
||||
global $wpdb;
|
||||
self::init_db();
|
||||
$our_prefix = $wpdb->base_prefix.self::$table_prefix;
|
||||
$tables = array($our_prefix.'tasks', $our_prefix.'taskmeta');
|
||||
|
||||
foreach ($tables as $table) {
|
||||
$query = "SHOW TABLES LIKE '{$table}'";
|
||||
$tables = $wpdb->get_results($query, ARRAY_A);
|
||||
if (!is_array($tables) || 0 == count($tables)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* See if any database schema updates are needed, and perform them if so.
|
||||
* Example Usage:
|
||||
* public static function update_101_add_new_column() {
|
||||
* $wpdb = $GLOBALS['wpdb'];
|
||||
* $wpdb->query('ALTER TABLE tm_tasks ADD task_expiry varchar(300) AFTER id');
|
||||
* }
|
||||
*/
|
||||
public static function check_updates() {
|
||||
self::init_db();
|
||||
$our_version = self::get_version();
|
||||
if (is_multisite()) {
|
||||
$db_version = get_site_option('updraft_task_manager_dbversion');
|
||||
} else {
|
||||
$db_version = get_option('updraft_task_manager_dbversion');
|
||||
}
|
||||
if (!$db_version || version_compare($our_version, $db_version, '>')) {
|
||||
foreach (self::$db_updates as $version => $updates) {
|
||||
if (version_compare($version, $db_version, '>')) {
|
||||
foreach ($updates as $update) {
|
||||
call_user_func(array(__CLASS__, $update));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_multisite()) {
|
||||
update_site_option('updraft_task_manager_dbversion', self::get_version());
|
||||
} else {
|
||||
update_option('updraft_task_manager_dbversion', self::get_version());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current version of the plugin
|
||||
*/
|
||||
public static function get_version() {
|
||||
return self::UPDRAFT_TASKS_DB_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the database tables
|
||||
*/
|
||||
public static function create_tables() {
|
||||
|
||||
$wpdb = $GLOBALS['wpdb'];
|
||||
|
||||
$our_prefix = $wpdb->base_prefix.self::$table_prefix;
|
||||
$collate = '';
|
||||
|
||||
if ($wpdb->has_cap('collation')) {
|
||||
if (!empty($wpdb->charset)) {
|
||||
$collate .= "DEFAULT CHARACTER SET $wpdb->charset";
|
||||
}
|
||||
if (!empty($wpdb->collate)) {
|
||||
$collate .= " COLLATE $wpdb->collate";
|
||||
}
|
||||
}
|
||||
|
||||
include_once ABSPATH.'wp-admin/includes/upgrade.php';
|
||||
|
||||
// Important: obey the magical/arbitrary rules for formatting this stuff: https://codex.wordpress.org/Creating_Tables_with_Plugins
|
||||
// Otherwise, you get SQL errors and unwanted header output warnings when activating
|
||||
|
||||
$create_tables = 'CREATE TABLE '.$our_prefix."tasks (
|
||||
task_id bigint(20) NOT NULL auto_increment,
|
||||
user_id bigint(20) NOT NULL,
|
||||
type varchar(300) NOT NULL,
|
||||
description varchar(300),
|
||||
PRIMARY KEY (task_id),
|
||||
KEY user_id (user_id),
|
||||
time_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
status varchar(300)
|
||||
) $collate;
|
||||
";
|
||||
// KEY attribute_name (attribute_name)
|
||||
dbDelta($create_tables);
|
||||
|
||||
$max_index_length = 191;
|
||||
|
||||
$create_tables = 'CREATE TABLE '.$our_prefix."taskmeta (
|
||||
meta_id bigint(20) NOT NULL auto_increment,
|
||||
task_id bigint(20) NOT NULL default '0',
|
||||
meta_key varchar(255) DEFAULT NULL,
|
||||
meta_value longtext,
|
||||
PRIMARY KEY (meta_id),
|
||||
KEY meta_key (meta_key($max_index_length)),
|
||||
KEY task_id (task_id)
|
||||
) $collate;
|
||||
";
|
||||
|
||||
dbDelta($create_tables);
|
||||
}
|
||||
|
||||
public static function add_attempts_and_class_identifier() {
|
||||
$wpdb = $GLOBALS['wpdb'];
|
||||
$our_prefix = $wpdb->base_prefix.self::$table_prefix;
|
||||
|
||||
$wpdb->query("ALTER TABLE ".$our_prefix."tasks CHANGE COLUMN `task_id` `id` INT NOT NULL");
|
||||
$wpdb->query("ALTER TABLE ".$our_prefix."tasks MODIFY COLUMN `id` INT auto_increment");
|
||||
$wpdb->query("ALTER TABLE ".$our_prefix."tasks ADD attempts INT DEFAULT 0 AFTER type");
|
||||
$wpdb->query("ALTER TABLE ".$our_prefix."tasks ADD class_identifier varchar(300) DEFAULT 0 AFTER type");
|
||||
}
|
||||
|
||||
public static function add_lock_column() {
|
||||
$wpdb = $GLOBALS['wpdb'];
|
||||
$our_prefix = $wpdb->base_prefix.self::$table_prefix;
|
||||
$wpdb->query('ALTER TABLE '.$our_prefix.'tasks ADD last_locked_at BIGINT DEFAULT 0 AFTER time_created');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of plugin slugs that uses this library
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function get_used_by_plugins() {
|
||||
return get_site_option('updraft_task_manager_plugins', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the array of plugin slugs that uses this library
|
||||
*
|
||||
* @param array $used_by_plugins An array of plugin slugs
|
||||
*/
|
||||
private static function update_used_by_plugins($used_by_plugins) {
|
||||
if (is_multisite()) {
|
||||
update_site_option('updraft_task_manager_plugins', $used_by_plugins);
|
||||
} else {
|
||||
update_option('updraft_task_manager_plugins', $used_by_plugins);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes either given plugin slug. If plugin slug is not provided removes option itself
|
||||
*
|
||||
* @param string $plugin_slug Plugin slug
|
||||
*/
|
||||
private static function delete_used_by_plugins($plugin_slug = '') {
|
||||
if (!empty($plugin_slug)) {
|
||||
$used_by_plugins = self::get_used_by_plugins();
|
||||
$used_by_plugins = self::remove_plugin_from_array($used_by_plugins, $plugin_slug);
|
||||
self::update_used_by_plugins($used_by_plugins);
|
||||
} else {
|
||||
delete_site_option('updraft_task_manager_plugins');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove given plugin slug from an array of plugin slugs
|
||||
*
|
||||
* @param array $used_by_plugins An array of plugin slugs
|
||||
* @param string $plugin_slug Plugin slug
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function remove_plugin_from_array($used_by_plugins, $plugin_slug) {
|
||||
$key = array_search($plugin_slug, $used_by_plugins);
|
||||
if (false !== $key) {
|
||||
unset($used_by_plugins[$key]);
|
||||
}
|
||||
return $used_by_plugins;
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
Vendored
Executable
+93
@@ -0,0 +1,93 @@
|
||||
# lib-central
|
||||
|
||||
|
||||
|
||||
## Getting started
|
||||
|
||||
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
|
||||
|
||||
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
|
||||
|
||||
## Add your files
|
||||
|
||||
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
|
||||
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
|
||||
|
||||
```
|
||||
cd existing_repo
|
||||
git remote add origin https://source.updraftplus.com/team-updraft/lib-central.git
|
||||
git branch -M master
|
||||
git push -uf origin master
|
||||
```
|
||||
|
||||
## Integrate with your tools
|
||||
|
||||
- [ ] [Set up project integrations](https://source.updraftplus.com/team-updraft/lib-central/-/settings/integrations)
|
||||
|
||||
## Collaborate with your team
|
||||
|
||||
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
|
||||
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
|
||||
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
|
||||
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
|
||||
- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
|
||||
|
||||
## Test and Deploy
|
||||
|
||||
Use the built-in continuous integration in GitLab.
|
||||
|
||||
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
|
||||
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
|
||||
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
|
||||
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
|
||||
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
|
||||
|
||||
***
|
||||
|
||||
# Editing this README
|
||||
|
||||
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
|
||||
|
||||
## Suggestions for a good README
|
||||
|
||||
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
|
||||
|
||||
## Name
|
||||
Choose a self-explaining name for your project.
|
||||
|
||||
## Description
|
||||
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
|
||||
|
||||
## Badges
|
||||
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
|
||||
|
||||
## Visuals
|
||||
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
|
||||
|
||||
## Installation
|
||||
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
|
||||
|
||||
## Usage
|
||||
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
|
||||
|
||||
## Support
|
||||
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
|
||||
|
||||
## Roadmap
|
||||
If you have ideas for releases in the future, it is a good idea to list them in the README.
|
||||
|
||||
## Contributing
|
||||
State if you are open to contributions and what your requirements are for accepting them.
|
||||
|
||||
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
|
||||
|
||||
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
|
||||
|
||||
## Authors and acknowledgment
|
||||
Show your appreciation to those who have contributed to the project.
|
||||
|
||||
## License
|
||||
For open source projects, say how it is licensed.
|
||||
|
||||
## Project status
|
||||
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
||||
Vendored
Executable
+851
@@ -0,0 +1,851 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
if (!$updraftcentral_host_plugin->is_host_dir_set()) die('No access.');
|
||||
|
||||
// This file is included during plugins_loaded
|
||||
|
||||
// Load the listener class that we rely on to pick up messages
|
||||
if (!class_exists('UpdraftCentral_Listener')) require_once('listener.php');
|
||||
|
||||
// We exit if class already exists. More common if two or more plugins integrated
|
||||
// the same `UpdraftCentral` client folder.
|
||||
if (!class_exists('UpdraftCentral_Main')) :
|
||||
|
||||
class UpdraftCentral_Main {
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
add_action('udrpc_log', array($this, 'udrpc_log'), 10, 3);
|
||||
|
||||
add_action('wp_ajax_updraftcentral_receivepublickey', array($this, 'wp_ajax_updraftcentral_receivepublickey'));
|
||||
add_action('wp_ajax_nopriv_updraftcentral_receivepublickey', array($this, 'wp_ajax_updraftcentral_receivepublickey'));
|
||||
|
||||
// The host plugin's command class is registered in its "plugins_loaded" method (e.g. UpdraftPlus::plugins_loaded()).
|
||||
//
|
||||
// N.B. The new filter "updraftcentral_remotecontrol_command_classes" was introduced on Jan. 2021 and will soon replace the
|
||||
// old filter "updraftplus_remotecontrol_command_classes" (below). This was done in order to synchronize all available filters
|
||||
// and actions related to UpdraftCentral so that we can easily port the UpdraftCentral client code into our other plugins.
|
||||
//
|
||||
// If you happened to use the old filter from any of your projects then you might as well update it with the new filter as the
|
||||
// old filter has already been marked as deprecated, though currently supported as can be seen below but will soon be remove
|
||||
// from this code block.
|
||||
$command_classes = apply_filters('updraftcentral_remotecontrol_command_classes', array(
|
||||
'core' => 'UpdraftCentral_Core_Commands',
|
||||
'updates' => 'UpdraftCentral_Updates_Commands',
|
||||
'users' => 'UpdraftCentral_Users_Commands',
|
||||
'comments' => 'UpdraftCentral_Comments_Commands',
|
||||
'analytics' => 'UpdraftCentral_Analytics_Commands',
|
||||
'plugin' => 'UpdraftCentral_Plugin_Commands',
|
||||
'theme' => 'UpdraftCentral_Theme_Commands',
|
||||
'posts' => 'UpdraftCentral_Posts_Commands',
|
||||
'media' => 'UpdraftCentral_Media_Commands',
|
||||
'pages' => 'UpdraftCentral_Pages_Commands',
|
||||
'backups' => 'UpdraftCentral_Backups_Commands'
|
||||
));
|
||||
|
||||
// N.B. This "updraftplus_remotecontrol_command_classes" filter has been marked as deprecated and will be remove after May 2021.
|
||||
// Please see above code comment for further explanation and its alternative.
|
||||
$command_classes = apply_filters('updraftplus_remotecontrol_command_classes', $command_classes);
|
||||
|
||||
// If nothing was sent, then there is no incoming message, so no need to set up a listener (or CORS request, etc.). This avoids a DB SELECT query on the option below in the case where it didn't get autoloaded, which is the case when there are no keys.
|
||||
if (!empty($_SERVER['REQUEST_METHOD']) && ('GET' == $_SERVER['REQUEST_METHOD'] || 'POST' == $_SERVER['REQUEST_METHOD']) && (empty($_REQUEST['action']) || 'updraft_central' !== $_REQUEST['action']) && empty($_REQUEST['udcentral_action']) && empty($_REQUEST['udrpc_message'])) return;
|
||||
|
||||
// Remote control keys
|
||||
// These are different from the remote send keys, which are set up in the Migrator add-on
|
||||
$our_keys = $this->get_central_localkeys();
|
||||
|
||||
if (is_array($our_keys) && !empty($our_keys)) {
|
||||
new UpdraftCentral_Listener($our_keys, $command_classes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues the needed styles and scripts for UpdraftCentral
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_central_scripts() {
|
||||
|
||||
// This is an additional check; the caller is assumed to have already run checks before painting its page in general
|
||||
if (!current_user_can('manage_options')) return;
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
$version = $updraftcentral_host_plugin->get_version();
|
||||
|
||||
$enqueue_version = (defined('WP_DEBUG') && WP_DEBUG) ? $version.'.'.time() : $version;
|
||||
$min_or_not = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
|
||||
|
||||
// Fallback to unminified version if the minified version is not found.
|
||||
if (!empty($min_or_not) && !file_exists(UPDRAFTCENTRAL_CLIENT_DIR.'/js/central'.$min_or_not.'.js')) {
|
||||
$min_or_not = '';
|
||||
}
|
||||
|
||||
wp_enqueue_script('updraft-central', UPDRAFTCENTRAL_CLIENT_URL.'/js/central'.$min_or_not.'.js', array(), $enqueue_version);
|
||||
wp_enqueue_style('updraft-central', UPDRAFTCENTRAL_CLIENT_URL.'/css/central'.$min_or_not.'.css', array(), $enqueue_version);
|
||||
|
||||
$localize = array_merge(
|
||||
array(
|
||||
'central_url' => UPDRAFTCENTRAL_CLIENT_URL,
|
||||
'plugin_name' => $updraftcentral_host_plugin->get_plugin_name(),
|
||||
'updraftcentral_request_nonce' => wp_create_nonce('updraftcentral-request-nonce'),
|
||||
),
|
||||
$updraftcentral_host_plugin->translations
|
||||
);
|
||||
|
||||
wp_localize_script('updraft-central', 'uclion', apply_filters('updraftcentral_uclion', $localize));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves current clean url for anchor link where href attribute value is not url (for ex. #div) or empty. Output is not escaped (caller should escape).
|
||||
*
|
||||
* @return String - current clean url
|
||||
*/
|
||||
public function get_current_clean_url() {
|
||||
|
||||
// Within an UpdraftCentral context, there should be no prefix on the anchor link
|
||||
if (defined('UPDRAFTCENTRAL_COMMAND') && UPDRAFTCENTRAL_COMMAND || defined('WP_CLI') && WP_CLI) return '';
|
||||
|
||||
if (defined('DOING_AJAX') && DOING_AJAX && !empty($_SERVER['HTTP_REFERER'])) {
|
||||
$current_url = $_SERVER['HTTP_REFERER'];
|
||||
} else {
|
||||
$url_prefix = is_ssl() ? 'https' : 'http';
|
||||
$host = empty($_SERVER['HTTP_HOST']) ? parse_url(network_site_url(), PHP_URL_HOST) : $_SERVER['HTTP_HOST'];
|
||||
$current_url = $url_prefix."://".$host.wp_unslash($_SERVER['REQUEST_URI']);
|
||||
}
|
||||
$remove_query_args = array('state', 'action', 'oauth_verifier', 'nonce', 'updraftplus_instance', 'access_token', 'user_id', 'updraftplus_googledriveauth');
|
||||
|
||||
$query_string = remove_query_arg($remove_query_args, $current_url);
|
||||
return function_exists('wp_unslash') ? wp_unslash($query_string) : stripslashes_deep($query_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WordPress version
|
||||
*
|
||||
* @return String - the version
|
||||
*/
|
||||
public function get_wordpress_version() {
|
||||
static $got_wp_version = false;
|
||||
if (!$got_wp_version) {
|
||||
@include(ABSPATH.WPINC.'/version.php');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
|
||||
$got_wp_version = $wp_version;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
|
||||
}
|
||||
return $got_wp_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the UpdraftCentral generated keys
|
||||
*
|
||||
* @param Mixed $default default value to return when option is not found
|
||||
*
|
||||
* @return Mixed
|
||||
*/
|
||||
private function get_central_localkeys($default = null) {
|
||||
|
||||
$option = 'updraft_central_localkeys';
|
||||
$ret = get_option($option, $default);
|
||||
return apply_filters('updraftcentral_get_option', $ret, $option, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the UpdraftCentral's keys
|
||||
*
|
||||
* @param string $value Specify option value
|
||||
* @param bool $use_cache Whether or not to use the WP options cache
|
||||
* @param string $autoload Whether to autoload (only takes effect on a change of value)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function update_central_localkeys($value, $use_cache = true, $autoload = 'yes') {
|
||||
$option = 'updraft_central_localkeys';
|
||||
|
||||
return update_option($option, apply_filters('updraftcentral_update_option', $value, $option, $use_cache), $autoload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive a new public key in $_GET, and echo a response. Will die() if called.
|
||||
*/
|
||||
public function wp_ajax_updraftcentral_receivepublickey() {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
// The actual nonce check is done in the method below
|
||||
if (empty($_GET['_wpnonce']) || empty($_GET['public_key']) || !isset($_GET['updraft_key_index'])) die;
|
||||
|
||||
$result = $this->receive_public_key();
|
||||
if (!is_array($result) || empty($result['responsetype'])) die;
|
||||
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>UpdraftCentral</title>
|
||||
<style>
|
||||
body {text-align: center;font-family: Helvetica,Arial,Lucida,sans-serif;background-color: #A64C1A;color: #FFF;height: 100%;width: 100%;margin: 0;padding: 0;}#main {height: 100%;width: 100%;display: table;}#wrapper {display: table-cell;height: 100%;vertical-align: middle;}h1 {margin-bottom: 5px;}h2 {margin-top: 0;font-size: 22px;color: #FFF;}#btn-close {color: #FFF;font-size: 20px;font-weight: 500;padding: .3em 1em;line-height: 1.7em !important;background-color: transparent;background-size: cover;background-position: 50%;background-repeat: no-repeat;border: 2px solid;border-radius: 3px;-webkit-transition-duration: .2s;transition-duration: .2s;-webkit-transition-property: all !important;transition-property: all !important;text-decoration: none;}#btn-close:hover {background-color: #DE6726;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<div id="wrapper"><img src="<?php echo esc_url(UPDRAFTCENTRAL_CLIENT_URL).'/images/ud-logo.png'; ?>" width="60" /> <h1><?php $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_connection', true); ?></h1><h2><?php echo esc_html(network_site_url()); ?></h2><p>
|
||||
<?php
|
||||
if ('ok' == $result['responsetype']) {
|
||||
$updraftcentral_host_plugin->retrieve_show_message('updraftcentral_connection_successful', true);
|
||||
} else {
|
||||
?>
|
||||
<strong><span id="udc-connect-failed">
|
||||
<?php $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_connection_failed', true); ?>
|
||||
</span></strong><br>
|
||||
<?php
|
||||
switch ($result['code']) {
|
||||
case 'unknown_key':
|
||||
$updraftcentral_host_plugin->retrieve_show_message('unknown_key', true);
|
||||
break;
|
||||
case 'not_logged_in':
|
||||
echo esc_html($updraftcentral_host_plugin->retrieve_show_message('not_logged_in')).' ';
|
||||
$updraftcentral_host_plugin->retrieve_show_message('must_visit_url', true);
|
||||
break;
|
||||
case 'nonce_failure':
|
||||
$updraftcentral_host_plugin->retrieve_show_message('security_check', true);
|
||||
$updraftcentral_host_plugin->retrieve_show_message('must_visit_link', true);
|
||||
break;
|
||||
case 'already_have':
|
||||
$updraftcentral_host_plugin->retrieve_show_message('connection_already_made', true);
|
||||
break;
|
||||
case 'insufficient_privilege':
|
||||
$updraftcentral_host_plugin->retrieve_show_message('insufficient_privilege', true);
|
||||
break;
|
||||
default:
|
||||
echo esc_html(print_r($result, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
<p><a id="btn-close" href="<?php echo esc_url($this->get_current_clean_url()); ?>" onclick="window.close();"><?php $updraftcentral_host_plugin->retrieve_show_message('close', true); ?></a>
|
||||
</p></div></div>
|
||||
<?php
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks _wpnonce, and if successful, saves the public key found in $_GET
|
||||
*
|
||||
* @return Array - with keys responsetype (can be 'error' or 'ok') and code, indicating whether the parse was successful
|
||||
*/
|
||||
private function receive_public_key() {
|
||||
|
||||
if (!is_user_logged_in()) {
|
||||
return array('responsetype' => 'error', 'code' => 'not_logged_in');
|
||||
}
|
||||
|
||||
if (!wp_verify_nonce($_GET['_wpnonce'], 'updraftcentral_receivepublickey')) return array('responsetype' => 'error', 'code' => 'nonce_failure');
|
||||
|
||||
$updraft_key_index = $_GET['updraft_key_index'];
|
||||
$our_keys = $this->get_central_localkeys();
|
||||
|
||||
if (!is_array($our_keys)) $our_keys = array();
|
||||
|
||||
if (!isset($our_keys[$updraft_key_index])) {
|
||||
return array('responsetype' => 'error', 'code' => 'unknown_key');
|
||||
}
|
||||
|
||||
if (!empty($our_keys[$updraft_key_index]['publickey_remote'])) {
|
||||
return array('responsetype' => 'error', 'code' => 'already_have');
|
||||
}
|
||||
|
||||
$our_keys[$updraft_key_index]['publickey_remote'] = base64_decode(stripslashes($_GET['public_key']));
|
||||
$this->update_central_localkeys($our_keys, true, 'no');
|
||||
|
||||
return array('responsetype' => 'ok', 'code' => 'ok');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action parameters, from udrpc: $message, $level, $this->key_name_indicator, $this->debug, $this
|
||||
*
|
||||
* @param string $message The log message
|
||||
* @param string $level Log level
|
||||
* @param string $key_name_indicator This indicates the key name
|
||||
*/
|
||||
public function udrpc_log($message, $level, $key_name_indicator) {
|
||||
|
||||
$udrpc_log = get_site_option('updraftcentral_client_log');
|
||||
if (!is_array($udrpc_log)) $udrpc_log = array();
|
||||
|
||||
$new_item = array(
|
||||
'time' => time(),
|
||||
'level' => $level,
|
||||
'message' => $message,
|
||||
'key_name_indicator' => $key_name_indicator
|
||||
);
|
||||
|
||||
if (!empty($_SERVER['REMOTE_ADDR'])) {
|
||||
$new_item['remote_ip'] = $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
if (!empty($_SERVER['HTTP_USER_AGENT'])) {
|
||||
$new_item['http_user_agent'] = $_SERVER['HTTP_USER_AGENT'];
|
||||
}
|
||||
if (!empty($_SERVER['HTTP_X_SECONDARY_USER_AGENT'])) {
|
||||
$new_item['http_secondary_user_agent'] = $_SERVER['HTTP_X_SECONDARY_USER_AGENT'];
|
||||
}
|
||||
|
||||
$udrpc_log[] = $new_item;
|
||||
|
||||
if (count($udrpc_log) > 50) array_shift($udrpc_log);
|
||||
|
||||
update_site_option('updraftcentral_client_log', $udrpc_log);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete UpdraftCentral Key
|
||||
*
|
||||
* @param array $key_id key_id of UpdraftCentral
|
||||
*
|
||||
* @return array which contains deleted flag and key table. If error, Returns array which contains fatal_error flag and fatal_error_message
|
||||
*/
|
||||
public function delete_key($key_id) {
|
||||
|
||||
$our_keys = $this->get_central_localkeys();
|
||||
if (is_array($key_id) && isset($key_id['key_id'])) {
|
||||
$key_id = $key_id['key_id'];
|
||||
}
|
||||
|
||||
if (!is_array($our_keys)) $our_keys = array();
|
||||
if (isset($our_keys[$key_id])) {
|
||||
unset($our_keys[$key_id]);
|
||||
$this->update_central_localkeys($our_keys);
|
||||
}
|
||||
return array('deleted' => 1, 'keys_table' => $this->get_keys_table());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get UpdraftCentral Log
|
||||
*
|
||||
* @return array which contains log_contents. If error, Returns array which contains fatal_error flag and fatal_error_message
|
||||
*/
|
||||
public function get_log() {
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
$udrpc_log = get_site_option('updraftcentral_client_log');
|
||||
if (!is_array($udrpc_log)) $udrpc_log = array();
|
||||
|
||||
$log_contents = '';
|
||||
|
||||
// Events are appended to the array in the order they happen. So, reversing the order gets them into most-recent-first order.
|
||||
rsort($udrpc_log);
|
||||
|
||||
if (empty($udrpc_log)) {
|
||||
$log_contents = '<em>'.$updraftcentral_host_plugin->retrieve_show_message('nothing_yet_logged').'</em>';
|
||||
}
|
||||
|
||||
foreach ($udrpc_log as $m) {
|
||||
|
||||
// Skip invalid data
|
||||
if (!isset($m['time'])) continue;
|
||||
|
||||
$time = gmdate('Y-m-d H:i:s O', $m['time']);
|
||||
// $level is not used yet. We could put the message in different colours for different levels, if/when it becomes used.
|
||||
|
||||
$key_name_indicator = empty($m['key_name_indicator']) ? '' : $m['key_name_indicator'];
|
||||
|
||||
$log_contents .= '<span title="'.esc_attr(print_r($m, true)).'">'."$time ";
|
||||
|
||||
if (!empty($m['remote_ip'])) $log_contents .= '['.htmlspecialchars($m['remote_ip']).'] ';
|
||||
|
||||
$log_contents .= "[".htmlspecialchars($key_name_indicator)."] ".htmlspecialchars($m['message'])."</span>\n";
|
||||
}
|
||||
|
||||
return array('log_contents' => $log_contents);
|
||||
|
||||
}
|
||||
|
||||
public function create_key($params) {
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
// Use the site URL - this means that if the site URL changes, communication ends; which is the case anyway
|
||||
$user = wp_get_current_user();
|
||||
|
||||
if (!is_object($user) || empty($user->ID)) return array('error' => $updraftcentral_host_plugin->retrieve_show_message('insufficient_privilege'));
|
||||
|
||||
if (!current_user_can('manage_options')) return array('error' => $updraftcentral_host_plugin->retrieve_show_message('insufficient_privilege'));
|
||||
|
||||
$where_send = empty($params['where_send']) ? '' : (string) $params['where_send'];
|
||||
|
||||
if ('__updraftpluscom' != $where_send) {
|
||||
$purl = parse_url($where_send);
|
||||
if (empty($purl) || !array($purl) || empty($purl['scheme']) || empty($purl['host'])) return array('error' => $updraftcentral_host_plugin->retrieve_show_message('invalid_url'));
|
||||
}
|
||||
|
||||
// ENT_HTML5 exists only on PHP 5.4+
|
||||
// @codingStandardsIgnoreLine
|
||||
$flags = defined('ENT_HTML5') ? ENT_QUOTES | ENT_HTML5 : ENT_QUOTES;
|
||||
|
||||
$extra_info = array(
|
||||
'user_id' => $user->ID,
|
||||
'user_login' => $user->user_login,
|
||||
'ms_id' => get_current_blog_id(),
|
||||
'site_title' => html_entity_decode(get_bloginfo('name'), $flags),
|
||||
);
|
||||
|
||||
if ($where_send) {
|
||||
$extra_info['mothership'] = $where_send;
|
||||
if (!empty($params['mothership_firewalled'])) {
|
||||
$extra_info['mothership_firewalled'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($params['key_description'])) {
|
||||
$extra_info['name'] = (string) $params['key_description'];
|
||||
}
|
||||
|
||||
$key_size = (empty($params['key_size']) || !is_numeric($params['key_size']) || $params['key_size'] < 512) ? 2048 : (int) $params['key_size'];
|
||||
|
||||
$extra_info['key_size'] = $key_size;
|
||||
|
||||
$created = $this->create_remote_control_key(false, $extra_info, $where_send);
|
||||
|
||||
if (is_array($created)) {
|
||||
$created['keys_table'] = $this->get_keys_table();
|
||||
|
||||
$created['keys_guide'] = '<h2 class="updraftcentral_wizard_success">'. $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_key_created') .'</h2>';
|
||||
|
||||
if ('__updraftpluscom' != $where_send) {
|
||||
$created['keys_guide'] .= '<div class="updraftcentral_wizard_success"><p>'.sprintf($updraftcentral_host_plugin->retrieve_show_message('need_to_copy_key'), '<a href="'.$where_send.'" target="_blank">UpdraftCentral dashboard</a>').'</p><p>'.$updraftcentral_host_plugin->retrieve_show_message('press_add_site_button').'</p><p>'.sprintf($updraftcentral_host_plugin->retrieve_show_message('detailed_instructions'), '<a target="_blank" href="https://updraftplus.com/updraftcentral-how-to-add-a-site/">UpdraftPlus.com</a>').'</p></div>';
|
||||
} else {
|
||||
$created['keys_guide'] .= '<div class="updraftcentral_wizard_success"><p>'. sprintf($updraftcentral_host_plugin->retrieve_show_message('control_this_site'), '<a target="_blank" href="https://updraftplus.com/my-account/updraftcentral-remote-control/">UpdraftPlus.com</a>').'</p></div>';
|
||||
}
|
||||
}
|
||||
|
||||
return $created;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an index, return the indicator name
|
||||
*
|
||||
* @param String $index
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
private function indicator_name_from_index($index) {
|
||||
return $index.'.central.updraftplus.com';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an RPC object, and sets some defaults on it that we always want
|
||||
*
|
||||
* @param string $indicator_name indicator name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_udrpc($indicator_name = 'migrator.updraftplus.com') {
|
||||
|
||||
global $updraftcentral_host_plugin, $updraftplus;
|
||||
|
||||
$updraftplus->ensure_phpseclib();
|
||||
|
||||
if (!class_exists('UpdraftPlus_Remote_Communications_V2')) include_once($updraftcentral_host_plugin->get_host_dir().'/vendor/team-updraft/common-libs/src/updraft-rpc/class-udrpc2.php');
|
||||
$ud_rpc = new UpdraftPlus_Remote_Communications_V2($indicator_name);
|
||||
$ud_rpc->set_can_generate(true);
|
||||
|
||||
return $ud_rpc;
|
||||
}
|
||||
|
||||
private function create_remote_control_key($index = false, $extra_info = array(), $post_it = false) {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
$our_keys = $this->get_central_localkeys();
|
||||
if (!is_array($our_keys)) $our_keys = array();
|
||||
|
||||
if (false === $index) {
|
||||
if (empty($our_keys)) {
|
||||
$index = 0;
|
||||
} else {
|
||||
$index = max(array_keys($our_keys))+1;
|
||||
}
|
||||
}
|
||||
|
||||
$name_hash = $index;
|
||||
|
||||
if (isset($our_keys[$name_hash])) {
|
||||
unset($our_keys[$name_hash]);
|
||||
}
|
||||
|
||||
$indicator_name = $this->indicator_name_from_index($name_hash);
|
||||
$ud_rpc = $this->get_udrpc($indicator_name);
|
||||
|
||||
if ('__updraftpluscom' == $post_it) {
|
||||
$post_it = defined('UPDRAFTPLUS_OVERRIDE_UDCOM_DESTINATION') ? UPDRAFTPLUS_OVERRIDE_UDCOM_DESTINATION : 'https://updraftplus.com/?updraftcentral_action=receive_key';
|
||||
$post_it_description = 'UpdraftPlus.Com';
|
||||
} else {
|
||||
$post_it_description = $post_it;
|
||||
}
|
||||
|
||||
// Normally, key generation takes seconds, even on a slow machine. However, some Windows machines appear to have a setup in which it takes a minute or more. And then, if you're on a double-localhost setup on slow hardware - even worse. It doesn't hurt to just raise the maximum execution time.
|
||||
|
||||
if (function_exists('set_time_limit')) @set_time_limit(UPDRAFTCENTRAL_SET_TIME_LIMIT);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
|
||||
|
||||
$key_size = (empty($extra_info['key_size']) || !is_numeric($extra_info['key_size']) || $extra_info['key_size'] < 512) ? 2048 : (int) $extra_info['key_size'];
|
||||
|
||||
if (is_object($ud_rpc) && $ud_rpc->generate_new_keypair($key_size)) {
|
||||
|
||||
if ($post_it && empty($extra_info['mothership_firewalled'])) {
|
||||
|
||||
$p_url = parse_url($post_it);
|
||||
if (is_array($p_url) && !empty($p_url['user'])) {
|
||||
$http_username = $p_url['user'];
|
||||
$http_password = empty($p_url['pass']) ? '' : $p_url['pass'];
|
||||
$post_it = $p_url['scheme'].'://'.$p_url['host'];
|
||||
if (!empty($p_url['port'])) $post_it .= ':'.$p_url['port'];
|
||||
$post_it .= $p_url['path'];
|
||||
if (!empty($p_url['query'])) $post_it .= '?'.$p_url['query'];
|
||||
}
|
||||
|
||||
$post_options = array(
|
||||
'timeout' => 90,
|
||||
'body' => array(
|
||||
'updraftcentral_action' => 'receive_key',
|
||||
'key' => $ud_rpc->get_key_remote()
|
||||
)
|
||||
);
|
||||
|
||||
if (!empty($http_username)) {
|
||||
$post_options['headers'] = array(
|
||||
'Authorization' => 'Basic '.base64_encode($http_username.':'.$http_password)
|
||||
);
|
||||
}
|
||||
|
||||
// This option allows the key to be sent to the other side via a known-secure channel (e.g. http over SSL), rather than potentially allowing it to travel over an unencrypted channel (e.g. http back to the user's browser). As such, if specified, it is compulsory for it to work.
|
||||
|
||||
$updraftcentral_host_plugin->register_wp_http_option_hooks();
|
||||
|
||||
$sent_key = wp_remote_post(
|
||||
$post_it,
|
||||
$post_options
|
||||
);
|
||||
|
||||
$updraftcentral_host_plugin->register_wp_http_option_hooks(false);
|
||||
|
||||
$connection_troubleshooting_url = 'https://updraftplus.com/troubleshooting-updraftcentral-connection-issues/';
|
||||
if (is_wp_error($sent_key) || empty($sent_key)) {
|
||||
|
||||
$err_msg = sprintf($updraftcentral_host_plugin->retrieve_show_message('attempt_to_register_failed'), (string) $post_it_description, $connection_troubleshooting_url);
|
||||
if (is_wp_error($sent_key)) $err_msg .= ' '.$sent_key->get_error_message().' ('.$sent_key->get_error_code().')';
|
||||
return array(
|
||||
'r' => $err_msg
|
||||
);
|
||||
}
|
||||
|
||||
$response = json_decode(wp_remote_retrieve_body($sent_key), true);
|
||||
|
||||
if (!is_array($response) || !isset($response['key_id']) || !isset($response['key_public'])) {
|
||||
return array(
|
||||
'r' => sprintf($updraftcentral_host_plugin->retrieve_show_message('attempt_to_register_failed'), (string) $post_it_description, $connection_troubleshooting_url),
|
||||
'raw' => wp_remote_retrieve_body($sent_key)
|
||||
);
|
||||
}
|
||||
|
||||
$key_hash = hash('sha256', $ud_rpc->get_key_remote());
|
||||
|
||||
$local_bundle = $ud_rpc->get_portable_bundle('base64_with_count', $extra_info, array('key' => array('key_hash' => $key_hash, 'key_id' => $response['key_id'])));
|
||||
|
||||
} elseif ($post_it) {
|
||||
// Don't send; instead, include in the bundle info that the mothership is firewalled; this will then tell the mothership to try the reverse connection instead
|
||||
|
||||
if (is_array($extra_info)) {
|
||||
$extra_info['mothership_firewalled_callback_url'] = wp_nonce_url(admin_url('admin-ajax.php'), 'updraftcentral_receivepublickey');
|
||||
$extra_info['updraft_key_index'] = $index;
|
||||
}
|
||||
|
||||
|
||||
$local_bundle = $ud_rpc->get_portable_bundle('base64_with_count', $extra_info, array('key' => $ud_rpc->get_key_remote()));
|
||||
}
|
||||
|
||||
|
||||
if (isset($extra_info['name'])) {
|
||||
$name = (string) $extra_info['name'];
|
||||
unset($extra_info['name']);
|
||||
} else {
|
||||
$name = 'UpdraftCentral Remote Control';
|
||||
}
|
||||
|
||||
$our_keys[$name_hash] = array(
|
||||
'name' => $name,
|
||||
'key' => $ud_rpc->get_key_local(),
|
||||
'extra_info' => $extra_info,
|
||||
'created' => time(),
|
||||
);
|
||||
// Store the other side's public key
|
||||
if (!empty($response) && is_array($response) && !empty($response['key_public'])) {
|
||||
$our_keys[$name_hash]['publickey_remote'] = $response['key_public'];
|
||||
}
|
||||
$this->update_central_localkeys($our_keys, true, 'no');
|
||||
|
||||
return array(
|
||||
'bundle' => $local_bundle,
|
||||
'r' => $updraftcentral_host_plugin->retrieve_show_message('key_created_successfully').' '.$updraftcentral_host_plugin->retrieve_show_message('copy_paste_key'),
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML for the keys table
|
||||
*
|
||||
* @param Boolean $echo_instead_of_return Whether the result should be echoed or returned
|
||||
* @return String
|
||||
*/
|
||||
public function get_keys_table($echo_instead_of_return = false) {
|
||||
|
||||
// This is an additional check - it implies requirement for a dashboard context
|
||||
if (!current_user_can('manage_options')) return;
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
if (!$echo_instead_of_return) ob_start();
|
||||
|
||||
$our_keys = $this->get_central_localkeys();
|
||||
if (!is_array($our_keys)) $our_keys = array();
|
||||
|
||||
if (empty($our_keys)) {
|
||||
?>
|
||||
<tr><td colspan="2"><em><?php $updraftcentral_host_plugin->retrieve_show_message('no_updraftcentral_dashboards', true); ?></em></td></tr>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
<div id="updraftcentral_keys_content" style="margin: 10px 0;">
|
||||
<?php if (!empty($our_keys)) { ?>
|
||||
<a href="<?php echo esc_url($this->get_current_clean_url()); ?>" class="updraftcentral_keys_show hidden-in-updraftcentral"><?php echo wp_kses_post(sprintf($updraftcentral_host_plugin->retrieve_show_message('manage_keys'), count($our_keys))); ?></a>
|
||||
<?php } ?>
|
||||
<table id="updraftcentral_keys_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left;"><?php $updraftcentral_host_plugin->retrieve_show_message('key_description', true); ?></th>
|
||||
<th style="text-align:left;"><?php $updraftcentral_host_plugin->retrieve_show_message('details', true); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
foreach ($our_keys as $i => $key) {
|
||||
|
||||
if (empty($key['extra_info'])) continue;
|
||||
|
||||
$user_id = $key['extra_info']['user_id'];
|
||||
|
||||
if (!empty($key['extra_info']['mothership'])) {
|
||||
|
||||
$mothership_url = $key['extra_info']['mothership'];
|
||||
|
||||
if ('__updraftpluscom' == $mothership_url) {
|
||||
$reconstructed_url = 'https://updraftplus.com';
|
||||
} else {
|
||||
$purl = parse_url($mothership_url);
|
||||
$path = empty($purl['path']) ? '' : $purl['path'];
|
||||
|
||||
$reconstructed_url = $purl['scheme'].'://'.$purl['host'].(!empty($purl['port']) ? ':'.$purl['port'] : '').$path;
|
||||
}
|
||||
|
||||
} else {
|
||||
$reconstructed_url = $updraftcentral_host_plugin->retrieve_show_message('unknown');
|
||||
}
|
||||
|
||||
$name = $key['name'];
|
||||
|
||||
$user = get_user_by('id', $user_id);
|
||||
|
||||
$user_display = is_a($user, 'WP_User') ? $user->user_login.' ('.$user->user_email.')' : $updraftcentral_host_plugin->retrieve_show_message('unknown');
|
||||
?>
|
||||
<tr class="updraft_debugrow"><td style="vertical-align:top;"><?php echo esc_html($name.' ('.$i.')'); ?></td><td><?php $updraftcentral_host_plugin->retrieve_show_message('access_as_user', true); ?> <?php echo esc_html($user_display); ?> <br> <?php $updraftcentral_host_plugin->retrieve_show_message('public_key_sent', true); ?> <?php echo esc_html($reconstructed_url); ?><br>
|
||||
<?php
|
||||
if (!empty($key['created'])) {
|
||||
echo esc_html($updraftcentral_host_plugin->retrieve_show_message('created').' '.date_i18n(get_option('date_format').' '.get_option('time_format'), $key['created'])).'.';
|
||||
if (!empty($key['extra_info']['key_size'])) {
|
||||
echo ' '.esc_html(sprintf($updraftcentral_host_plugin->retrieve_show_message('key_size'), $key['extra_info']['key_size'])).'.';
|
||||
}
|
||||
?>
|
||||
<br>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<a href="<?php echo esc_url($this->get_current_clean_url()); ?>" data-key_id="<?php echo esc_attr($i); ?>" class="updraftcentral_key_delete"><?php $updraftcentral_host_plugin->retrieve_show_message('delete', true); ?></a></td></tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php
|
||||
if (!$echo_instead_of_return) return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML markup for the 'create key' section
|
||||
*
|
||||
* @param Boolean $echo_instead_of_return Whether the result should be echoed or returned
|
||||
* @return String|Void - the HTML
|
||||
*/
|
||||
private function create_key_markup($echo_instead_of_return = false) {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
if (!$echo_instead_of_return) ob_start();
|
||||
?>
|
||||
<div class="create_key_container">
|
||||
<h4 class="updraftcentral_wizard_stage1"> <?php $updraftcentral_host_plugin->retrieve_show_message('connect_to_updraftcentral_dashboard', true); ?></h4>
|
||||
<table style="width: 100%; table-layout:fixed;">
|
||||
<thead></thead>
|
||||
<tbody>
|
||||
<tr class="updraftcentral_wizard_stage1">
|
||||
<td>
|
||||
<div class="updraftcentral_wizard_mothership updraftcentral_wizard_option">
|
||||
<label class="button-primary" tabindex="0">
|
||||
<input checked="checked" type="radio" name="updraftcentral_mothership" id="updraftcentral_mothership_updraftpluscom" style="display: none;">
|
||||
TeamUpdraft.com
|
||||
</label><br>
|
||||
<div><?php echo wp_kses_post(sprintf(esc_html($updraftcentral_host_plugin->retrieve_show_message('in_example')), '<a target="_blank" href="https://teamupdraft.com/my-account/?utm_source=udp-plugin&utm_medium=referral&utm_campaign=paac&utm_content=an-account&utm_creative_format=text">'.esc_html($updraftcentral_host_plugin->retrieve_show_message('an_account')).'</a>')); ?></div>
|
||||
|
||||
</div>
|
||||
<div class="updraftcentral_wizard_self_hosted_stage1 updraftcentral_wizard_option">
|
||||
<label class="button-primary" tabindex="0">
|
||||
<input type="radio" name="updraftcentral_mothership" id="updraftcentral_mothership_other" style="display: none;">
|
||||
<?php $updraftcentral_host_plugin->retrieve_show_message('self_hosted_dashboard', true);?>
|
||||
</label><br>
|
||||
<div><?php echo wp_kses_post(sprintf(esc_html($updraftcentral_host_plugin->retrieve_show_message('website_installed')), '<a target="_blank" href="https://wordpress.org/plugins/updraftcentral/">UpdraftCentral</a>')); ?></div>
|
||||
</div>
|
||||
<div class="updraftcentral_wizard_self_hosted_stage2" style="float:left; clear:left;display:none;">
|
||||
<p style="font-size: 13px;"><?php $updraftcentral_host_plugin->retrieve_show_message('enter_url', true); ?></p>
|
||||
<p style="font-size: 13px;" id="updraftcentral_wizard_stage1_error"></p>
|
||||
<input disabled="disabled" id="updraftcentral_keycreate_mothership" type="text" size="40" placeholder="<?php $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_dashboard_url', true); ?>" value="">
|
||||
<button type="button" class="button button-primary" id="updraftcentral_stage2_go"><?php $updraftcentral_host_plugin->retrieve_show_message('next', true); ?></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="updraft_debugrow updraftcentral_wizard_stage2" style="display: none;">
|
||||
<h4 class="updraftcentral_wizard_stage2" style="display: none;"><?php $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_connection_details', true); ?></h4>
|
||||
<td class="updraftcentral_keycreate_description">
|
||||
<?php $updraftcentral_host_plugin->retrieve_show_message('description', true); ?>:
|
||||
<input id="updraftcentral_keycreate_description" type="text" size="20" placeholder="<?php $updraftcentral_host_plugin->retrieve_show_message('enter_description', true); ?>" value="" >
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="updraft_debugrow updraftcentral_wizard_stage2" style="display: none;">
|
||||
<td>
|
||||
<?php $updraftcentral_host_plugin->retrieve_show_message('encryption_key_size', true); ?>
|
||||
<select style="" id="updraftcentral_keycreate_keysize">
|
||||
<option value="512"><?php echo wp_kses_post(sprintf($updraftcentral_host_plugin->retrieve_show_message('bits').' - '.$updraftcentral_host_plugin->retrieve_show_message('easy_to_break'), '512')); ?></option>
|
||||
<option value="1024"><?php echo wp_kses_post(sprintf($updraftcentral_host_plugin->retrieve_show_message('bits').' - '.$updraftcentral_host_plugin->retrieve_show_message('faster'), '1024')); ?></option>
|
||||
<option value="2048" selected="selected"><?php echo wp_kses_post(sprintf($updraftcentral_host_plugin->retrieve_show_message('bytes').' - '.$updraftcentral_host_plugin->retrieve_show_message('recommended'), '2048')); ?></option>
|
||||
<option value="4096"><?php echo wp_kses_post(sprintf($updraftcentral_host_plugin->retrieve_show_message('bits').' - '.$updraftcentral_host_plugin->retrieve_show_message('slower'), '4096')); ?></option>
|
||||
</select>
|
||||
<br>
|
||||
<div id="updraftcentral_keycreate_mothership_firewalled_container">
|
||||
<label>
|
||||
<input id="updraftcentral_keycreate_mothership_firewalled" type="checkbox">
|
||||
<?php $updraftcentral_host_plugin->retrieve_show_message('use_alternative_method', true); ?>
|
||||
<a href="<?php echo esc_url($this->get_current_clean_url()); ?>" id="updraftcentral_keycreate_altmethod_moreinfo_get"><?php $updraftcentral_host_plugin->retrieve_show_message('more_information', true); ?></a>
|
||||
<p id="updraftcentral_keycreate_altmethod_moreinfo" style="display:none; border: 1px dotted; padding: 3px; margin: 2px 10px 2px 24px;">
|
||||
<em><?php $updraftcentral_host_plugin->retrieve_show_message('this_is_useful', true);?></em>
|
||||
</p>
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="updraft_debugrow updraftcentral_wizard_stage2" style="display: none;">
|
||||
<td>
|
||||
<button style="margin-top: 5px;" type="button" class="button button-primary" id="updraftcentral_keycreate_go"><?php $updraftcentral_host_plugin->retrieve_show_message('create', true); ?></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="updraft_debugrow updraftcentral_wizard_stage2" style="display: none;">
|
||||
<td>
|
||||
<a id="updraftcentral_stage1_go"><?php $updraftcentral_host_plugin->retrieve_show_message('back', true); ?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="updraft-copy-modal" title="<?php esc_html_e('Copy to clipboard', 'updraftplus');?>">
|
||||
<p>
|
||||
<?php echo esc_html__('Your web browser prevented the copy operation.', 'updraftplus').' '.'<a href="https://updraftplus.com/faqs/how-do-i-set-clipboard-permissions-for-different-browsers/" target="__blank">'.' '.esc_html__('Follow this link to read about how to set browser permission', 'updraftplus').'</a>'; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if (!$echo_instead_of_return) return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get log event viewer mark-up
|
||||
*
|
||||
* @param Boolean $echo_instead_of_return Whether the result should be echoed or returned
|
||||
* @return String - the HTML
|
||||
*/
|
||||
private function get_log_markup($echo_instead_of_return = false) {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
if (!$echo_instead_of_return) ob_start();
|
||||
?>
|
||||
<div id="updraftcentral_view_log_container" style="margin: 10px 0;">
|
||||
<a href="<?php echo esc_url($this->get_current_clean_url()); ?>" id="updraftcentral_view_log"><?php $updraftcentral_host_plugin->retrieve_show_message('view_log_events', true); ?>...</a><br>
|
||||
<pre id="updraftcentral_view_log_contents" style="min-height: 110px; padding: 0 4px;">
|
||||
</pre>
|
||||
</div>
|
||||
<?php
|
||||
if (!$echo_instead_of_return) return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Echo the debug-tools dashboard HTML. Called by the WP action updraftplus_debugtools_dashboard.
|
||||
*/
|
||||
public function debugtools_dashboard() {
|
||||
|
||||
$this->enqueue_central_scripts();
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
$including_desc = '';
|
||||
if (function_exists('get_current_screen')) {
|
||||
$screen = get_current_screen();
|
||||
$hosts = apply_filters('updraftcentral_host_plugins', array());
|
||||
$includes = $updraftcentral_host_plugin->retrieve_show_message('including_description');
|
||||
|
||||
foreach ($hosts as $plugin) {
|
||||
if (false !== stripos($screen->id, $plugin)) {
|
||||
$key = str_replace('-', '_', strtolower($plugin)).'_desc';
|
||||
if (isset($includes[$key])) {
|
||||
$including_desc = $includes[$key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$updraftcentral_description = preg_replace('/\s+/', ' ', sprintf($updraftcentral_host_plugin->retrieve_show_message('updraftcentral_description'), $including_desc));
|
||||
?>
|
||||
<div class="advanced_tools updraft_central">
|
||||
<h3><?php $updraftcentral_host_plugin->retrieve_show_message('updraftcentral_remote_control', true); ?></h3>
|
||||
<p>
|
||||
<?php echo esc_html($updraftcentral_description); ?> <a target="_blank" href="https://teamupdraft.com/updraftcentral/?utm_source=udp-plugin&utm_medium=referral&utm_campaign=paac&utm_content=read-more-here&utm_creative_format=text"><?php $updraftcentral_host_plugin->retrieve_show_message('read_more', true); ?></a>
|
||||
</p>
|
||||
<div style="min-height: 310px;" id="updraftcentral_keys">
|
||||
<?php $this->create_key_markup(true); ?>
|
||||
<?php $this->get_keys_table(true); ?>
|
||||
<button style="display: none;" type="button" class="button button-primary" id="updraftcentral_wizard_go"><?php $updraftcentral_host_plugin->retrieve_show_message('create_another_key', true); ?></button>
|
||||
<?php $this->get_log_markup(true); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
global $updraftcentral_main;
|
||||
$updraftcentral_main = new UpdraftCentral_Main();
|
||||
Vendored
Executable
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
class Automatic_Upgrader_Skin extends Automatic_Upgrader_Skin_Main {
|
||||
|
||||
public function feedback($string, ...$args) { // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ellipsisFound, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- spread operator is not supported in PHP < 5.5 but WP 5.3 supports PHP 5.6 minimum
|
||||
parent::updraft_feedback($string);
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+126
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
// @codingStandardsIgnoreFile
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
// Extracted from 4.5.2/wordpress/wp-admin/includes/class-wp-upgrader-skins.php; with the bulk_*() methods added since they are not in the base class on all WP versions.
|
||||
// Needed only on WP < 3.7
|
||||
|
||||
/**
|
||||
* Upgrader Skin for Automatic WordPress Upgrades
|
||||
*
|
||||
* Extracted from 4.5.2/wordpress/wp-admin/includes/class-wp-upgrader-skins.php; with the bulk_*() methods added since they are not in the base class on all WP versions.
|
||||
* Needed only on WP < 3.7
|
||||
*
|
||||
* This skin is designed to be used when no output is intended, all output
|
||||
* is captured and stored for the caller to process and log/email/discard.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Upgrader
|
||||
* @since 3.7.0
|
||||
*/
|
||||
class Automatic_Upgrader_Skin_Main extends WP_Upgrader_Skin {
|
||||
|
||||
protected $messages = array();
|
||||
|
||||
/**
|
||||
* Request filesystem credentials
|
||||
*
|
||||
* @param bool $error Check if there is an error: default is false
|
||||
* @param string $context Context for credentials
|
||||
* @param bool $allow_relaxed_file_ownership Check if relaxed file ownership is allowed
|
||||
* @return bool
|
||||
*/
|
||||
public function request_filesystem_credentials($error = false, $context = '', $allow_relaxed_file_ownership = false) {
|
||||
if ($context) {
|
||||
$this->options['context'] = $context;
|
||||
}
|
||||
// TODO: fix up request_filesystem_credentials(), or split it, to allow us to request a no-output version
|
||||
// This will output a credentials form in event of failure, We don't want that, so just hide with a buffer
|
||||
ob_start();
|
||||
$result = parent::request_filesystem_credentials($error, $context, $allow_relaxed_file_ownership);
|
||||
ob_end_clean();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get update message
|
||||
*
|
||||
* @return array reti=urns an array of messages
|
||||
*/
|
||||
public function get_upgrade_messages() {
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Feedback
|
||||
*
|
||||
* @param string|array|WP_Error $data THis is the data to be used for the feedback
|
||||
*/
|
||||
protected function updraft_feedback($data) {
|
||||
if (is_wp_error($data)) {
|
||||
$string = $data->get_error_message();
|
||||
} elseif (is_array($data)) {
|
||||
return;
|
||||
} else {
|
||||
$string = $data;
|
||||
}
|
||||
if (!empty($this->upgrader->strings[$string]))
|
||||
$string = $this->upgrader->strings[$string];
|
||||
|
||||
if (false !== strpos($string, '%')) {
|
||||
$args = func_get_args();
|
||||
$args = array_splice($args, 1);
|
||||
if (!empty($args))
|
||||
$string = vsprintf($string, $args);
|
||||
}
|
||||
|
||||
$string = trim($string);
|
||||
|
||||
// Only allow basic HTML in the messages, as it'll be used in emails/logs rather than direct browser output.
|
||||
$string = wp_kses($string, array(
|
||||
'a' => array(
|
||||
'href' => true
|
||||
),
|
||||
'br' => true,
|
||||
'em' => true,
|
||||
'strong' => true,
|
||||
));
|
||||
|
||||
if (empty($string))
|
||||
return;
|
||||
|
||||
$this->messages[] = $string;
|
||||
}
|
||||
|
||||
public function header() {
|
||||
ob_start();
|
||||
}
|
||||
|
||||
public function footer() {
|
||||
$output = ob_get_clean();
|
||||
if (!empty($output))
|
||||
$this->feedback($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @access public
|
||||
*/
|
||||
public function bulk_header() {}
|
||||
|
||||
public function bulk_footer() {
|
||||
}
|
||||
}
|
||||
|
||||
global $updraftcentral_main;
|
||||
$wp_version = $updraftcentral_main->get_wordpress_version();
|
||||
|
||||
if (version_compare($wp_version, '5.3', '>=')) {
|
||||
if (!class_exists('Automatic_Upgrader_Skin')) require_once(dirname(__FILE__).'/automatic-upgrader-skin-compatibility.php');
|
||||
} else {
|
||||
class Automatic_Upgrader_Skin extends Automatic_Upgrader_Skin_Main {
|
||||
|
||||
public function feedback($string) {
|
||||
parent::updraft_feedback($string);
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+49
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH') || !defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* The extended class of Plugin_Upgrader that is mostly used for overriding some of the parent methods to short-circuit their native behaviour or to manipulate some data, parameters and/or method arguments
|
||||
*/
|
||||
class UpdraftCentral_Plugin_Upgrader extends Plugin_Upgrader {
|
||||
|
||||
/**
|
||||
* Run an upgrade/installation
|
||||
*
|
||||
* @param Array $options {
|
||||
* Array or string of arguments for upgrading/installing a package.
|
||||
*
|
||||
* @type bool $clear_destination Whether to delete any files already in the destination folder. Default false. (since 2.8.0)
|
||||
* }
|
||||
*
|
||||
* @return Array|False|WP_Error The result from self::install_package() on success, otherwise a WP_Error,
|
||||
* or false if unable to connect to the filesystem.
|
||||
*/
|
||||
public function run($options) {
|
||||
$options['clear_destination'] = true; // force overwritting the existing one, in case WP < 5.5.0 is in use where "overwrite_package" parameter doesn't exist
|
||||
return parent::run($options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The extended class of Plugin_Upgrader that is mostly used for overriding some of the parent methods to short-circuit their native behaviour or to manipulate some data, parameters and/or method arguments
|
||||
*/
|
||||
class UpdraftCentral_Theme_Upgrader extends Theme_Upgrader {
|
||||
|
||||
/**
|
||||
* Run an upgrade/installation
|
||||
*
|
||||
* @param Array $options {
|
||||
* Array or string of arguments for upgrading/installing a package.
|
||||
*
|
||||
* @type bool $clear_destination Whether to delete any files already in the destination folder. Default false. (since 2.8.0)
|
||||
* }
|
||||
*
|
||||
* @return Array|False|WP_Error The result from self::install_package() on success, otherwise a WP_Error,
|
||||
* or false if unable to connect to the filesystem.
|
||||
*/
|
||||
public function run($options) {
|
||||
$options['clear_destination'] = true; // force overwritting the existing one, in case WP < 5.5.0 is in use where "overwrite_package" parameter doesn't exist
|
||||
return parent::run($options);
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+366
@@ -0,0 +1,366 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* - A container for all the RPC commands implemented. Commands map exactly onto method names (and hence this class should not implement anything else, beyond the constructor, and private methods)
|
||||
* - Return format is array('response' => (string - a code), 'data' => (mixed));
|
||||
*
|
||||
* RPC commands are not allowed to begin with an underscore. So, any private methods can be prefixed with an underscore.
|
||||
*/
|
||||
abstract class UpdraftCentral_Commands {
|
||||
|
||||
protected $rc;
|
||||
|
||||
protected $ud;
|
||||
|
||||
protected $installed_data;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param string $rc
|
||||
*/
|
||||
public function __construct($rc) {
|
||||
$this->rc = $rc;
|
||||
global $updraftplus;
|
||||
$this->ud = $updraftplus;
|
||||
$this->installed_data = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Include a file or files from wp-admin/includes
|
||||
*/
|
||||
final protected function _admin_include() {
|
||||
$files = func_get_args();
|
||||
foreach ($files as $file) {
|
||||
include_once(ABSPATH.'/wp-admin/includes/'.$file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Include a file or files from wp-includes
|
||||
*/
|
||||
final protected function _frontend_include() {
|
||||
$files = func_get_args();
|
||||
foreach ($files as $file) {
|
||||
include_once(ABSPATH.WPINC.'/'.$file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a response in the expected format
|
||||
*
|
||||
* @param Mixed $data
|
||||
* @param String $code
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
final protected function _response($data = null, $code = 'rpcok') {
|
||||
return array(
|
||||
'response' => $code,
|
||||
'data' => $data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an error in the expected format
|
||||
*
|
||||
* @param String $code
|
||||
* @param Mixed $data
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
final protected function _generic_error_response($code = 'central_unspecified', $data = null) {
|
||||
return $this->_response(
|
||||
array(
|
||||
'code' => $code,
|
||||
'data' => $data
|
||||
),
|
||||
'rpcerror'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a backup and a security credentials is required for the given request
|
||||
*
|
||||
* @param array $dir The directory location to check
|
||||
* @return array
|
||||
*/
|
||||
final protected function _get_backup_credentials_settings($dir) {
|
||||
|
||||
// Do we need to ask the user for filesystem credentials? when installing and/or deleting items in the given directory
|
||||
$filesystem_method = get_filesystem_method(array(), $dir);
|
||||
|
||||
ob_start();
|
||||
$filesystem_credentials_are_stored = request_filesystem_credentials(site_url(), $filesystem_method);
|
||||
ob_end_clean();
|
||||
$request_filesystem_credentials = ('direct' != $filesystem_method && !$filesystem_credentials_are_stored);
|
||||
|
||||
// Do we need to execute a backup process before installing/managing items
|
||||
$automatic_backups = (class_exists('UpdraftPlus_Options') && class_exists('UpdraftPlus_Addon_Autobackup') && UpdraftPlus_Options::get_updraft_option('updraft_autobackup_default')) ? true : false;
|
||||
|
||||
return array(
|
||||
'request_filesystem_credentials' => $request_filesystem_credentials,
|
||||
'automatic_backups' => $automatic_backups
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the information of the currently installed item (e.g. plugin or theme) through filter
|
||||
*
|
||||
* @param bool $response Indicates whether the installation was a success or failure
|
||||
* @param array $args Extra argument for the hook
|
||||
* @param array $data Contains paths used and other relevant information regarding the file
|
||||
* @return array
|
||||
*/
|
||||
final public function get_install_data($response, $args, $data) {
|
||||
|
||||
if ($response) {
|
||||
switch ($args['type']) {
|
||||
case 'plugin':
|
||||
$plugin_data = get_plugins('/'.$data['destination_name']);
|
||||
if (!empty($plugin_data)) {
|
||||
$info = reset($plugin_data);
|
||||
$key = key($plugin_data);
|
||||
|
||||
$info['slug'] = $data['destination_name'].'/'.$key;
|
||||
$this->installed_data = $info;
|
||||
}
|
||||
break;
|
||||
case 'theme':
|
||||
$theme = wp_get_theme($data['destination_name']);
|
||||
if ($theme->exists()) {
|
||||
// Minimalistic info here, if you need to add additional information
|
||||
// you can add them here. For now, the "Name" and "slug" fields will suffice
|
||||
// in the succeeding process.
|
||||
$this->installed_data = array(
|
||||
'Name' => $theme->get('Name'),
|
||||
'slug' => $data['destination_name'],
|
||||
'template' => $theme->get_template()
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs and activates either a plugin or theme through zip file upload
|
||||
*
|
||||
* @param array $params Parameter array containing information pertaining the currently uploaded item
|
||||
* @param string $type Indicates whether this current process is intended for a 'plugin' or a 'theme' item
|
||||
* @return array
|
||||
*/
|
||||
final protected function process_chunk_upload($params, $type) {
|
||||
global $updraftcentral_host_plugin, $updraftcentral_main;
|
||||
|
||||
if (!in_array($type, array('plugin', 'theme'))) {
|
||||
return $this->_generic_error_response('upload_type_not_supported');
|
||||
}
|
||||
|
||||
$permission_error = false;
|
||||
if ('plugin' === $type) {
|
||||
if (!current_user_can('install_plugins') || !current_user_can('activate_plugins')) $permission_error = true;
|
||||
} else {
|
||||
if (!current_user_can('install_themes') || !current_user_can('switch_themes')) $permission_error = true;
|
||||
}
|
||||
|
||||
if ($permission_error) {
|
||||
return $this->_generic_error_response($type.'_insufficient_permission');
|
||||
}
|
||||
|
||||
// Pull any available and writable directory where we can store
|
||||
// our data/file temporarily before running the installation process.
|
||||
$upload_dir = untrailingslashit(get_temp_dir());
|
||||
if (!is_writable($upload_dir)) {
|
||||
$upload_dir = WP_CONTENT_DIR.'/upgrade';
|
||||
|
||||
if (!is_dir($upload_dir)) {
|
||||
$wp_dir = wp_upload_dir();
|
||||
if (!empty($wp_dir['basedir'])) $upload_dir = $wp_dir['basedir'];
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't found any writable directory to temporarily store our file then
|
||||
// we bail and send an error back to the caller.
|
||||
if (!is_dir($upload_dir) || !is_writable($upload_dir)) {
|
||||
return $this->_generic_error_response('upload_dir_not_available');
|
||||
}
|
||||
|
||||
// Preloads the submitted credentials to the global $_POST variable
|
||||
if (!empty($params) && isset($params['filesystem_credentials'])) {
|
||||
parse_str($params['filesystem_credentials'], $filesystem_credentials);
|
||||
if (is_array($filesystem_credentials)) {
|
||||
foreach ($filesystem_credentials as $key => $value) {
|
||||
// Put them into $_POST, which is where request_filesystem_credentials() checks for them.
|
||||
$_POST[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save uploaded file
|
||||
$filename = basename($params['filename']).md5(get_home_url());
|
||||
$is_chunked = false;
|
||||
|
||||
if (isset($params['chunks']) && 1 < (int) $params['chunks']) {
|
||||
$filename .= '.part';
|
||||
$is_chunked = true;
|
||||
}
|
||||
|
||||
if (!$is_chunked || ($is_chunked && isset($params['chunk']) && 0 === (int) $params['chunk'])) {
|
||||
// if it's not a chunk upload or if it's a chunk upload operation and the current chunk variable is zero, then it means a new upload operation has just begun therefore we should remove previous left-over file (if any and due to error during the previous upload of the same file), because it can lead to a corrupt/invalid zip file (we use file_put_contents a few lines below with FILE_APPEND attribute)
|
||||
if (file_exists($upload_dir.'/'.$filename) && !unlink($upload_dir.'/'.$filename)) return $this->_generic_error_response('unable_to_delete_existing_file');
|
||||
}
|
||||
|
||||
if (empty($params['data'])) {
|
||||
return $this->_generic_error_response('data_empty_or_invalid');
|
||||
}
|
||||
|
||||
$result = file_put_contents($upload_dir.'/'.$filename, base64_decode($params['data']), FILE_APPEND | LOCK_EX);
|
||||
|
||||
if (false === $result) {
|
||||
return $this->_generic_error_response('unable_to_write_content');
|
||||
}
|
||||
|
||||
// Set $install_now to true for single upload and for the last chunk of a multi-chunks upload process
|
||||
$install_now = true;
|
||||
|
||||
if ($is_chunked) {
|
||||
if ($params['chunk'] == (int) $params['chunks'] - 1) {
|
||||
// If this is the last chunk of the request, then we're going to restore the
|
||||
// original filename of the file (without the '.part') since our upload is now complete.
|
||||
$orig_filename = basename($filename, '.part');
|
||||
$success = rename($upload_dir.'/'.$filename, $upload_dir.'/'.$orig_filename);
|
||||
|
||||
// If renaming the file was successful then restore the original name and override the $filename variable.
|
||||
// Overriding the $filename variable makes it easy for us to use the same variable for both
|
||||
// non-chunked and chunked zip file for the installation process.
|
||||
if ($success) {
|
||||
$filename = $orig_filename;
|
||||
} else {
|
||||
return $this->_generic_error_response('unable_to_rename_file');
|
||||
}
|
||||
} else {
|
||||
// Bypass installation for now since we're waiting for the last chunk to arrive
|
||||
// to complete the uploading of the zip file.
|
||||
$install_now = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Everything is already good (upload completed), thus, we proceed with the installation
|
||||
if ($install_now) {
|
||||
|
||||
// We have successfully uploaded the zip file in this location with its original filename intact.
|
||||
$zip_filepath = $upload_dir.'/'.$filename;
|
||||
|
||||
// Making sure that the file does actually exists, since we've just run through
|
||||
// a renaming process above.
|
||||
if (file_exists($zip_filepath)) {
|
||||
add_filter('upgrader_post_install', array($this, 'get_install_data'), 10, 3);
|
||||
|
||||
// WP < 3.7
|
||||
if (!class_exists('Automatic_Upgrader_Skin')) include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/classes/class-automatic-upgrader-skin.php');
|
||||
require_once(UPDRAFTCENTRAL_CLIENT_DIR.'/classes/class-updraftcentral-wp-upgrader.php');
|
||||
|
||||
$skin = new Automatic_Upgrader_Skin();
|
||||
$upgrader = ('plugin' === $type) ? new UpdraftCentral_Plugin_Upgrader($skin) : new UpdraftCentral_Theme_Upgrader($skin);
|
||||
|
||||
$install_result = $upgrader->install($zip_filepath);
|
||||
remove_filter('upgrader_post_install', array($this, 'get_install_data'), 10, 3);
|
||||
|
||||
// Remove zip file on success and on error (cleanup)
|
||||
if ($install_result || is_null($install_result) || is_wp_error($install_result)) {
|
||||
@unlink($zip_filepath);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise if the file doesn't exist.
|
||||
}
|
||||
|
||||
if (false === $install_result || is_wp_error($install_result)) {
|
||||
$message = $updraftcentral_host_plugin->retrieve_show_message('unable_to_connect');
|
||||
if (is_wp_error($install_result)) $message = $install_result->get_error_message();
|
||||
|
||||
return $this->_generic_error_response($type.'_install_failed', array('message' => $message));
|
||||
} else {
|
||||
// Pull installed data
|
||||
$data = $this->installed_data;
|
||||
|
||||
// For WP 3.4 the intended filter hook isn't working or not available
|
||||
// so we're going to pull the data manually.
|
||||
if ($install_result && empty($data)) {
|
||||
$result = $this->get_install_data($install_result, array('type' => $type), $skin->result);
|
||||
if ($result) {
|
||||
// Getting the installed data one more time after manually calling
|
||||
// the "get_install_data" function.
|
||||
$data = $this->installed_data;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
// Activate item if set
|
||||
$is_active = ('plugin' === $type) ? is_plugin_active($data['slug']) : ((wp_get_theme()->get('Name') === $data['Name']) ? true : false);
|
||||
|
||||
if ((bool) $params['activate'] && !$is_active) {
|
||||
if ('plugin' === $type) {
|
||||
if (is_multisite()) {
|
||||
$activate = activate_plugin($data['slug'], '', true);
|
||||
} else {
|
||||
$activate = activate_plugin($data['slug']);
|
||||
}
|
||||
} else {
|
||||
// In order to make it compatible with older versions of switch_theme which takes two
|
||||
// arguments we're going to pass two arguments instead of one. Latest versions have backward
|
||||
// compatibility so it's safe to do it this way.
|
||||
switch_theme($data['template'], $data['slug']);
|
||||
$activate = (wp_get_theme()->get_stylesheet() === $data['slug']) ? true : false;
|
||||
}
|
||||
|
||||
if (false === $activate || is_wp_error($activate)) {
|
||||
$wp_version = $updraftcentral_main->get_wordpress_version();
|
||||
|
||||
$message = is_wp_error($activate) ? array('message' => $activate->get_error_message()) : array('message' => sprintf($updraftcentral_host_plugin->retrieve_show_message('unable_to_activate'), $type, $type, $wp_version));
|
||||
return $this->_generic_error_response('unable_to_activate_'.$type, $message);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response(
|
||||
array(
|
||||
'installed' => true,
|
||||
'installed_data' => $data,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (is_wp_error($skin->result)) {
|
||||
$code = $skin->result->get_error_code();
|
||||
$message = $skin->result->get_error_message();
|
||||
|
||||
$error_data = $skin->result->get_error_data($code);
|
||||
if (!empty($error_data)) {
|
||||
if (is_array($error_data)) $error_data = json_encode($error_data);
|
||||
|
||||
$message .= ' '.$error_data;
|
||||
}
|
||||
|
||||
return $this->_generic_error_response($code, $message);
|
||||
} else {
|
||||
return $this->_response(
|
||||
array(
|
||||
'installed' => false,
|
||||
'message' => sprintf($updraftcentral_host_plugin->retrieve_show_message('unable_to_install'), $type, $type, $type, $type, 'wp-content/'.$type.'s'),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Returning response to a chunk requests while still processing and
|
||||
// completing the file upload process. If we don't return a positive response
|
||||
// for every chunk requests then the caller will assumed an error has occurred
|
||||
// and will eventually stop the upload process.
|
||||
return $this->_response(array('in_progress' => true));
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+57
@@ -0,0 +1,57 @@
|
||||
.updraftcentral_wizard_option {
|
||||
width: 45%;
|
||||
float: left;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.updraftcentral_wizard_option label {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
#updraftcentral_keys_table {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.create_key_container {
|
||||
border: 1px solid;
|
||||
border-radius: 4px;
|
||||
padding: 0 0 6px 6px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.updraftcentral-subheading {
|
||||
font-size: 14px;
|
||||
margin-top: -10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.updraftcentral-data-consent {
|
||||
font-size: 13px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#updraftcentral_keys_table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#updraftcentral_stage1_go {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.updraftcentral_wizard_option > div {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#updraftcentral_keys_table td {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
#updraftcentral_keys_table .updraftcentral_key_delete {
|
||||
display: inline-block;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
#updraftcentral_keys_table .updraft_debugrow td {
|
||||
min-width: auto !important;
|
||||
}
|
||||
Vendored
Executable
+81
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_SET_TIME_LIMIT')) define('UPDRAFTCENTRAL_SET_TIME_LIMIT', 900);
|
||||
|
||||
// We bypass the class declaration if the class already existed. This usually happens if two or more
|
||||
// plugins integrated the same `UpdraftCentral` client folder.
|
||||
if (!class_exists('UpdraftCentral_Factory')) :
|
||||
|
||||
/**
|
||||
* Returns an instance of the host plugin class where the UpdraftCentral "central" folder is being
|
||||
* integrated.
|
||||
*/
|
||||
class UpdraftCentral_Factory {
|
||||
|
||||
/**
|
||||
* Creates a host plugin instance
|
||||
*
|
||||
* @return object|null
|
||||
*/
|
||||
public static function create_host() {
|
||||
|
||||
// All other plugins that wish to integrate the "central" libraries into their
|
||||
// codebase must use this filter (see WP-Optimize plugin as an example).
|
||||
$hosts = apply_filters('updraftcentral_host_plugins', array());
|
||||
|
||||
// If $hosts is empty then we return null
|
||||
if (empty($hosts)) return null;
|
||||
|
||||
// N.B. If multiple host plugins (e.g. updraftplus, wp-optimize, etc.) are currently
|
||||
// active then we only select one to handle all incoming UpdraftCentral requests for
|
||||
// this website in order to avoid conflicts and confusion especially when tracing or
|
||||
// debugging issues.
|
||||
//
|
||||
// You will know which plugin is currently serving and handling the request by checking
|
||||
// the "get_plugin_name" method of the global variable "$updraftcentral_host_plugin"
|
||||
// (e.g. $updraftcentral_host_plugin->get_plugin_name())
|
||||
//
|
||||
// N.B. You can add additional host plugins here. Just make sure that you will create
|
||||
// a host class for that particular plugin (see central/wp-optimize.php as an example).
|
||||
$mapped_classes = array(
|
||||
'updraftplus' => 'UpdraftPlus_Host',
|
||||
'wp-optimize' => 'WP_Optimize_Host',
|
||||
);
|
||||
|
||||
$path = $host_class = '';
|
||||
foreach ($hosts as $plugin) {
|
||||
// Make sure that we have a registered host class with a valid file that exist
|
||||
$host_file = dirname(__FILE__).'/'.$plugin.'.php';
|
||||
if (isset($mapped_classes[$plugin]) && file_exists($host_file)) {
|
||||
$path = $host_file;
|
||||
$host_class = $mapped_classes[$plugin];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The host file was not found under this plugin thus, we let the other plugins
|
||||
// create or build the host plugin (global) variable instead.
|
||||
if (empty($path)) return null;
|
||||
|
||||
if (!class_exists($host_class)) include_once($path);
|
||||
|
||||
// Re-check host class once again just to make sure that we have the desired
|
||||
// class loaded before calling its instance method
|
||||
if (class_exists($host_class)) {
|
||||
return call_user_func(array($host_class, 'instance'));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
global $updraftcentral_host_plugin;
|
||||
$updraftcentral_host_plugin = UpdraftCentral_Factory::create_host();
|
||||
|
||||
if ($updraftcentral_host_plugin) {
|
||||
$updraftcentral_host_plugin->load_updraftcentral();
|
||||
}
|
||||
Vendored
Executable
+311
@@ -0,0 +1,311 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('No direct access.');
|
||||
|
||||
/**
|
||||
* The template definition for UpdraftCentral host
|
||||
*/
|
||||
abstract class UpdraftCentral_Host {
|
||||
|
||||
public $plugin_name;
|
||||
|
||||
public $translations;
|
||||
|
||||
public $error_reporting_stop_when_logged = false;
|
||||
|
||||
public $no_deprecation_warnings = false;
|
||||
|
||||
private $jobdata;
|
||||
|
||||
abstract protected function load_updraftcentral();
|
||||
abstract protected function is_host_dir_set();
|
||||
abstract protected function get_host_dir();
|
||||
abstract protected function get_version();
|
||||
abstract public function log($line, $level = 'notice', $uniq_id = false);
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action('wp_ajax_updraft_central_ajax', array($this, 'updraft_central_ajax_handler'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin name associated with this host class
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_plugin_name() {
|
||||
return $this->plugin_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves or shows a message from the translations collection based on its identifier key
|
||||
*
|
||||
* @param string $key The ID of the the message
|
||||
* @param bool $echo Indicate whether the message is to be shown directly (echoed) or just for retrieval
|
||||
*
|
||||
* @return string/void
|
||||
*/
|
||||
public function retrieve_show_message($key, $echo = false) {
|
||||
if (empty($key) || !isset($this->translations[$key])) return '';
|
||||
|
||||
if ($echo) {
|
||||
echo esc_html($this->translations[$key]);
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->translations[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a section to a designated area primarily used for generating UpdraftCentral keys
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function debugtools_dashboard() {
|
||||
if (!current_user_can('manage_options')) return;
|
||||
|
||||
global $updraftcentral_main;
|
||||
|
||||
if (!class_exists('UpdraftCentral_Main')) {
|
||||
if (defined('UPDRAFTCENTRAL_CLIENT_DIR') && file_exists(UPDRAFTCENTRAL_CLIENT_DIR.'/bootstrap.php')) {
|
||||
include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/bootstrap.php');
|
||||
$updraftcentral_main = new UpdraftCentral_Main();
|
||||
}
|
||||
}
|
||||
|
||||
if ($updraftcentral_main) {
|
||||
$updraftcentral_main->debugtools_dashboard();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current user can perform key control AJAX actions
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function current_user_can_ajax() {
|
||||
return current_user_can('manage_options');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles ajax requests coming from the section or area generated by the
|
||||
* "debugtools_dashboard" method (below)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updraft_central_ajax_handler() {
|
||||
global $updraftcentral_main;
|
||||
|
||||
$nonce = empty($_REQUEST['nonce']) ? '' : $_REQUEST['nonce'];
|
||||
if (empty($nonce) || !wp_verify_nonce($nonce, 'updraftcentral-request-nonce') || !$this->current_user_can_ajax() || empty($_REQUEST['subaction'])) die('Security check');
|
||||
|
||||
if (is_a($updraftcentral_main, 'UpdraftCentral_Main')) {
|
||||
|
||||
$subaction = $_REQUEST['subaction'];
|
||||
if ($this->is_action_whitelisted($subaction) && is_callable(array($updraftcentral_main, $subaction))) {
|
||||
|
||||
// Undo WP's slashing of POST data
|
||||
$data = $this->wp_unslash($_POST);
|
||||
|
||||
// TODO: Once all commands come through here and through updraft_send_command(), the data should always come from this attribute (once updraft_send_command() is modified appropriately).
|
||||
if (isset($data['action_data'])) $data = $data['action_data'];
|
||||
try {
|
||||
|
||||
$results = call_user_func(array($updraftcentral_main, $subaction), $data);
|
||||
} catch (Exception $e) {
|
||||
$log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during '.$subaction.' subaction. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
|
||||
error_log($log_message);
|
||||
echo json_encode(array(
|
||||
'fatal_error' => true,
|
||||
'fatal_error_message' => $log_message
|
||||
));
|
||||
die;
|
||||
// @codingStandardsIgnoreLine
|
||||
} catch (Error $e) {
|
||||
$log_message = 'PHP Fatal error ('.get_class($e).') has occurred during '.$subaction.' subaction. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
|
||||
error_log($log_message);
|
||||
echo json_encode(array(
|
||||
'fatal_error' => true,
|
||||
'fatal_error_message' => $log_message
|
||||
));
|
||||
die;
|
||||
}
|
||||
if (is_wp_error($results)) {
|
||||
$results = array(
|
||||
'result' => false,
|
||||
'error_code' => $results->get_error_code(),
|
||||
'error_message' => $results->get_error_message(),
|
||||
'error_data' => $results->get_error_data(),
|
||||
);
|
||||
}
|
||||
|
||||
if (is_string($results)) {
|
||||
// A handful of legacy methods, and some which are directly the source for iframes, for which JSON is not appropriate.
|
||||
echo $results; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- We don't escape here to avoid double escaping and keep the HTML code needed by the receiver of this request.
|
||||
} else {
|
||||
echo json_encode($results);
|
||||
}
|
||||
die;
|
||||
}
|
||||
}
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies whether the submitted action is valid and allowed for execution over AJAX
|
||||
*
|
||||
* @param string $action The action to execute
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_action_whitelisted($action) {
|
||||
$allowed_actions = array('delete_key', 'get_log', 'create_key');
|
||||
return in_array($action, $allowed_actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the filter used by UpdraftCentral to log errors or certain events
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_logline_filter() {
|
||||
return 'updraftcentral_logline';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an RPC object, and sets some defaults on it that we always want
|
||||
*
|
||||
* @param string $indicator_name indicator name
|
||||
* @return array
|
||||
*/
|
||||
public function get_udrpc($indicator_name = 'migrator.updraftplus.com') {
|
||||
global $updraftplus;
|
||||
$updraftplus->ensure_phpseclib();
|
||||
if (!class_exists('UpdraftPlus_Remote_Communications_V2')) include_once($this->get_host_dir().'/vendor/team-updraft/common-libs/src/updraft-rpc/class-udrpc2.php');
|
||||
$ud_rpc = new UpdraftPlus_Remote_Communications_V2($indicator_name);
|
||||
$ud_rpc->set_can_generate(true);
|
||||
return $ud_rpc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Noop method.
|
||||
* Depending on the host plugin this method may or may not be used.
|
||||
*
|
||||
* N.B. The UpdraftPlus plugin is using and overriding this method in its host file.
|
||||
*
|
||||
* @param boolean $register Indicate whether to add or remote filter hooks
|
||||
* @ignore
|
||||
*/
|
||||
// @codingStandardsIgnoreLine
|
||||
public function register_wp_http_option_hooks($register = true) {}
|
||||
|
||||
/**
|
||||
* Remove slashes from a string or array of strings.
|
||||
*
|
||||
* The function wp_unslash() is WP 3.6+, so therefore we have a compatibility method here
|
||||
*
|
||||
* @param String|Array $value String or array of strings to unslash.
|
||||
* @return String|Array Unslashed $value
|
||||
*/
|
||||
public function wp_unslash($value) {
|
||||
return function_exists('wp_unslash') ? wp_unslash($value) : stripslashes_deep($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a log line based from the PHP error information
|
||||
*
|
||||
* @param Integer $errno Error number
|
||||
* @param String $errstr Error string
|
||||
* @param String $errfile Error file
|
||||
* @param String $errline Line number where the error occurred
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function php_error_to_logline($errno, $errstr, $errfile, $errline) {
|
||||
switch ($errno) {
|
||||
case 1:
|
||||
$e_type = 'E_ERROR';
|
||||
break;
|
||||
case 2:
|
||||
$e_type = 'E_WARNING';
|
||||
break;
|
||||
case 4:
|
||||
$e_type = 'E_PARSE';
|
||||
break;
|
||||
case 8:
|
||||
$e_type = 'E_NOTICE';
|
||||
break;
|
||||
case 16:
|
||||
$e_type = 'E_CORE_ERROR';
|
||||
break;
|
||||
case 32:
|
||||
$e_type = 'E_CORE_WARNING';
|
||||
break;
|
||||
case 64:
|
||||
$e_type = 'E_COMPILE_ERROR';
|
||||
break;
|
||||
case 128:
|
||||
$e_type = 'E_COMPILE_WARNING';
|
||||
break;
|
||||
case 256:
|
||||
$e_type = 'E_USER_ERROR';
|
||||
break;
|
||||
case 512:
|
||||
$e_type = 'E_USER_WARNING';
|
||||
break;
|
||||
case 1024:
|
||||
$e_type = 'E_USER_NOTICE';
|
||||
break;
|
||||
case 2048:
|
||||
$e_type = 'E_STRICT';
|
||||
break;
|
||||
case 4096:
|
||||
$e_type = 'E_RECOVERABLE_ERROR';
|
||||
break;
|
||||
case 8192:
|
||||
$e_type = 'E_DEPRECATED';
|
||||
break;
|
||||
case 16384:
|
||||
$e_type = 'E_USER_DEPRECATED';
|
||||
break;
|
||||
case 30719:
|
||||
$e_type = 'E_ALL';
|
||||
break;
|
||||
default:
|
||||
$e_type = "E_UNKNOWN ($errno)";
|
||||
break;
|
||||
}
|
||||
|
||||
if (false !== stripos($errstr, 'table which is not valid in this version of Gravity Forms')) return false;
|
||||
|
||||
if (!is_string($errstr)) $errstr = serialize($errstr);
|
||||
|
||||
if (0 === strpos($errfile, ABSPATH)) $errfile = substr($errfile, strlen(ABSPATH));
|
||||
|
||||
if ('E_DEPRECATED' == $e_type && !empty($this->no_deprecation_warnings)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return "PHP event: code $e_type: $errstr (line $errline, $errfile)";
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP error handler
|
||||
*
|
||||
* @param Integer $errno Error number
|
||||
* @param String $errstr Error string
|
||||
* @param String $errfile Error file
|
||||
* @param String $errline Line number where the error occurred
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function php_error($errno, $errstr, $errfile, $errline) {
|
||||
if (0 == error_reporting()) return true;
|
||||
$logline = $this->php_error_to_logline($errno, $errstr, $errfile, $errline);
|
||||
if (false !== $logline) $this->log($logline, 'notice', 'php_event');
|
||||
// Pass it up the chain
|
||||
return $this->error_reporting_stop_when_logged;
|
||||
}
|
||||
}
|
||||
Vendored
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
Vendored
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
Vendored
Executable
+436
@@ -0,0 +1,436 @@
|
||||
/**
|
||||
* Send an action over AJAX. A wrapper around jQuery.ajax. In future, all consumers can be reviewed to simplify some of the options, where there is historical cruft.
|
||||
* N.B. updraft_iframe_modal() below uses the AJAX URL for the iframe's src attribute
|
||||
*
|
||||
* @param {string} action - the action to send
|
||||
* @param {*} data - data to send
|
||||
* @param {Function} callback - will be called with the results
|
||||
* @param {object} options -further options. Relevant properties include:
|
||||
* - [json_parse=true] - whether to JSON parse the results
|
||||
* - [alert_on_error=true] - whether to show an alert box if there was a problem (otherwise, suppress it)
|
||||
* - [action='updraft_ajax'] - what to send as the action parameter on the AJAX request (N.B. action parameter to this function goes as the 'subaction' parameter on the AJAX request)
|
||||
* - [nonce=updraft_credentialtest_nonce] - the nonce value to send.
|
||||
* - [nonce_key='nonce'] - the key value for the nonce field
|
||||
* - [timeout=null] - set a timeout after this number of seconds (or if null, none is set)
|
||||
* - [async=true] - control whether the request is asynchronous (almost always wanted) or blocking (would need to have a specific reason)
|
||||
* - [type='POST'] - GET or POST
|
||||
*/
|
||||
function updraftcentral_send_command(action, data, callback, options) {
|
||||
|
||||
default_options = {
|
||||
json_parse: true,
|
||||
alert_on_error: true,
|
||||
action: 'updraft_central_ajax',
|
||||
nonce_key: 'nonce',
|
||||
timeout: null,
|
||||
async: true,
|
||||
type: 'POST'
|
||||
}
|
||||
|
||||
if ('undefined' !== typeof uclion.updraftcentral_request_nonce && uclion.updraftcentral_request_nonce) {
|
||||
default_options.nonce = uclion.updraftcentral_request_nonce;
|
||||
}
|
||||
|
||||
if ('undefined' === typeof options) options = {};
|
||||
|
||||
for (var opt in default_options) {
|
||||
if (!options.hasOwnProperty(opt)) { options[opt] = default_options[opt]; }
|
||||
}
|
||||
|
||||
var ajax_data = {
|
||||
action: options.action,
|
||||
subaction: action,
|
||||
};
|
||||
|
||||
ajax_data[options.nonce_key] = options.nonce;
|
||||
ajax_data.action_data = data;
|
||||
|
||||
var ajax_opts = {
|
||||
type: options.type,
|
||||
url: ajaxurl,
|
||||
data: ajax_data,
|
||||
success: function(response, status) {
|
||||
if (options.json_parse) {
|
||||
try {
|
||||
var resp = central_parse_json(response);
|
||||
} catch (e) {
|
||||
if ('function' == typeof options.error_callback) {
|
||||
return options.error_callback(response, e, 502, resp);
|
||||
} else {
|
||||
console.log(e);
|
||||
console.log(response);
|
||||
if (options.alert_on_error) { alert(uclion.unexpectedresponse+' '+response); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (resp.hasOwnProperty('fatal_error')) {
|
||||
if ('function' == typeof options.error_callback) {
|
||||
// 500 is internal server error code
|
||||
return options.error_callback(response, status, 500, resp);
|
||||
} else {
|
||||
console.error(resp.fatal_error_message);
|
||||
if (options.alert_on_error) { alert(resp.fatal_error_message); }
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ('function' == typeof callback) callback(resp, status, response);
|
||||
} else {
|
||||
if ('function' == typeof callback) callback(response, status);
|
||||
}
|
||||
},
|
||||
error: function(response, status, error_code) {
|
||||
if ('function' == typeof options.error_callback) {
|
||||
options.error_callback(response, status, error_code);
|
||||
} else {
|
||||
console.log("updraftcentral_send_command: error: "+status+" ("+error_code+")");
|
||||
console.log(response);
|
||||
}
|
||||
},
|
||||
dataType: 'text',
|
||||
async: options.async
|
||||
};
|
||||
|
||||
if (null != options.timeout) { ajax_opts.timeout = options.timeout; }
|
||||
|
||||
jQuery.ajax(ajax_opts);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse JSON string, including automatically detecting unwanted extra input and skipping it
|
||||
*
|
||||
* @param {string} json_mix_str - JSON string which need to parse and convert to object
|
||||
* @param {boolean} analyse - if true, then the return format will contain information on the parsing, and parsing will skip attempting to JSON.parse() the entire string (will begin with trying to locate the actual JSON)
|
||||
*
|
||||
* @throws SyntaxError|String (including passing on what JSON.parse may throw) if a parsing error occurs.
|
||||
*
|
||||
* @returns Mixed parsed JSON object. Will only return if parsing is successful (otherwise, will throw). If analyse is true, then will rather return an object with properties (mixed)parsed, (integer)json_start_pos and (integer)json_end_pos
|
||||
*/
|
||||
function central_parse_json(json_mix_str, analyse) {
|
||||
|
||||
analyse = ('undefined' === typeof analyse) ? false : true;
|
||||
|
||||
// Just try it - i.e. the 'default' case where things work (which can include extra whitespace/line-feeds, and simple strings, etc.).
|
||||
if (!analyse) {
|
||||
try {
|
||||
var result = JSON.parse(json_mix_str);
|
||||
return result;
|
||||
} catch (e) {
|
||||
console.log(uclion.plugin_name+': Exception when trying to parse JSON (1) - will attempt to fix/re-parse based upon first/last curly brackets');
|
||||
console.log(json_mix_str);
|
||||
}
|
||||
}
|
||||
|
||||
var json_start_pos = json_mix_str.indexOf('{');
|
||||
var json_last_pos = json_mix_str.lastIndexOf('}');
|
||||
|
||||
// Case where some php notice may be added after or before json string
|
||||
if (json_start_pos > -1 && json_last_pos > -1) {
|
||||
var json_str = json_mix_str.slice(json_start_pos, json_last_pos + 1);
|
||||
try {
|
||||
var parsed = JSON.parse(json_str);
|
||||
if (!analyse) { console.log(uclion.plugin_name+': JSON re-parse successful'); }
|
||||
return analyse ? { parsed: parsed, json_start_pos: json_start_pos, json_last_pos: json_last_pos + 1 } : parsed;
|
||||
} catch (e) {
|
||||
console.log(uclion.plugin_name+': Exception when trying to parse JSON (2) - will attempt to fix/re-parse based upon bracket counting');
|
||||
|
||||
var cursor = json_start_pos;
|
||||
var open_count = 0;
|
||||
var last_character = '';
|
||||
var inside_string = false;
|
||||
|
||||
// Don't mistake this for a real JSON parser. Its aim is to improve the odds in real-world cases seen, not to arrive at universal perfection.
|
||||
while ((open_count > 0 || cursor == json_start_pos) && cursor <= json_last_pos) {
|
||||
|
||||
var current_character = json_mix_str.charAt(cursor);
|
||||
|
||||
if (!inside_string && '{' == current_character) {
|
||||
open_count++;
|
||||
} else if (!inside_string && '}' == current_character) {
|
||||
open_count--;
|
||||
} else if ('"' == current_character && '\\' != last_character) {
|
||||
inside_string = inside_string ? false : true;
|
||||
}
|
||||
|
||||
last_character = current_character;
|
||||
cursor++;
|
||||
}
|
||||
console.log("Started at cursor="+json_start_pos+", ended at cursor="+cursor+" with result following:");
|
||||
console.log(json_mix_str.substring(json_start_pos, cursor));
|
||||
|
||||
try {
|
||||
var parsed = JSON.parse(json_mix_str.substring(json_start_pos, cursor));
|
||||
console.log(uclion.plugin_name+': JSON re-parse successful');
|
||||
return analyse ? { parsed: parsed, json_start_pos: json_start_pos, json_last_pos: cursor } : parsed;
|
||||
} catch (e) {
|
||||
// Throw it again, so that our function works just like JSON.parse() in its behaviour.
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw uclion.plugin_name+": could not parse the JSON";
|
||||
|
||||
}
|
||||
|
||||
jQuery(function($) {
|
||||
$('#updraftcentral_keys').on('click', 'a.updraftcentral_keys_show', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).remove();
|
||||
$('#updraftcentral_keys_table').slideDown();
|
||||
});
|
||||
|
||||
$('#updraftcentral_keycreate_altmethod_moreinfo_get').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).remove();
|
||||
$('#updraftcentral_keycreate_altmethod_moreinfo').slideDown();
|
||||
});
|
||||
|
||||
function updraftcentral_keys_setupform(on_page_load) {
|
||||
var is_other = jQuery('#updraftcentral_mothership_other').is(':checked') ? true : false;
|
||||
if (is_other) {
|
||||
jQuery('#updraftcentral_keycreate_mothership').prop('disabled', false);
|
||||
if (on_page_load) {
|
||||
jQuery('#updraftcentral_keycreate_mothership_firewalled_container').show();
|
||||
} else {
|
||||
jQuery('.updraftcentral_wizard_self_hosted_stage2').show();
|
||||
jQuery('#updraftcentral_keycreate_mothership_firewalled_container').slideDown();
|
||||
jQuery('#updraftcentral_keycreate_mothership').trigger('focus');
|
||||
}
|
||||
} else {
|
||||
jQuery('#updraftcentral_keycreate_mothership').prop('disabled', true);
|
||||
if (!on_page_load) {
|
||||
jQuery('.updraftcentral_wizard_self_hosted_stage2').hide();
|
||||
updraftcentral_stage2_go();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updraftcentral_stage2_go() {
|
||||
// Reset the error message before we continue
|
||||
jQuery('#updraftcentral_wizard_stage1_error').text('');
|
||||
|
||||
var host = '';
|
||||
|
||||
if (jQuery('#updraftcentral_mothership_updraftpluscom').is(':checked')) {
|
||||
jQuery('.updraftcentral_keycreate_description').hide();
|
||||
host = 'updraftplus.com';
|
||||
} else if (jQuery('#updraftcentral_mothership_other').is(':checked')) {
|
||||
jQuery('.updraftcentral_keycreate_description').show();
|
||||
var mothership = jQuery('#updraftcentral_keycreate_mothership').val();
|
||||
if ('' == mothership) {
|
||||
jQuery('#updraftcentral_wizard_stage1_error').text(uclion.updraftcentral_wizard_empty_url);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var url = new URL(mothership);
|
||||
host = url.hostname;
|
||||
} catch (e) {
|
||||
// Try and grab the host name a different way if it failed because of no URL object (e.g. Firefox version 25 and below).
|
||||
if ('undefined' === typeof URL) {
|
||||
host = jQuery('<a>').prop('href', mothership).prop('hostname');
|
||||
}
|
||||
if (!host || 'undefined' !== typeof URL) {
|
||||
jQuery('#updraftcentral_wizard_stage1_error').text(uclion.updraftcentral_wizard_invalid_url);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jQuery('#updraftcentral_keycreate_description').val(host);
|
||||
|
||||
jQuery('.updraftcentral_wizard_stage1').hide();
|
||||
jQuery('.updraftcentral_wizard_stage2').show();
|
||||
}
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', 'input[type="radio"]', function() {
|
||||
updraftcentral_keys_setupform(false);
|
||||
});
|
||||
// Initial setup (for browsers, e.g. Firefox, that remember form selection state but not DOM state, which can leave an inconsistent state)
|
||||
updraftcentral_keys_setupform(true);
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', '#updraftcentral_view_log', function(e) {
|
||||
e.preventDefault();
|
||||
jQuery('#updraftcentral_view_log_container').block({ message: '<div style="margin: 8px; font-size:150%;"><img src="'+uclion.central_url+'/images/udlogo-rotating.gif" height="80" width="80" style="padding-bottom:10px;"><br>'+uclion.fetching+'</div>'});
|
||||
try {
|
||||
updraftcentral_send_command('get_log', null, function(response) {
|
||||
jQuery('#updraftcentral_view_log_container').unblock();
|
||||
if (response.hasOwnProperty('log_contents')) {
|
||||
jQuery('#updraftcentral_view_log_contents').html('<div style="border:1px solid;padding: 2px;max-height: 400px; overflow-y:scroll;">'+response.log_contents+'</div>');
|
||||
} else {
|
||||
console.log(response);
|
||||
}
|
||||
}, { error_callback: function(response, status, error_code, resp) {
|
||||
jQuery('#updraftcentral_view_log_container').unblock();
|
||||
if (typeof resp !== 'undefined' && resp.hasOwnProperty('fatal_error')) {
|
||||
console.error(resp.fatal_error_message);
|
||||
alert(resp.fatal_error_message);
|
||||
} else {
|
||||
var error_message = "updraftcentral_send_command: error: "+status+" ("+error_code+")";
|
||||
console.log(error_message);
|
||||
alert(error_message);
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
jQuery('#updraft_central_key').html();
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
|
||||
// UpdraftCentral
|
||||
jQuery('#updraftcentral_keys').on('click', '#updraftcentral_wizard_go', function(e) {
|
||||
jQuery('#updraftcentral_wizard_go').hide();
|
||||
jQuery('.updraftcentral_wizard_success').remove();
|
||||
jQuery('.create_key_container').show();
|
||||
});
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', '#updraftcentral_stage1_go', function(e) {
|
||||
e.preventDefault();
|
||||
jQuery('.updraftcentral_wizard_stage2').hide();
|
||||
jQuery('.updraftcentral_wizard_stage1').show();
|
||||
});
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', '#updraftcentral_stage2_go', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
updraftcentral_stage2_go();
|
||||
});
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', '#updraftcentral_keycreate_go', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var is_other = jQuery('#updraftcentral_mothership_other').is(':checked') ? true : false;
|
||||
|
||||
var key_description = jQuery('#updraftcentral_keycreate_description').val();
|
||||
var key_size = jQuery('#updraftcentral_keycreate_keysize').val();
|
||||
|
||||
var where_send = '__updraftpluscom';
|
||||
|
||||
data = {
|
||||
key_description: key_description,
|
||||
key_size: key_size,
|
||||
};
|
||||
|
||||
if (is_other) {
|
||||
where_send = jQuery('#updraftcentral_keycreate_mothership').val();
|
||||
if (where_send.substring(0, 4) != 'http') {
|
||||
alert(uclion.enter_mothership_url);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
data.mothership_firewalled = jQuery('#updraftcentral_keycreate_mothership_firewalled').is(':checked') ? 1 : 0;
|
||||
data.where_send = where_send;
|
||||
|
||||
jQuery('.create_key_container').hide();
|
||||
jQuery('.updraftcentral_wizard_stage1').show();
|
||||
jQuery('.updraftcentral_wizard_stage2').hide();
|
||||
|
||||
jQuery('#updraftcentral_keys').block({ message: '<div style="margin: 8px; font-size:150%;"><img src="'+uclion.central_url+'/images/udlogo-rotating.gif" height="80" width="80" style="padding-bottom:10px;"><br>'+uclion.creating_please_allow+'</div>'});
|
||||
|
||||
try {
|
||||
updraftcentral_send_command('create_key', data, function(resp) {
|
||||
jQuery('#updraftcentral_keys').unblock();
|
||||
try {
|
||||
if (resp.hasOwnProperty('error')) {
|
||||
alert(resp.error);
|
||||
console.log(resp);
|
||||
return;
|
||||
}
|
||||
alert(resp.r);
|
||||
|
||||
if (resp.hasOwnProperty('bundle') && resp.hasOwnProperty('keys_guide')) {
|
||||
jQuery('#updraftcentral_keys_content').html(resp.keys_guide);
|
||||
jQuery('#updraftcentral_keys_content').append('<div class="updraftcentral_wizard_success">'+resp.r+'<br><textarea id="updraftcentral-key" onclick="this.select();" style="width:620px; height:165px; word-wrap:break-word; border: 1px solid #aaa; border-radius: 3px; padding:4px;">'+resp.bundle+'</textarea><button id="updraftplus-copy" class="button button-secondary" style="display: block;">'+uclion.copy_to_clipboard+'</button></div>');
|
||||
} else {
|
||||
console.log(resp);
|
||||
}
|
||||
|
||||
if (resp.hasOwnProperty('keys_table')) {
|
||||
jQuery('#updraftcentral_keys_content').append(resp.keys_table);
|
||||
}
|
||||
|
||||
jQuery('#updraftcentral_wizard_go').show();
|
||||
|
||||
} catch (err) {
|
||||
alert(uclion.unexpectedresponse+' '+response);
|
||||
console.log(err);
|
||||
}
|
||||
}, { error_callback: function(response, status, error_code, resp) {
|
||||
jQuery('#updraftcentral_keys').unblock();
|
||||
if (typeof resp !== 'undefined' && resp.hasOwnProperty('fatal_error')) {
|
||||
console.error(resp.fatal_error_message);
|
||||
alert(resp.fatal_error_message);
|
||||
} else {
|
||||
var error_message = "updraftcentral_send_command: error: "+status+" ("+error_code+")";
|
||||
console.log(error_message);
|
||||
alert(error_message);
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
jQuery('#updraft_central_key').html();
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var updraft_copy_modal_buttons = {};
|
||||
updraft_copy_modal_buttons[updraftlion.close] = function() {
|
||||
jQuery(this).dialog("close");
|
||||
};
|
||||
|
||||
jQuery("#updraft-copy-modal").dialog({
|
||||
autoOpen: false,
|
||||
resizeOnWindowResize: true,
|
||||
scrollWithViewport: true,
|
||||
resizeAccordingToViewport: true,
|
||||
modal: true,
|
||||
buttons: updraft_copy_modal_buttons,
|
||||
});
|
||||
|
||||
jQuery('#updraftcentral_keys_content').on('click', '#updraftplus-copy', function(e) {
|
||||
e.preventDefault();
|
||||
var ele = jQuery('#updraftcentral-key');
|
||||
if (ele[0].value) {
|
||||
navigator.clipboard.writeText(ele[0].value).then(function() {
|
||||
alert(uclion.key_copied);
|
||||
}, function(err) {
|
||||
jQuery('#updraft-copy-modal').dialog('open');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
jQuery('#updraftcentral_keys').on('click', '.updraftcentral_key_delete', function(e) {
|
||||
e.preventDefault();
|
||||
var key_id = jQuery(this).data('key_id');
|
||||
if ('undefined' == typeof key_id) {
|
||||
console.log("UpdraftPlus: .updraftcentral_key_delete clicked, but no key ID found");
|
||||
return;
|
||||
}
|
||||
|
||||
jQuery('#updraftcentral_keys').block({ message: '<div style="margin: 8px; font-size:150%;"><img src="'+uclion.central_url+'/images/udlogo-rotating.gif" height="80" width="80" style="padding-bottom:10px;"><br>'+uclion.deleting+'</div>'});
|
||||
|
||||
updraftcentral_send_command('delete_key', { key_id: key_id }, function(response) {
|
||||
jQuery('#updraftcentral_keys').unblock();
|
||||
if (response.hasOwnProperty('keys_table')) {
|
||||
jQuery('#updraftcentral_keys_content').html(response.keys_table);
|
||||
}
|
||||
}, { error_callback: function(response, status, error_code, resp) {
|
||||
jQuery('#updraftcentral_keys').unblock();
|
||||
if (typeof resp !== 'undefined' && resp.hasOwnProperty('fatal_error')) {
|
||||
console.error(resp.fatal_error_message);
|
||||
alert(resp.fatal_error_message);
|
||||
} else {
|
||||
var error_message = "updraftcentral_send_command: error: "+status+" ("+error_code+")";
|
||||
console.log(error_message);
|
||||
alert(error_message);
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
Vendored
Executable
+372
@@ -0,0 +1,372 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* This class is the basic glue between the lower-level Remote Communications (RPC) class in UpdraftCentral, and the host plugin. It does not contain actual commands themselves; the class names to use for actual commands are passed in as a parameter to the constructor.
|
||||
*/
|
||||
class UpdraftCentral_Listener {
|
||||
|
||||
public $udrpc_version;
|
||||
|
||||
private $host = null;
|
||||
|
||||
private $receivers = array();
|
||||
|
||||
private $extra_info = array();
|
||||
|
||||
private $php_events = array();
|
||||
|
||||
private $commands = array();
|
||||
|
||||
private $current_udrpc = null;
|
||||
|
||||
private $command_classes;
|
||||
|
||||
private $auto_logged_in_cookie;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param Array $keys - keys to set up listeners for
|
||||
* @param Array $command_classes - commands
|
||||
*/
|
||||
public function __construct($keys = array(), $command_classes = array()) {
|
||||
global $updraftcentral_host_plugin;
|
||||
$this->host = $updraftcentral_host_plugin;
|
||||
|
||||
// It seems impossible for this condition to result in a return; but it seems Plesk can do something odd within the control panel that causes a problem - see HS#6276
|
||||
if (!is_a($this->host, 'UpdraftCentral_Host')) return;
|
||||
|
||||
$this->command_classes = $command_classes;
|
||||
|
||||
foreach ($keys as $name_hash => $key) {
|
||||
// publickey_remote isn't necessarily set yet, depending on the key exchange method
|
||||
if (!is_array($key) || empty($key['extra_info']) || empty($key['publickey_remote'])) continue;
|
||||
$indicator = $name_hash.'.central.updraftplus.com';
|
||||
$ud_rpc = $this->host->get_udrpc($indicator);
|
||||
$this->udrpc_version = $ud_rpc->version;
|
||||
|
||||
// Only turn this on if you are comfortable with potentially anything appearing in your PHP error log
|
||||
if (defined('UPDRAFTCENTRAL_UDRPC_FORCE_DEBUG') && UPDRAFTCENTRAL_UDRPC_FORCE_DEBUG) $ud_rpc->set_debug(true);
|
||||
|
||||
$this->receivers[$indicator] = $ud_rpc;
|
||||
$this->extra_info[$indicator] = isset($key['extra_info']) ? $key['extra_info'] : null;
|
||||
$ud_rpc->set_key_local($key['key']);
|
||||
$ud_rpc->set_key_remote($key['publickey_remote']);
|
||||
// Create listener (which causes WP actions to be fired when messages are received)
|
||||
$ud_rpc->activate_replay_protection();
|
||||
if (!empty($key['extra_info']) && isset($key['extra_info']['mothership'])) {
|
||||
$mothership = $key['extra_info']['mothership'];
|
||||
$url = '';
|
||||
if ('__updraftpluscom' == $mothership) {
|
||||
$url = 'https://teamupdraft.com';
|
||||
} elseif (false != ($parsed = parse_url($key['extra_info']['mothership'])) && is_array($parsed)) {
|
||||
$url = $parsed['scheme'].'://'.$parsed['host'];
|
||||
}
|
||||
if (!empty($url)) $ud_rpc->set_allow_cors_from(array($url));
|
||||
}
|
||||
$ud_rpc->create_listener();
|
||||
}
|
||||
|
||||
// If we ever need to expand beyond a single GET action, this can/should be generalised and put into the commands class
|
||||
if (!empty($_GET['udcentral_action']) && 'login' == $_GET['udcentral_action']) {
|
||||
// auth_redirect() does not return, according to the documentation; but the code shows that it can
|
||||
// auth_redirect();
|
||||
|
||||
if (!empty($_GET['login_id']) && is_numeric($_GET['login_id']) && !empty($_GET['login_key'])) {
|
||||
$login_user = get_user_by('id', $_GET['login_id']);
|
||||
|
||||
// THis is included so we can get $wp_version
|
||||
include_once(ABSPATH.WPINC.'/version.php');
|
||||
|
||||
if (is_a($login_user, 'WP_User') || (version_compare($wp_version, '3.5', '<') && !empty($login_user->ID))) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
|
||||
// Allow site implementers to disable this functionality
|
||||
$allow_autologin = apply_filters('updraftcentral_allow_autologin', true, $login_user);
|
||||
if ($allow_autologin) {
|
||||
$login_key = get_user_meta($login_user->ID, 'updraftcentral_login_key', true);
|
||||
if (is_array($login_key) && !empty($login_key['created']) && $login_key['created'] > time() - 60 && !empty($login_key['key']) && $login_key['key'] == $_GET['login_key']) {
|
||||
$autologin = empty($login_key['redirect_url']) ? network_admin_url() : $login_key['redirect_url'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($autologin)) {
|
||||
// Allow use once only
|
||||
delete_user_meta($login_user->ID, 'updraftcentral_login_key');
|
||||
$this->autologin_user($login_user, $autologin);
|
||||
}
|
||||
}
|
||||
|
||||
add_filter('udrpc_action', array($this, 'udrpc_action'), 10, 5);
|
||||
add_filter('updraftcentral_get_command_info', array($this, 'updraftcentral_get_command_info'), 10, 2);
|
||||
add_filter('updraftcentral_get_updraftplus_status', array($this, 'get_updraftplus_status'), 10, 1);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the UpdraftPlus plugin status whether it has been installed or activated
|
||||
*
|
||||
* @param mixed $data Default data to return
|
||||
* @return array
|
||||
*/
|
||||
public function get_updraftplus_status($data) {
|
||||
|
||||
// Handle cases of users who rename their plugin folders
|
||||
if (class_exists('UpdraftPlus')) {
|
||||
$data['is_updraftplus_installed'] = true;
|
||||
$data['is_updraftplus_active'] = true;
|
||||
} else {
|
||||
if (!function_exists('get_plugins')) require_once(ABSPATH.'wp-admin/includes/plugin.php');
|
||||
$plugins = get_plugins();
|
||||
$key = 'updraftplus/updraftplus.php';
|
||||
|
||||
if (array_key_exists($key, $plugins)) {
|
||||
$data['is_updraftplus_installed'] = true;
|
||||
if (is_plugin_active($key)) $data['is_updraftplus_active'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves command class information and includes class file if class
|
||||
* is currently not available.
|
||||
*
|
||||
* @param mixed $response The default response to return if the submitted command does not exists
|
||||
* @param string $command The command to parse and check
|
||||
* @return array Contains the following command information "command_php_class", "class_prefix" and "command"
|
||||
*/
|
||||
public function updraftcentral_get_command_info($response, $command) {
|
||||
if (!preg_match('/^([a-z0-9]+)\.(.*)$/', $command, $matches)) return $response;
|
||||
$class_prefix = $matches[1];
|
||||
$command = $matches[2];
|
||||
|
||||
// Other plugins might have registered the filter rather later so we need to make
|
||||
// sure that we get all the commands intended for UpdraftCentral.
|
||||
$this->command_classes = apply_filters('updraftcentral_remotecontrol_command_classes', $this->command_classes);
|
||||
|
||||
// We only handle some commands - the others, we let something else deal with
|
||||
if (!isset($this->command_classes[$class_prefix])) return $response;
|
||||
|
||||
$command_php_class = $this->command_classes[$class_prefix];
|
||||
$command_base_class_at = apply_filters('updraftcentral_command_base_class_at', UPDRAFTCENTRAL_CLIENT_DIR.'/commands.php');
|
||||
|
||||
if (!class_exists('UpdraftCentral_Commands')) include_once($command_base_class_at);
|
||||
|
||||
// Second parameter has been passed since
|
||||
do_action('updraftcentral_command_class_wanted', $command_php_class);
|
||||
|
||||
if (!class_exists($command_php_class)) {
|
||||
if (file_exists(UPDRAFTCENTRAL_CLIENT_DIR.'/modules/'.$class_prefix.'.php')) {
|
||||
include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/modules/'.$class_prefix.'.php');
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'command_php_class' => $command_php_class,
|
||||
'class_prefix' => $class_prefix,
|
||||
'command' => $command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* In response to auto logging in the user; set a corresponding logged_in cookie to the $login_user_cookie class variable
|
||||
*
|
||||
* @param String $cookie Authentication cookie
|
||||
* @param Integer $user_id User ID
|
||||
* @param Integer $expiration The time the cookie expires as a UNIX timestamp
|
||||
* @param String $scheme Cookie scheme used. Accepts 'auth', 'secure_auth', or 'logged_in'
|
||||
*/
|
||||
public function set_global_logged_in_cookie($cookie, $user_id, $expiration, $scheme) {
|
||||
if ('logged_in' === $scheme) {
|
||||
$this->auto_logged_in_cookie = $cookie;
|
||||
}
|
||||
return $cookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do verification before calling this method
|
||||
*
|
||||
* @param WP_User|Object $user user object for autologin
|
||||
* @param boolean $redirect_url Redirect URL
|
||||
*/
|
||||
private function autologin_user($user, $redirect_url = false) {
|
||||
if (!is_user_logged_in()) {
|
||||
// $user = get_user_by('id', $user_id);
|
||||
// Don't check that it's a WP_User - that's WP 3.5+ only
|
||||
if (!is_object($user) || empty($user->ID)) return;
|
||||
wp_set_current_user($user->ID, $user->user_login);
|
||||
add_filter('auth_cookie', array($this, 'set_global_logged_in_cookie'), 10, 4);
|
||||
wp_set_auth_cookie($user->ID);
|
||||
remove_filter('auth_cookie', array($this, 'set_global_logged_in_cookie'), 10, 4);
|
||||
do_action('wp_login', $user->user_login, $user);
|
||||
}
|
||||
if ($redirect_url) {
|
||||
// the wp_set_auth_cookie() above uses setcookie() function but the corresponding LOGGED_IN_COOKIE variable is visible and can only be accessible on the next page load
|
||||
// so we set the auth cookie into the superglobal $_COOKIE variable manually, we do this because the previously non logged-in user is now being auto-logged in and wp_create_nonce() needs the value of LOGGED_IN_COOKIE variable to produce a correct nonce
|
||||
if ($this->auto_logged_in_cookie) $_COOKIE[LOGGED_IN_COOKIE] = $this->auto_logged_in_cookie;
|
||||
$redirect_url = add_query_arg('restore_initiation_nonce', wp_create_nonce('updraftplus_udcentral_initiate_restore'), $redirect_url);
|
||||
if ($this->auto_logged_in_cookie) unset($_COOKIE[LOGGED_IN_COOKIE]);
|
||||
wp_safe_redirect($redirect_url);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WP filter udrpc_action
|
||||
*
|
||||
* @param Array $response - the unfiltered response that will be returned
|
||||
* @param String $command - the command being called
|
||||
* @param Array $data - the parameters to the command
|
||||
* @param String $key_name_indicator - the UC key that is in use
|
||||
* @param Object $ud_rpc - the UDRP object
|
||||
*
|
||||
* @return Array - filtered response
|
||||
*/
|
||||
public function udrpc_action($response, $command, $data, $key_name_indicator, $ud_rpc) {
|
||||
try {
|
||||
|
||||
if (empty($this->receivers[$key_name_indicator])) return $response;
|
||||
|
||||
// This can be used to detect an UpdraftCentral context
|
||||
if (!defined('UPDRAFTCENTRAL_COMMAND')) define('UPDRAFTCENTRAL_COMMAND', $command);
|
||||
|
||||
$this->initialise_listener_error_handling();
|
||||
|
||||
// UpdraftCentral needs this extra information especially now that the UpdraftCentral
|
||||
// libraries can be totally embedded in other plugins (e.g. WP-Optimize, etc.) thus,
|
||||
// that makes the UpdraftPlus plugin optional.
|
||||
//
|
||||
// This will give UpdraftCentral a proper way of disabling the backup feature
|
||||
// for this site if the UpdraftPlus plugin is currently not installed or activated.
|
||||
//
|
||||
// In addition, we need to attached the host plugin who is handling the UpdraftCentral requests
|
||||
global $updraftcentral_host_plugin;
|
||||
$extra = apply_filters('updraftcentral_get_updraftplus_status', array(
|
||||
'is_updraftplus_installed' => false,
|
||||
'is_updraftplus_active' => false,
|
||||
'host_plugin' => $updraftcentral_host_plugin->plugin_name,
|
||||
));
|
||||
|
||||
$command_info = apply_filters('updraftcentral_get_command_info', false, $command);
|
||||
if (!$command_info) {
|
||||
if (isset($response['data']) && is_array($response['data'])) $response['data']['extra'] = $extra;
|
||||
return $response;
|
||||
}
|
||||
|
||||
$class_prefix = $command_info['class_prefix'];
|
||||
$command = $command_info['command'];
|
||||
$command_php_class = $command_info['command_php_class'];
|
||||
|
||||
if (empty($this->commands[$class_prefix])) {
|
||||
if (class_exists($command_php_class)) {
|
||||
$this->commands[$class_prefix] = new $command_php_class($this);
|
||||
}
|
||||
}
|
||||
|
||||
$command_class = isset($this->commands[$class_prefix]) ? $this->commands[$class_prefix] : new stdClass;
|
||||
|
||||
if ('_' == substr($command, 0, 1) || !is_a($command_class, $command_php_class) || (!method_exists($command_class, $command) && !method_exists($command_class, '__call'))) {
|
||||
if (defined('UPDRAFTCENTRAL_UDRPC_FORCE_DEBUG') && UPDRAFTCENTRAL_UDRPC_FORCE_DEBUG) error_log("Unknown RPC command received: ".$command);
|
||||
|
||||
return $this->return_rpc_message(array('response' => 'rpcerror', 'data' => array('code' => 'unknown_rpc_command', 'data' => array('prefix' => $class_prefix, 'command' => $command, 'class' => $command_php_class))));
|
||||
}
|
||||
|
||||
$extra_info = isset($this->extra_info[$key_name_indicator]) ? $this->extra_info[$key_name_indicator] : null;
|
||||
|
||||
// Make it so that current_user_can() checks can apply + work
|
||||
if (!empty($extra_info['user_id'])) wp_set_current_user($extra_info['user_id']);
|
||||
|
||||
$this->current_udrpc = $ud_rpc;
|
||||
|
||||
do_action('updraftcentral_listener_pre_udrpc_action', $command, $command_class, $data, $extra_info);
|
||||
|
||||
// Allow the command class to perform any boiler-plate actions.
|
||||
if (is_callable(array($command_class, '_pre_action'))) call_user_func(array($command_class, '_pre_action'), $command, $data, $extra_info);
|
||||
|
||||
// Despatch
|
||||
$msg = apply_filters('updraftcentral_listener_udrpc_action', call_user_func(array($command_class, $command), $data, $extra_info), $command_class, $class_prefix, $command, $data, $extra_info);
|
||||
|
||||
if (is_callable(array($command_class, '_post_action'))) call_user_func(array($command_class, '_post_action'), $command, $data, $extra_info);
|
||||
|
||||
do_action('updraftcentral_listener_post_udrpc_action', $command, $command_class, $data, $extra_info);
|
||||
|
||||
if (isset($msg['data']) && is_array($msg['data'])) {
|
||||
$msg['data']['extra'] = $extra;
|
||||
}
|
||||
|
||||
return $this->return_rpc_message($msg);
|
||||
} catch (Exception $e) {
|
||||
$log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during UpdraftCentral command execution. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
|
||||
error_log($log_message);
|
||||
|
||||
return $this->return_rpc_message(array('response' => 'rpcerror', 'data' => array('code' => 'rpc_fatal_error', 'data' => array('command' => $command, 'message' => $log_message))));
|
||||
// @codingStandardsIgnoreLine
|
||||
} catch (Error $e) {
|
||||
$log_message = 'PHP Fatal error ('.get_class($e).') has occurred during UpdraftCentral command execution. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
|
||||
error_log($log_message);
|
||||
|
||||
return $this->return_rpc_message(array('response' => 'rpcerror', 'data' => array('code' => 'rpc_fatal_error', 'data' => array('command' => $command, 'message' => $log_message))));
|
||||
}
|
||||
}
|
||||
|
||||
public function get_current_udrpc() {
|
||||
return $this->current_udrpc;
|
||||
}
|
||||
|
||||
private function initialise_listener_error_handling() {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
$this->host->error_reporting_stop_when_logged = true;
|
||||
$error_levels = version_compare(PHP_VERSION, '8.4.0', '>=') ? E_ALL : E_ALL & ~E_STRICT;
|
||||
set_error_handler(array($this->host, 'php_error'), $error_levels);
|
||||
$this->php_events = array();
|
||||
@ob_start();// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Might be a bigger picture that I am missing but do we need to silence errors here?
|
||||
add_filter($updraftcentral_host_plugin->get_logline_filter(), array($this, 'updraftcentral_logline'), 10, 4);
|
||||
if (!$updraftcentral_host_plugin->get_debug_mode()) return;
|
||||
}
|
||||
|
||||
public function updraftcentral_logline($line, $nonce, $level, $uniq_id) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Unused parameter is present because the method is used as a WP filter.
|
||||
if ('notice' === $level && 'php_event' === $uniq_id) {
|
||||
$this->php_events[] = $line;
|
||||
}
|
||||
return $line;
|
||||
}
|
||||
|
||||
public function return_rpc_message($msg) {
|
||||
if (is_array($msg) && isset($msg['response']) && 'error' == $msg['response']) {
|
||||
$this->host->log('Unexpected response code in remote communications: '.serialize($msg));
|
||||
}
|
||||
|
||||
$caught_output = @ob_get_contents();// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Might be a bigger picture that I am missing but do we need to silence errors here?
|
||||
@ob_end_clean();// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Might be a bigger picture that I am missing but do we need to silence errors here?
|
||||
// If turning output-catching off, turn this on instead:
|
||||
// $caught_output = ''; @ob_end_flush();
|
||||
|
||||
// If there's higher-level output buffering going on, then get rid of that
|
||||
if (ob_get_level()) ob_end_clean();
|
||||
|
||||
if ($caught_output) {
|
||||
if (!isset($msg['data'])) $msg['data'] = null;
|
||||
$msg['data'] = array('caught_output' => $caught_output, 'previous_data' => $msg['data']);
|
||||
$already_rearranged_data = true;
|
||||
}
|
||||
|
||||
if (!empty($this->php_events)) {
|
||||
if (!isset($msg['data'])) $msg['data'] = null;
|
||||
if (!empty($already_rearranged_data)) {
|
||||
$msg['data']['php_events'] = array();
|
||||
} else {
|
||||
$msg['data'] = array('php_events' => array(), 'previous_data' => $msg['data']);
|
||||
}
|
||||
foreach ($this->php_events as $logline) {
|
||||
$msg['data']['php_events'][] = $logline;
|
||||
}
|
||||
}
|
||||
restore_error_handler();
|
||||
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+440
@@ -0,0 +1,440 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles Analytics Commands
|
||||
*
|
||||
* @method array ga_checker()
|
||||
* @method array get_access_token()
|
||||
* @method array set_authorization_code()
|
||||
*/
|
||||
class UpdraftCentral_Analytics_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
private $scope = 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/analytics.readonly';
|
||||
|
||||
private $endpoint = 'https://accounts.google.com/o/oauth2/auth';
|
||||
|
||||
private $token_info_endpoint = 'https://www.googleapis.com/oauth2/v1/tokeninfo';
|
||||
|
||||
private $access_key = 'updraftcentral_auth_server_access';
|
||||
|
||||
private $auth_endpoint;
|
||||
|
||||
private $client_id;
|
||||
|
||||
private $view_key = 'updraftcentral_analytics_views';
|
||||
|
||||
private $tracking_id_key = 'updraftcentral_analytics_tracking_id';
|
||||
|
||||
private $expiration;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->auth_endpoint = defined('UPDRAFTPLUS_GOOGLE_ANALYTICS_CALLBACK_URL') ? UPDRAFTPLUS_GOOGLE_ANALYTICS_CALLBACK_URL : 'https://auth.updraftplus.com/auth/googleanalytics';
|
||||
$this->client_id = defined('UPDRAFTPLUS_GOOGLE_ANALYTICS_CLIENT_ID') ? UPDRAFTPLUS_GOOGLE_ANALYTICS_CLIENT_ID : '306245874349-6s896c3tjpra26ns3dpplhqcl6rv6qlb.apps.googleusercontent.com';
|
||||
|
||||
// Set transient expiration - default for 24 hours
|
||||
$this->expiration = 86400;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether Google Analytics (GA) is installed or setup
|
||||
*
|
||||
* N.B. This check assumes GA is installed either using "wp_head" or "wp_footer" (e.g. attached
|
||||
* to the <head/> or somewhere before </body>). It does not recursively check all the pages
|
||||
* of the website to find if GA is installed on each or one of those pages, but only on the main/root page.
|
||||
*
|
||||
* @return array $result An array containing "ga_installed" property which returns "true" if GA (Google Analytics) is installed, "false" otherwise.
|
||||
*/
|
||||
public function ga_checker() {
|
||||
|
||||
try {
|
||||
|
||||
// Retrieves the tracking code/id if available
|
||||
$tracking_id = $this->get_tracking_id();
|
||||
$installed = true;
|
||||
|
||||
// If tracking code/id is currently not available then we
|
||||
// parse the needed information from the buffered content through
|
||||
// the "wp_head" and "wp_footer" hooks.
|
||||
if (false === $tracking_id) {
|
||||
$info = $this->extract_tracking_id();
|
||||
|
||||
$installed = $info['installed'];
|
||||
$tracking_id = $info['tracking_id'];
|
||||
}
|
||||
|
||||
// Get access token to be use to generate the report.
|
||||
$access_token = $this->_get_token();
|
||||
|
||||
if (empty($access_token)) {
|
||||
// If we don't get a valid access token then that would mean
|
||||
// the access has been revoked by the user or UpdraftCentral was not authorized yet
|
||||
// to access the user's analytics data, thus, we're clearing
|
||||
// any previously stored user access so we're doing some housekeeping here.
|
||||
$this->clear_user_access();
|
||||
}
|
||||
|
||||
// Wrap and combined information for the requesting
|
||||
// client's consumption
|
||||
$result = array(
|
||||
'ga_installed' => $installed,
|
||||
'tracking_id' => $tracking_id,
|
||||
'client_id' => $this->client_id,
|
||||
'redirect_uri' => $this->auth_endpoint,
|
||||
'scope' => $this->scope,
|
||||
'access_token' => $access_token,
|
||||
'endpoint' => $this->endpoint
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts Google Tracking ID from contents rendered through the "wp_head" and "wp_footer" action hooks
|
||||
*
|
||||
* @internal
|
||||
* @return array $result An array containing the result of the extraction.
|
||||
*/
|
||||
private function extract_tracking_id() {
|
||||
|
||||
// Define result array
|
||||
$result = array();
|
||||
|
||||
// Retrieve header content
|
||||
ob_start();
|
||||
do_action('wp_head');
|
||||
$header_content = ob_get_clean();
|
||||
|
||||
// Extract analytics information if available.
|
||||
$output = $this->parse_content($header_content);
|
||||
$result['installed'] = $output['installed'];
|
||||
$result['tracking_id'] = $output['tracking_id'];
|
||||
|
||||
// If it was not found, then now try the footer
|
||||
if (empty($result['tracking_id'])) {
|
||||
// Retrieve footer content
|
||||
ob_start();
|
||||
do_action('wp_footer');
|
||||
$footer_content = ob_get_clean();
|
||||
$output = $this->parse_content($footer_content);
|
||||
$result['installed'] = $output['installed'];
|
||||
$result['tracking_id'] = $output['tracking_id'];
|
||||
}
|
||||
|
||||
if (!empty($result['tracking_id'])) {
|
||||
set_transient($this->tracking_id_key, $result['tracking_id'], $this->expiration);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets access token
|
||||
*
|
||||
* Validates whether the system currently have a valid token to use when connecting to Google Analytics API.
|
||||
* If not, then it will send a token request based on the authorization code we stored during the
|
||||
* authorization phase. Otherwise, it will return an empty token.
|
||||
*
|
||||
* @return array $result An array containing the Google Analytics API access token.
|
||||
*/
|
||||
public function get_access_token() {
|
||||
|
||||
try {
|
||||
|
||||
// Loads or request a valid token to use
|
||||
$access_token = $this->_get_token();
|
||||
|
||||
if (!empty($access_token)) {
|
||||
$result = array('access_token' => $access_token);
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'ga_token_retrieval_failed', 'values' => array());
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any previously stored user access
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function clear_user_access() {
|
||||
return delete_option($this->access_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves user is and access token received from the auth server
|
||||
*
|
||||
* @param array $query Parameter array containing the user id and access token from the auth server.
|
||||
* @return array $result An array containing a "success" or "failure" message as a result of the current process.
|
||||
*/
|
||||
public function save_user_access($query) {
|
||||
|
||||
try {
|
||||
|
||||
$token = get_option($this->access_key, false);
|
||||
$result = array();
|
||||
|
||||
if (false === $token) {
|
||||
$token = array(
|
||||
'user_id' => base64_decode(urldecode($query['user_id'])),
|
||||
'access_token' => base64_decode(urldecode($query['access_token']))
|
||||
);
|
||||
|
||||
if (false !== update_option($this->access_key, $token)) {
|
||||
$result = array('error' => false, 'message' => 'ga_access_saved', 'values' => array());
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'ga_access_saving_failed', 'values' => array($query['access_token']));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the tracking code/id manually (user input)
|
||||
*
|
||||
* @param array $query Parameter array containing the tracking code/id to save.
|
||||
* @return array $result An array containing the result of the process.
|
||||
*/
|
||||
public function save_tracking_id($query) {
|
||||
try {
|
||||
$tracking_id = $query['tracking_id'];
|
||||
$saved = false;
|
||||
|
||||
if (!empty($tracking_id)) {
|
||||
$saved = set_transient($this->tracking_id_key, $tracking_id, $this->expiration);
|
||||
}
|
||||
|
||||
$result = array('saved' => $saved);
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves any available access token either previously saved info or
|
||||
* from a new request from the Google Server.
|
||||
*
|
||||
* @internal
|
||||
* @return string $authorization_code
|
||||
*/
|
||||
private function _get_token() {
|
||||
|
||||
// Retrieves the tracking code/id if available
|
||||
$tracking_id = $this->get_tracking_id();
|
||||
$access_token = '';
|
||||
|
||||
$token = get_option($this->access_key, false);
|
||||
if (false !== $token) {
|
||||
$access_token = isset($token['access_token']) ? $token['access_token'] : '';
|
||||
$user_id = isset($token['user_id']) ? $token['user_id'] : '';
|
||||
|
||||
if ((!empty($access_token) && !$this->_token_valid($access_token)) || (!empty($user_id) && empty($access_token) && !empty($tracking_id))) {
|
||||
if (!empty($user_id)) {
|
||||
$args = array(
|
||||
'headers' => apply_filters('updraftplus_auth_headers', array())
|
||||
);
|
||||
|
||||
$response = wp_remote_get($this->auth_endpoint.'?user_id='.$user_id.'&code=ud_googleanalytics_code', $args);
|
||||
if (is_wp_error($response)) {
|
||||
throw new Exception($response->get_error_message()); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- The escaping should be happening when the exception is printed
|
||||
} else {
|
||||
if (is_array($response)) {
|
||||
|
||||
$body = json_decode($response['body'], true);
|
||||
$token_response = array();
|
||||
|
||||
if (is_array($body) && !isset($body['error'])) {
|
||||
$token_response = json_decode(base64_decode($body[0]), true);
|
||||
}
|
||||
|
||||
if (is_array($token_response) && isset($token_response['access_token'])) {
|
||||
$access_token = $token_response['access_token'];
|
||||
} else {
|
||||
// If we don't get any valid response then that would mean that the
|
||||
// permission was already revoked. Thus, we need to re-authorize the
|
||||
// user before using the analytics feature once again.
|
||||
$access_token = '';
|
||||
}
|
||||
|
||||
$token['access_token'] = $access_token;
|
||||
update_option($this->access_key, $token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $access_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies whether the access token is still valid for use
|
||||
*
|
||||
* @internal
|
||||
* @param string $token The access token to be check and validated
|
||||
* @return bool
|
||||
* @throws Exception If an error has occurred while connecting to the Google Server.
|
||||
*/
|
||||
private function _token_valid($token) {
|
||||
|
||||
$response = wp_remote_get($this->token_info_endpoint.'?access_token='.$token);
|
||||
if (is_wp_error($response)) {
|
||||
throw new Exception($response->get_error_message()); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- The escaping should be happening when the exception is printed
|
||||
} else {
|
||||
if (is_array($response)) {
|
||||
$response = json_decode($response['body'], true);
|
||||
if (!empty($response)) {
|
||||
if (!isset($response['error']) && !isset($response['error_description'])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and extracts the google analytics information (NEEDED)
|
||||
*
|
||||
* @internal
|
||||
* @param string $content The content to parse
|
||||
* @return array An array containing the status of the process along with the tracking code/id
|
||||
*/
|
||||
private function parse_content($content) {
|
||||
|
||||
$installed = false;
|
||||
$gtm_installed = false;
|
||||
$tracking_id = '';
|
||||
$script_file_found = false;
|
||||
$tracking_id_found = false;
|
||||
|
||||
// Pull google analytics script file(s)
|
||||
preg_match_all('/<script\b[^>]*>([\s\S]*?)<\/script>/i', $content, $scripts);
|
||||
for ($i=0; $i < count($scripts[0]); $i++) {
|
||||
// Check for Google Analytics file
|
||||
if (stristr($scripts[0][$i], 'ga.js') || stristr($scripts[0][$i], 'analytics.js')) {
|
||||
$script_file_found = true;
|
||||
}
|
||||
|
||||
// Check for Google Tag Manager file
|
||||
// N.B. We are not checking for GTM but this check will be useful when
|
||||
// showing the notice to the user if we haven't found Google Analytics
|
||||
// directly being installed on the page.
|
||||
if (stristr($scripts[0][$i], 'gtm.js')) {
|
||||
$gtm_installed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Pull tracking code
|
||||
preg_match_all('/UA-[0-9]{5,}-[0-9]{1,}/i', $content, $codes);
|
||||
if (count($codes) > 0) {
|
||||
if (!empty($codes[0])) {
|
||||
$tracking_id_found = true;
|
||||
$tracking_id = $codes[0][0];
|
||||
}
|
||||
}
|
||||
|
||||
// If we found both the script and the tracking code then it is safe
|
||||
// to say that Google Analytics (GA) is installed. Thus, we're returning
|
||||
// "true" as a response.
|
||||
if ($script_file_found && $tracking_id_found) {
|
||||
$installed = true;
|
||||
}
|
||||
|
||||
// Return result of process.
|
||||
return array(
|
||||
'installed' => $installed,
|
||||
'gtm_installed' => $gtm_installed,
|
||||
'tracking_id' => $tracking_id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the "analytics_tracking_id" transient
|
||||
*
|
||||
* @internal
|
||||
* @return mixed Returns the value of the saved transient. Returns "false" if the transient does not exist.
|
||||
*/
|
||||
private function get_tracking_id() {
|
||||
return get_transient($this->tracking_id_key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current tracking id
|
||||
*
|
||||
* @return array $result An array containing the Google Tracking ID.
|
||||
*/
|
||||
public function get_current_tracking_id() {
|
||||
try {
|
||||
|
||||
// Get current site transient stored for this key
|
||||
$tracking_id = get_transient($this->tracking_id_key);
|
||||
|
||||
// Checks whether we have a valid token
|
||||
$access_token = $this->_get_token();
|
||||
if (empty($access_token)) {
|
||||
$tracking_id = '';
|
||||
}
|
||||
|
||||
if (false === $tracking_id) {
|
||||
$result = $this->extract_tracking_id();
|
||||
} else {
|
||||
$result = array(
|
||||
'installed' => true,
|
||||
'tracking_id' => $tracking_id
|
||||
);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears user access from database
|
||||
*
|
||||
* @return array $result An array containing the "Remove" confirmation whether the action succeeded or not.
|
||||
*/
|
||||
public function remove_user_access() {
|
||||
try {
|
||||
|
||||
// Clear user access
|
||||
$is_cleared = $this->clear_user_access();
|
||||
|
||||
if (false !== $is_cleared) {
|
||||
$result = array('removed' => true);
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'user_access_remove_failed', 'values' => array());
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => 'generic_response_error', 'values' => array($e->getMessage()));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+391
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles Backups Commands
|
||||
*/
|
||||
class UpdraftCentral_Backups_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
private $switched = false;
|
||||
|
||||
/**
|
||||
* Function that gets called before every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _pre_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- This function is called from listener.php and $extra_info is being sent.
|
||||
// Here we assign the current blog_id to a variable $blog_id
|
||||
$blog_id = get_current_blog_id();
|
||||
if (!empty($data['site_id'])) $blog_id = $data['site_id'];
|
||||
|
||||
if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
|
||||
$this->switched = switch_to_blog($blog_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that gets called after every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _post_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the caller from UpdraftCentral_Listener class uses 3 arguments.
|
||||
// Here, we're restoring to the current (default) blog before we switched
|
||||
if ($this->switched) restore_current_blog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the UpdraftPlus plugin status, UpdraftVault storage usage status, Next backup
|
||||
* schedule, etc. Used primarily by UpdraftCentral background process.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_status() {
|
||||
|
||||
if (!current_user_can('manage_options')) {
|
||||
$response = array(
|
||||
'status' => 'error',
|
||||
'error_code' => 'insufficient_permission',
|
||||
);
|
||||
} else {
|
||||
|
||||
if (!function_exists('get_mu_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
|
||||
$mu_plugins = get_mu_plugins();
|
||||
|
||||
$is_premium = false;
|
||||
if (defined('UPDRAFTPLUS_DIR') && file_exists(UPDRAFTPLUS_DIR.'/udaddons')) $is_premium = true;
|
||||
|
||||
// Set default response
|
||||
$response = array(
|
||||
'updraftplus_version' => '',
|
||||
'is_premium' => $is_premium,
|
||||
'installed' => false,
|
||||
'active' => false,
|
||||
'backup_count' => 0,
|
||||
'has_mu_plugins' => !empty($mu_plugins) ? true : false,
|
||||
'last_backup' => array(
|
||||
'backup_nonce' => '',
|
||||
'has_errors' => false,
|
||||
'has_warnings' => false,
|
||||
'has_succeeded' => false,
|
||||
),
|
||||
'updraftvault' => array(
|
||||
'site_connected' => false,
|
||||
'storage' => array('quota_used' => '0 MB', 'quota' => '0 MB', 'percentage_usage' => '0.0%'),
|
||||
),
|
||||
'meta' => array(),
|
||||
);
|
||||
|
||||
if (class_exists('UpdraftPlus')) {
|
||||
global $updraftplus;
|
||||
|
||||
$response['updraftplus_version'] = $updraftplus->version;
|
||||
$response['updraftvault'] = $this->get_updraftvault_status();
|
||||
$response['installed'] = true;
|
||||
$response['active'] = true;
|
||||
$response['meta'] = $this->get_filesystem_credentials_info();
|
||||
|
||||
$schedule = $this->get_next_backup_schedule();
|
||||
if ($schedule) {
|
||||
$response['next_backup_schedule'] = $schedule;
|
||||
}
|
||||
|
||||
$backup_history = UpdraftPlus_Backup_History::add_jobdata(UpdraftPlus_Backup_History::get_history());
|
||||
|
||||
$response['backup_count'] = count($backup_history);
|
||||
|
||||
$updraft_last_backup = UpdraftPlus_Options::get_updraft_option('updraft_last_backup');
|
||||
if ($updraft_last_backup) {
|
||||
$response['last_backup']['backup_nonce'] = $updraft_last_backup['backup_nonce'];
|
||||
if (isset($updraft_last_backup['backup_time'])) {
|
||||
$response['last_backup']['backup_date'] = gmdate('n/j/Y', $updraft_last_backup['backup_time']);
|
||||
$response['last_backup']['backup_time'] = $updraft_last_backup['backup_time'];
|
||||
}
|
||||
|
||||
$errors = 0;
|
||||
$warnings = 0;
|
||||
|
||||
if (is_array($updraft_last_backup['errors'])) {
|
||||
foreach ($updraft_last_backup['errors'] as $err) {
|
||||
$level = (is_array($err)) ? $err['level'] : 'error';
|
||||
if ('warning' == $level) {
|
||||
$warnings++;
|
||||
} elseif ('error' == $level) {
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors > 0) $response['last_backup']['has_errors'] = true;
|
||||
if ($warnings > 0) $response['last_backup']['has_warnings'] = true;
|
||||
if (isset($updraft_last_backup['success']) && $updraft_last_backup['success']) $response['last_backup']['has_succeeded'] = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!function_exists('get_plugins')) require_once(ABSPATH.'wp-admin/includes/plugin.php');
|
||||
$plugins = get_plugins();
|
||||
$key = 'updraftplus/updraftplus.php';
|
||||
|
||||
if (array_key_exists($key, $plugins)) {
|
||||
$response['installed'] = true;
|
||||
if (is_plugin_active($key)) $response['active'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the next backup schedule for Files and Database backups
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_next_backup_schedule() {
|
||||
|
||||
// Get the next (nearest) scheduled backups
|
||||
$files = wp_next_scheduled('updraft_backup');
|
||||
$db = wp_next_scheduled('updraft_backup_database');
|
||||
|
||||
if ($files && $db) {
|
||||
$timestamp = min($files, $db); // Get the nearest schedule among the two schedules
|
||||
} elseif ($files && !$db) {
|
||||
$timestamp = $files;
|
||||
} elseif (!$files && $db) {
|
||||
$timestamp = $db;
|
||||
} else {
|
||||
$timestamp = null;
|
||||
}
|
||||
|
||||
if (!empty($timestamp)) {
|
||||
return gmdate('g:i A - D', $timestamp);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the UpdrafVault storage usage status
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_updraftvault_status() {
|
||||
|
||||
if (!class_exists('UpdraftCentral_UpdraftVault_Commands')) {
|
||||
include_once(UPDRAFTPLUS_DIR.'/includes/updraftvault.php');
|
||||
}
|
||||
|
||||
$updraftvault = new UpdraftCentral_UpdraftVault_Commands($this->rc);
|
||||
$creds = $updraftvault->get_credentials();
|
||||
|
||||
$site_connected = false;
|
||||
$storage = array('quota_used' => '0 MB', 'quota' => '0 MB', 'percentage_usage' => '0.0%');
|
||||
$remote_service = false;
|
||||
|
||||
if (isset($creds['data'])) {
|
||||
if (!isset($creds['data']['error']) && isset($creds['data']['accesskey'])) {
|
||||
$site_connected = true;
|
||||
|
||||
$storage_objects_and_ids = UpdraftPlus_Storage_Methods_Interface::get_storage_objects_and_ids(array('updraftvault'));
|
||||
|
||||
if (isset($storage_objects_and_ids['updraftvault']['instance_settings'])) {
|
||||
$instance_settings = $storage_objects_and_ids['updraftvault']['instance_settings'];
|
||||
$instance_id = key($instance_settings);
|
||||
$opts = $instance_settings[$instance_id];
|
||||
|
||||
if (!class_exists('UpdraftPlus_BackupModule_updraftvault')) {
|
||||
include_once(UPDRAFTPLUS_DIR.'/methods/updraftvault.php');
|
||||
}
|
||||
|
||||
$vault = new UpdraftPlus_BackupModule_updraftvault();
|
||||
$vault->set_options($opts, false, $instance_id);
|
||||
|
||||
$quota_root = $opts['quota_root'];
|
||||
$quota = $opts['quota'];
|
||||
|
||||
if (empty($quota_root)) {
|
||||
// This next line is wrong: it lists the files *in this site's sub-folder*, rather than the whole Vault
|
||||
$current_files = $vault->listfiles('');
|
||||
} else {
|
||||
$current_files = $vault->listfiles_with_path($quota_root, '', true);
|
||||
}
|
||||
|
||||
if (!is_wp_error($current_files) && is_array($current_files)) {
|
||||
$quota_used = 0;
|
||||
foreach ($current_files as $file) {
|
||||
$quota_used += $file['size'];
|
||||
}
|
||||
|
||||
$storage = array(
|
||||
'quota_used' => round($quota_used / 1048576, 1).' MB',
|
||||
'quota' => round($quota / 1048576, 1).' MB',
|
||||
'percentage_usage' => sprintf('%.1f', 100*$quota_used / $quota).'%',
|
||||
);
|
||||
|
||||
$remote_service = array(
|
||||
'name' => 'updraft_include_remote_service_updraftvault',
|
||||
'value' => $instance_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'site_connected' => $site_connected,
|
||||
'storage' => $storage,
|
||||
'remote_service' => $remote_service,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information whether filesystem credentials (e.g. FTP/SSH) are required
|
||||
* when updating plugins
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_filesystem_credentials_info() {
|
||||
|
||||
if (!function_exists('get_filesystem_method')) {
|
||||
include_once(ABSPATH.'/wp-admin/includes/file.php');
|
||||
}
|
||||
|
||||
$filesystem_method = get_filesystem_method(array(), WP_PLUGIN_DIR);
|
||||
|
||||
ob_start();
|
||||
$filesystem_credentials_are_stored = request_filesystem_credentials(site_url());
|
||||
$filesystem_form = strip_tags(ob_get_contents(), '<div><h2><p><input><label><fieldset><legend><span><em>');
|
||||
ob_end_clean();
|
||||
|
||||
$request_filesystem_credentials = ('direct' != $filesystem_method && !$filesystem_credentials_are_stored);
|
||||
|
||||
return array(
|
||||
'request_filesystem_credentials' => $request_filesystem_credentials,
|
||||
'filesystem_form' => base64_encode($filesystem_form),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the backup progress in terms of entities completed. Used primarily by UpdraftCentral
|
||||
* for polling backup progress in the background.
|
||||
*
|
||||
* @param array $params Submitted arguments for the current request
|
||||
* @return array
|
||||
*/
|
||||
public function get_backup_progress($params) {
|
||||
|
||||
$nonce = isset($params['nonce']) ? $params['nonce'] : false;
|
||||
$response = array('nonce' => $params['nonce']);
|
||||
|
||||
if (!current_user_can('manage_options')) {
|
||||
$response['status'] = 'error';
|
||||
$response['error_code'] = 'insufficient_permission';
|
||||
} else {
|
||||
global $updraftplus;
|
||||
|
||||
if ($nonce && $updraftplus && is_a($updraftplus, 'UpdraftPlus')) {
|
||||
|
||||
// Check the job is not still running.
|
||||
$jobdata = $updraftplus->jobdata_getarray($nonce);
|
||||
|
||||
if (!empty($jobdata)) {
|
||||
$response['status'] = 'in-progress';
|
||||
|
||||
$file_entities = 0;
|
||||
$db_entities = 0;
|
||||
$processed = 0;
|
||||
|
||||
if (isset($jobdata['backup_database']) && 'no' != $jobdata['backup_database']) {
|
||||
$backup_database = $jobdata['backup_database'];
|
||||
$db_entities += count($backup_database);
|
||||
|
||||
foreach ($backup_database as $whichdb => $info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- In this check we only need the status contained in the $info for now.
|
||||
$status = $info; // For default: 'wp'
|
||||
if (is_array($info)) {
|
||||
$status = $info['status'];
|
||||
}
|
||||
|
||||
if ('finished' == $status) {
|
||||
$processed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($jobdata['backup_files']) && 'no' != $jobdata['backup_files']) {
|
||||
$file_entities = count($jobdata['job_file_entities']);
|
||||
|
||||
$backup_files = $jobdata['backup_files'];
|
||||
if ('finished' == $backup_files) {
|
||||
$processed += $file_entities;
|
||||
} elseif (isset($jobdata['filecreating_substatus'])) {
|
||||
$substatus = $jobdata['filecreating_substatus'];
|
||||
$processed += max(0, intval($substatus['i']) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
$response['progress'] = array(
|
||||
'file_entities' => $file_entities,
|
||||
'db_entities' => $db_entities,
|
||||
'total_entities' => $file_entities+$db_entities,
|
||||
'processed' => $processed,
|
||||
'percentage' => floor(($processed/($file_entities+$db_entities))*100),
|
||||
'nonce' => $nonce,
|
||||
);
|
||||
|
||||
UpdraftPlus_Options::update_updraft_option('updraft_central_last_backup_progress', $response['progress'], false);
|
||||
} else {
|
||||
$last_backup = UpdraftPlus_Options::get_updraft_option('updraft_last_backup');
|
||||
if ($nonce == $last_backup['backup_nonce']) {
|
||||
$response['status'] = 'finished';
|
||||
$response['progress'] = array('percentage' => 100);
|
||||
$response['progress']['errors'] = $last_backup['errors'];
|
||||
$response['progress']['backup_time'] = $last_backup['backup_time'];
|
||||
$response['progress']['completed_time'] = gmdate('g:ia', $last_backup['backup_time']);
|
||||
$response['progress']['completed_date'] = gmdate('M d, Y', $last_backup['backup_time']);
|
||||
|
||||
$errors = 0;
|
||||
$warnings = 0;
|
||||
|
||||
if (!empty($last_backup['errors']) && is_array($last_backup['errors'])) {
|
||||
foreach ($last_backup['errors'] as $err) {
|
||||
$level = (is_array($err)) ? $err['level'] : 'error';
|
||||
if ('warning' == $level) {
|
||||
$warnings++;
|
||||
} elseif ('error' == $level) {
|
||||
$errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response['progress']['has_errors'] = ($errors > 0) ? true : false;
|
||||
$response['progress']['has_warnings'] = ($warnings > 0) ? true : false;
|
||||
} else {
|
||||
// We might be too early to check the `updraft_last_backup` thus, we'll
|
||||
// give it a few rounds to check by setting the status to "in-progress"
|
||||
// and returning the last backup progress (if applicable).
|
||||
$last_progress = UpdraftPlus_Options::get_updraft_option('updraft_central_last_backup_progress');
|
||||
|
||||
$response['status'] = 'in-progress';
|
||||
if (!empty($last_progress) && isset($last_progress['nonce'])) {
|
||||
$response['progress'] = $last_progress;
|
||||
|
||||
if ($nonce == $last_progress['nonce']) {
|
||||
UpdraftPlus_Options::delete_updraft_option('updraft_central_last_backup_progress');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response($response);
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+842
@@ -0,0 +1,842 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
class UpdraftCentral_Comments_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
/**
|
||||
* The _search_comments function searches all available comments based
|
||||
* on the following query parameters (type, status, search)
|
||||
*
|
||||
* Search Parameters/Filters:
|
||||
* type - comment types can be 'comment', 'trackback' and 'pingback', defaults to 'comment'
|
||||
* status - comment status can be 'hold' or unapprove, 'approve', 'spam', 'trash'
|
||||
* search - user generated content or keyword
|
||||
*
|
||||
* @param array $query The query to search comments
|
||||
* @return array
|
||||
*/
|
||||
private function _search_comments($query) {
|
||||
|
||||
// Basic parameters to the query and should display
|
||||
// the results in descending order (latest comments) first
|
||||
// based on their generated IDs
|
||||
|
||||
$args = array(
|
||||
'orderby' => 'ID',
|
||||
'order' => 'DESC',
|
||||
'type' => $query['type'],
|
||||
'status' => $query['status'],
|
||||
'search' => esc_attr($query['search']),
|
||||
);
|
||||
|
||||
$query = new WP_Comment_Query;
|
||||
$found_comments = $query->query($args);
|
||||
|
||||
$comments = array();
|
||||
foreach ($found_comments as $comment) {
|
||||
|
||||
// We're returning a collection of comment in an array,
|
||||
// in sync with the originator of the request on the ui side
|
||||
// so, we're pulling it one by one into the array before
|
||||
// returning it.
|
||||
|
||||
if (!in_array($comment, $comments)) {
|
||||
array_push($comments, $comment);
|
||||
}
|
||||
}
|
||||
|
||||
return $comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* The _calculate_pages function generates and builds the pagination links
|
||||
* based on the current search parameters/filters. Please see _search_comments
|
||||
* for the breakdown of these parameters.
|
||||
*
|
||||
* @param array $query Query to generate pagination links
|
||||
* @return array
|
||||
*/
|
||||
private function _calculate_pages($query) {
|
||||
$per_page_options = array(10, 20, 30, 40, 50);
|
||||
|
||||
if (!empty($query)) {
|
||||
if (!empty($query['search'])) {
|
||||
return array(
|
||||
'page_count' => 1,
|
||||
'page_no' => 1
|
||||
);
|
||||
}
|
||||
|
||||
$pages = array();
|
||||
$page_query = new WP_Comment_Query;
|
||||
|
||||
// Here, we're pulling the comments based on the
|
||||
// two parameters namely type and status.
|
||||
//
|
||||
// The number of results/comments found will then
|
||||
// be use to compute for the number of pages to be
|
||||
// displayed as navigation links when browsing all
|
||||
// comments from the frontend.
|
||||
|
||||
$comments = $page_query->query(array(
|
||||
'type' => $query['type'],
|
||||
'status' => $query['status']
|
||||
));
|
||||
|
||||
$total_comments = count($comments);
|
||||
$page_count = ceil($total_comments / $query['per_page']);
|
||||
|
||||
if ($page_count > 1) {
|
||||
for ($i = 0; $i < $page_count; $i++) {
|
||||
if ($i + 1 == $query['page_no']) {
|
||||
$paginator_item = array(
|
||||
'value' => $i+1,
|
||||
'setting' => 'disabled'
|
||||
);
|
||||
} else {
|
||||
$paginator_item = array(
|
||||
'value' => $i+1
|
||||
);
|
||||
}
|
||||
array_push($pages, $paginator_item);
|
||||
}
|
||||
|
||||
if ($query['page_no'] >= $page_count) {
|
||||
$page_next = array(
|
||||
'value' => $page_count,
|
||||
'setting' => 'disabled'
|
||||
);
|
||||
} else {
|
||||
$page_next = array(
|
||||
'value' => $query['page_no'] + 1
|
||||
);
|
||||
}
|
||||
|
||||
if (1 === $query['page_no']) {
|
||||
$page_prev = array(
|
||||
'value' => 1,
|
||||
'setting' => 'disabled'
|
||||
);
|
||||
} else {
|
||||
$page_prev = array(
|
||||
'value' => $query['page_no'] - 1
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'page_no' => $query['page_no'],
|
||||
'per_page' => $query['per_page'],
|
||||
'page_count' => $page_count,
|
||||
'pages' => $pages,
|
||||
'page_next' => $page_next,
|
||||
'page_prev' => $page_prev,
|
||||
'total_results' => $total_comments,
|
||||
'per_page_options' => $per_page_options
|
||||
);
|
||||
|
||||
} else {
|
||||
return array(
|
||||
'page_no' => $query['page_no'],
|
||||
'per_page' => $query['per_page'],
|
||||
'page_count' => $page_count,
|
||||
'total_results' => $total_comments,
|
||||
'per_page_options' => $per_page_options
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return array(
|
||||
'per_page_options' => $per_page_options
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_blog_sites function pulls blog sites available for the current WP instance.
|
||||
* If Multisite is enabled on the server, then sites under the network will be pulled, otherwise, it will return an empty array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_blog_sites() {
|
||||
|
||||
if (!is_multisite()) return array();
|
||||
|
||||
// Initialize array container
|
||||
$sites = $network_sites = array();
|
||||
|
||||
// Check to see if latest get_sites (available on WP version >= 4.6) function is
|
||||
// available to pull any available sites from the current WP instance. If not, then
|
||||
// we're going to use the fallback function wp_get_sites (for older version).
|
||||
|
||||
if (function_exists('get_sites') && class_exists('WP_Site_Query')) {
|
||||
$network_sites = get_sites();
|
||||
} else {
|
||||
if (function_exists('wp_get_sites')) {
|
||||
$network_sites = wp_get_sites();
|
||||
}
|
||||
}
|
||||
|
||||
// We only process if sites array is not empty, otherwise, bypass
|
||||
// the next block.
|
||||
|
||||
if (!empty($network_sites)) {
|
||||
foreach ($network_sites as $site) {
|
||||
|
||||
// Here we're checking if the site type is an array, because
|
||||
// we're pulling the blog_id property based on the type of
|
||||
// site returned.
|
||||
// get_sites returns an array of object, whereas the wp_get_sites
|
||||
// function returns an array of array.
|
||||
|
||||
$blog_id = (is_array($site)) ? $site['blog_id'] : $site->blog_id;
|
||||
|
||||
|
||||
// We're saving the blog_id and blog name as an associative item
|
||||
// into the sites array, that will be used as "Sites" option in
|
||||
// the frontend.
|
||||
|
||||
$sites[$blog_id] = get_blog_details($blog_id)->blogname;
|
||||
}
|
||||
}
|
||||
|
||||
return $sites;
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_wp_option function pulls current blog options
|
||||
* from the database using either following functions:
|
||||
* - get_blog_option (for multisite)
|
||||
* - get_option (for ordinary blog)
|
||||
*
|
||||
* @param array $blog_id This is the specific blog ID
|
||||
* @param array $setting specifies settings
|
||||
* @return array
|
||||
*/
|
||||
private function _get_wp_option($blog_id, $setting) {
|
||||
return is_multisite() ? get_blog_option($blog_id, $setting) : get_option($setting);
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_comments function pull all the comments from the database
|
||||
* based on the current search parameters/filters. Please see _search_comments
|
||||
* for the breakdown of these parameters.
|
||||
*
|
||||
* @param array $query Specific query to pull comments
|
||||
* @return array
|
||||
*/
|
||||
public function get_comments($query) {
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($query['blog_id'])) $blog_id = $query['blog_id'];
|
||||
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull comments from.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
if (!empty($query['search'])) {
|
||||
// If a search keyword is present, then we'll call the _search_comments
|
||||
// function to process the query.
|
||||
|
||||
$comments = $this->_search_comments($query);
|
||||
} else {
|
||||
// Set default parameter values if the designated
|
||||
// parameters are empty.
|
||||
|
||||
if (empty($query['per_page'])) {
|
||||
$query['per_page'] = 10;
|
||||
}
|
||||
if (empty($query['page_no'])) {
|
||||
$query['page_no'] = 1;
|
||||
}
|
||||
if (empty($query['type'])) {
|
||||
$query['type'] = '';
|
||||
}
|
||||
if (empty($query['status'])) {
|
||||
$query['status'] = '';
|
||||
}
|
||||
|
||||
// Since WP_Comment_Query parameters doesn't have a "page" attribute, we
|
||||
// need to compute for the offset to get the exact content based on the
|
||||
// current page and the number of items per page.
|
||||
|
||||
$offset = ((int) $query['page_no'] - 1) * (int) $query['per_page'];
|
||||
$args = array(
|
||||
'orderby' => 'ID',
|
||||
'order' => 'DESC',
|
||||
'number' => $query['per_page'],
|
||||
'offset' => $offset,
|
||||
'type' => $query['type'],
|
||||
'status' => $query['status']
|
||||
);
|
||||
|
||||
$comments_query = new WP_Comment_Query;
|
||||
$comments = $comments_query->query($args);
|
||||
}
|
||||
|
||||
// If no comments are found based on the current query then
|
||||
// we return with error.
|
||||
|
||||
if (empty($comments)) {
|
||||
$result = array('message' => 'comments_not_found');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Otherwise, we're going to process each comment
|
||||
// before we return it to the one issuing the request.
|
||||
//
|
||||
// Process in the sense that we add additional related info
|
||||
// such as the post tile where the comment belongs to, the
|
||||
// comment status, a formatted date field, and to which parent comment
|
||||
// does the comment was intended to be as a reply.
|
||||
|
||||
foreach ($comments as &$comment) {
|
||||
$comment = get_comment($comment->comment_ID, ARRAY_A);
|
||||
if ($comment) {
|
||||
$post = get_post($comment['comment_post_ID']);
|
||||
|
||||
if ($post) $comment['in_response_to'] = $post->post_title;
|
||||
if (!empty($comment['comment_parent'])) {
|
||||
$parent_comment = get_comment($comment['comment_parent'], ARRAY_A);
|
||||
if ($parent_comment) $comment['in_reply_to'] = $parent_comment['comment_author'];
|
||||
}
|
||||
|
||||
// We're formatting the comment_date to be exactly the same
|
||||
// with that of WP Comments table (e.g. 2016/12/21 at 10:30 PM)
|
||||
|
||||
$comment['comment_date'] = date('Y/m/d \a\t g:i a', strtotime($comment['comment_date']));
|
||||
|
||||
$status = wp_get_comment_status($comment['comment_ID']);
|
||||
if ($status) {
|
||||
$comment['comment_status'] = $status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We return the following to the one issuing
|
||||
// the request.
|
||||
|
||||
$result = array(
|
||||
'comments' => $comments,
|
||||
'paging' => $this->_calculate_pages($query)
|
||||
);
|
||||
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_comment_filters function builds a array of options
|
||||
* to be use as filters for the search function on the frontend.
|
||||
*/
|
||||
public function get_comment_filters() {
|
||||
// Options for comment_types field
|
||||
$comment_types = apply_filters('admin_comment_types_dropdown', array(
|
||||
'comment' => __('Comments'),// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core.
|
||||
'pings' => __('Pings'),// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core.
|
||||
));
|
||||
|
||||
// Options for comment_status field
|
||||
$comment_statuses = array(
|
||||
'approve' => __('Approve'),// phpcs:ignore WordPress.WP.I18n.MissingArgDomain -- The string exists within the WordPress core.
|
||||
'hold' => __('Hold or Unapprove', 'updraftplus'),
|
||||
'trash' => __('Trash', 'updraftplus'),
|
||||
'spam' => __('Spam', 'updraftplus'),
|
||||
);
|
||||
|
||||
// Pull sites options if available.
|
||||
$sites = $this->get_blog_sites();
|
||||
|
||||
$result = array(
|
||||
'sites' => $sites,
|
||||
'types' => $comment_types,
|
||||
'statuses' => $comment_statuses,
|
||||
'paging' => $this->_calculate_pages(null),
|
||||
);
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_settings function pulls the current discussion settings
|
||||
* option values.
|
||||
*
|
||||
* @param array $params Passing specific params for getting current discussion settings
|
||||
* @return array
|
||||
*/
|
||||
public function get_settings($params) {
|
||||
global $updraftcentral_main;
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to manage and edit
|
||||
// WP options then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'manage_options')) {
|
||||
$result = array('error' => true, 'message' => 'insufficient_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Pull sites options if available.
|
||||
$sites = $this->get_blog_sites();
|
||||
|
||||
// Wrap current discussion settings values into an array item
|
||||
// named settings.
|
||||
|
||||
$result = array(
|
||||
'settings' => array(
|
||||
'default_pingback_flag' => $this->_get_wp_option($blog_id, 'default_pingback_flag'),
|
||||
'default_ping_status' => $this->_get_wp_option($blog_id, 'default_ping_status'),
|
||||
'default_comment_status' => $this->_get_wp_option($blog_id, 'default_comment_status'),
|
||||
'require_name_email' => $this->_get_wp_option($blog_id, 'require_name_email'),
|
||||
'comment_registration' => $this->_get_wp_option($blog_id, 'comment_registration'),
|
||||
'close_comments_for_old_posts' => $this->_get_wp_option($blog_id, 'close_comments_for_old_posts'),
|
||||
'close_comments_days_old' => $this->_get_wp_option($blog_id, 'close_comments_days_old'),
|
||||
'thread_comments' => $this->_get_wp_option($blog_id, 'thread_comments'),
|
||||
'thread_comments_depth' => $this->_get_wp_option($blog_id, 'thread_comments_depth'),
|
||||
'page_comments' => $this->_get_wp_option($blog_id, 'page_comments'),
|
||||
'comments_per_page' => $this->_get_wp_option($blog_id, 'comments_per_page'),
|
||||
'default_comments_page' => $this->_get_wp_option($blog_id, 'default_comments_page'),
|
||||
'comment_order' => $this->_get_wp_option($blog_id, 'comment_order'),
|
||||
'comments_notify' => $this->_get_wp_option($blog_id, 'comments_notify'),
|
||||
'moderation_notify' => $this->_get_wp_option($blog_id, 'moderation_notify'),
|
||||
'comment_moderation' => $this->_get_wp_option($blog_id, 'comment_moderation'),
|
||||
'comment_max_links' => $this->_get_wp_option($blog_id, 'comment_max_links'),
|
||||
'moderation_keys' => $this->_get_wp_option($blog_id, 'moderation_keys'),
|
||||
),
|
||||
'sites' => $sites,
|
||||
);
|
||||
|
||||
$wp_version = $updraftcentral_main->get_wordpress_version();
|
||||
if (version_compare($wp_version, '5.5.0', '<')) {
|
||||
$result['settings']['comment_whitelist'] = $this->_get_wp_option($blog_id, 'comment_whitelist');
|
||||
$result['settings']['blacklist_keys'] = $this->_get_wp_option($blog_id, 'blacklist_keys');
|
||||
} else {
|
||||
$result['settings']['comment_previously_approved'] = $this->_get_wp_option($blog_id, 'comment_previously_approved');
|
||||
$result['settings']['disallowed_keys'] = $this->_get_wp_option($blog_id, 'disallowed_keys');
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The update_settings function updates the discussion settings
|
||||
* basing on the user generated content/option from the frontend
|
||||
* form.
|
||||
*
|
||||
* @param array $params Specific params to update settings based on discussion
|
||||
* @return array
|
||||
*/
|
||||
public function update_settings($params) {
|
||||
|
||||
// Extract settings values from passed parameters.
|
||||
$settings = $params['settings'];
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to manage and edit
|
||||
// WP options then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'manage_options')) {
|
||||
$result = array('error' => true, 'message' => 'insufficient_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're sanitizing the input fields before we save them to the database
|
||||
// for safety and security reason. The "explode" and "implode" functions are meant
|
||||
// to maintain the line breaks associated with a textarea input/value.
|
||||
|
||||
foreach ($settings as $key => $value) {
|
||||
|
||||
// We're using update_blog_option and update_option altogether to update the current
|
||||
// discussion settings.
|
||||
|
||||
if (is_multisite()) {
|
||||
update_blog_option($blog_id, $key, implode("\n", array_map('sanitize_text_field', explode("\n", $value))));
|
||||
} else {
|
||||
update_option($key, implode("\n", array_map('sanitize_text_field', explode("\n", $value))));
|
||||
}
|
||||
}
|
||||
|
||||
// We're not checking for errors here, but instead we're directly returning a success (error = false)
|
||||
// status always, because WP's update_option will return fail if values were not changed, meaning
|
||||
// previous values were not changed by the user's current request, not an actual exception thrown.
|
||||
// Thus, giving a false positive message or report to the frontend.
|
||||
|
||||
$result = array('error' => false, 'message' => 'settings_updated', 'values' => array());
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_comment function pulls a single comment based
|
||||
* on a comment ID.
|
||||
*
|
||||
* @param array $params Specific params for getting a single comment
|
||||
* @return array
|
||||
*/
|
||||
public function get_comment($params) {
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to moderate or edit
|
||||
// a comment then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'moderate_comments')) {
|
||||
$result = array('error' => true, 'message' => 'insufficient_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull comments from.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
// Get comment by comment_ID parameter and return result as an array.
|
||||
$result = array(
|
||||
'comment' => get_comment($params['comment_id'], ARRAY_A)
|
||||
);
|
||||
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The reply_comment function creates a new comment as a reply
|
||||
* to a certain/selected comment.
|
||||
*
|
||||
* @param array $params Specific params to create a new comment reply
|
||||
* @return array
|
||||
*/
|
||||
public function reply_comment($params) {
|
||||
|
||||
// Extract reply info from the passed parameters
|
||||
$reply = $params['comment'];
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to moderate or edit
|
||||
// a comment then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'moderate_comments')) {
|
||||
$result = array('error' => true, 'message' => 'comment_reply_no_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to apply our changes.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
|
||||
// Get comment by comment_ID parameter.
|
||||
$comment = get_comment($reply['comment_id']);
|
||||
if ($comment) {
|
||||
|
||||
// Get the currently logged in user
|
||||
$user = wp_get_current_user();
|
||||
|
||||
// If the current comment was not approved yet then
|
||||
// we need to approve it before we create a reply to
|
||||
// to the comment, mimicking exactly the WP behaviour
|
||||
// in terms of creating a reply to a comment.
|
||||
|
||||
if (empty($comment->comment_approved)) {
|
||||
$update_data = array(
|
||||
'comment_ID' => $reply['comment_id'],
|
||||
'comment_approved' => 1
|
||||
);
|
||||
wp_update_comment($update_data);
|
||||
}
|
||||
|
||||
// Build new comment parameters based on current user info and
|
||||
// the target comment for the reply.
|
||||
$data = array(
|
||||
'comment_post_ID' => $comment->comment_post_ID,
|
||||
'comment_author' => $user->display_name,
|
||||
'comment_author_email' => $user->user_email,
|
||||
'comment_author_url' => $user->user_url,
|
||||
'comment_content' => $reply['message'],
|
||||
'comment_parent' => $reply['comment_id'],
|
||||
'user_id' => $user->ID,
|
||||
'comment_date' => current_time('mysql'),
|
||||
'comment_approved' => 1
|
||||
);
|
||||
|
||||
// Create new comment based on the parameters above, and return
|
||||
// the status accordingly.
|
||||
|
||||
if (wp_insert_comment($data)) {
|
||||
$result = array('error' => false, 'message' => 'comment_replied_with_comment_author', 'values' => array($comment->comment_author));
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_reply_failed_with_error', 'values' => array($comment->comment_ID));
|
||||
}
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_does_not_exists_error', 'values' => array($reply['comment_id']));
|
||||
}
|
||||
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The edit_comment function saves new information for the
|
||||
* currently selected comment.
|
||||
*
|
||||
* @param array $params Specific params for editing a comment
|
||||
* @return array
|
||||
*/
|
||||
public function edit_comment($params) {
|
||||
|
||||
// Extract new comment info from the passed parameters
|
||||
$comment = $params['comment'];
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to moderate or edit
|
||||
// a comment then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'moderate_comments')) {
|
||||
$result = array('error' => true, 'message' => 'comment_edit_no_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to apply our changes.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
|
||||
// Get current comment details
|
||||
$original_comment = get_comment($comment['comment_id']);
|
||||
if ($original_comment) {
|
||||
$data = array();
|
||||
|
||||
// Replace "comment_id" with "comment_ID" since WP does not recognize
|
||||
// the small case "id".
|
||||
$comment['comment_ID'] = $original_comment->comment_ID;
|
||||
unset($comment['comment_id']);
|
||||
|
||||
// Here, we're sanitizing the input fields before we save them to the database
|
||||
// for safety and security reason. The "explode" and "implode" functions are meant
|
||||
// to maintain the line breaks associated with a textarea input/value.
|
||||
|
||||
foreach ($comment as $key => $value) {
|
||||
$data[$key] = implode("\n", array_map('sanitize_text_field', explode("\n", $value)));
|
||||
}
|
||||
|
||||
// Update existing comment based on the passed parameter fields and
|
||||
// return the status accordingly.
|
||||
|
||||
if (wp_update_comment($data)) {
|
||||
$result = array('error' => false, 'message' => 'comment_edited_with_comment_author', 'values' => array($original_comment->comment_author));
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_edit_failed_with_error', 'values' => array($original_comment->comment_ID));
|
||||
}
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_does_not_exists_error', 'values' => array($comment['comment_id']));
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The update_comment_status function is a generic handler for the following
|
||||
* comment actions:
|
||||
*
|
||||
* - approve comment
|
||||
* - unapprove comment
|
||||
* - set comment as spam
|
||||
* - move comment to trash
|
||||
* - delete comment permanently
|
||||
* - unset comment as spam
|
||||
* - restore comment
|
||||
*
|
||||
* @param array $params Specific params to update comment status
|
||||
* @return array
|
||||
*/
|
||||
public function update_comment_status($params) {
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['blog_id'])) $blog_id = $params['blog_id'];
|
||||
|
||||
|
||||
// If user does not have sufficient privileges to moderate or edit
|
||||
// a comment then we return with error.
|
||||
|
||||
if (!current_user_can_for_blog($blog_id, 'moderate_comments')) {
|
||||
$result = array('error' => true, 'message' => 'comment_change_status_no_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to apply our changes.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
|
||||
// We make sure that we still have a valid comment from the server
|
||||
// before we apply the currently selected action.
|
||||
|
||||
$comment = get_comment($params['comment_id']);
|
||||
if ($comment) {
|
||||
$post = get_post($comment->comment_post_ID);
|
||||
|
||||
if ($post) $comment->in_response_to = $post->post_title;
|
||||
if (!empty($comment->comment_parent)) {
|
||||
$parent_comment = get_comment($comment->comment_parent);
|
||||
if ($parent_comment) $comment->in_reply_to = $parent_comment->comment_author;
|
||||
}
|
||||
|
||||
// We're formatting the comment_date to be exactly the same
|
||||
// with that of WP Comments table (e.g. 2016/12/21 at 10:30 PM)
|
||||
|
||||
$comment->comment_date = date('Y/m/d \a\t g:i a', strtotime($comment->comment_date));
|
||||
|
||||
$status = wp_get_comment_status($comment->comment_ID);
|
||||
if ($status) {
|
||||
$comment->comment_status = $status;
|
||||
}
|
||||
|
||||
$succeeded = false;
|
||||
$message = '';
|
||||
|
||||
// Here, we're using WP's wp_set_comment_status function to change the state
|
||||
// of the selected comment based on the current action, except for the "delete" action
|
||||
// where we use the wp_delete_comment to delete the comment permanently by passing
|
||||
// "true" to the second argument.
|
||||
|
||||
switch ($params['action']) {
|
||||
case 'approve':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'approve');
|
||||
$message = 'comment_approve_with_comment_author';
|
||||
break;
|
||||
case 'unapprove':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'hold');
|
||||
$message = 'comment_unapprove_with_comment_author';
|
||||
break;
|
||||
case 'spam':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'spam');
|
||||
$message = 'comment_spam_with_comment_author';
|
||||
break;
|
||||
case 'trash':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'trash');
|
||||
$message = 'comment_trash_with_comment_author';
|
||||
break;
|
||||
case 'delete':
|
||||
$succeeded = wp_delete_comment($params['comment_id'], true);
|
||||
$message = 'comment_delete_with_comment_author';
|
||||
break;
|
||||
case 'notspam':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'hold');
|
||||
$message = 'comment_not_spam_with_comment_author';
|
||||
break;
|
||||
case 'restore':
|
||||
$succeeded = wp_set_comment_status($params['comment_id'], 'hold');
|
||||
$message = 'comment_restore_with_comment_author';
|
||||
break;
|
||||
}
|
||||
|
||||
// If the current action succeeded, then we return a success message, otherwise,
|
||||
// we return an error message to the user issuing the request.
|
||||
|
||||
if ($succeeded) {
|
||||
$result = array('error' => false, 'message' => $message, 'values' => array($comment->comment_author), 'status' => $comment->comment_status, 'approved' => $comment->comment_approved);
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_change_status_failed_with_error', 'values' => array($comment->comment_ID));
|
||||
}
|
||||
} else {
|
||||
$result = array('error' => true, 'message' => 'comment_does_not_exists_error', 'values' => array($params['comment_id']));
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+508
@@ -0,0 +1,508 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* - A container for RPC commands (core UpdraftCentral commands). Commands map exactly onto method names (and hence this class should not implement anything else, beyond the constructor, and private methods)
|
||||
* - Return format is array('response' => (string - a code), 'data' => (mixed));
|
||||
*
|
||||
* RPC commands are not allowed to begin with an underscore. So, any private methods can be prefixed with an underscore.
|
||||
*/
|
||||
class UpdraftCentral_Core_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
/**
|
||||
* Retrieve site icon (favicon)
|
||||
*
|
||||
* @return array An array containing the site icon (favicon) byte string if available
|
||||
*/
|
||||
public function get_site_icon() {
|
||||
|
||||
if (!function_exists('get_site_icon_url')) {
|
||||
include_once(ABSPATH.'wp-includes/general-template.php');
|
||||
}
|
||||
|
||||
$site_icon_url = get_site_icon_url();
|
||||
|
||||
// If none is set in WordPress, let's try to search for the default favicon
|
||||
// within the site's directory
|
||||
if (empty($site_icon_url)) {
|
||||
|
||||
if (!function_exists('get_site_url')) {
|
||||
include_once(ABSPATH.'wp-includes/link-template.php');
|
||||
}
|
||||
|
||||
// Common favicon locations to check
|
||||
$potential_locations = array(
|
||||
'/favicon.ico',
|
||||
'/favicon.png',
|
||||
'/favicon.svg',
|
||||
'/assets/favicon.ico',
|
||||
'/assets/images/favicon.ico',
|
||||
'/apple-touch-icon.png',
|
||||
'/apple-touch-icon-precomposed.png',
|
||||
);
|
||||
|
||||
foreach ($potential_locations as $location) {
|
||||
$path = rtrim(ABSPATH, '/\\').$location;
|
||||
if (file_exists($path)) {
|
||||
$site_icon_url = get_site_url().$location;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We are returning the site icon as byte string instead of URL in order to avoid
|
||||
// any hotlink protection that might prevent us to show the icon in UpdraftCentral
|
||||
// dashboard successfully.
|
||||
$site_icon = '';
|
||||
if (!empty($site_icon_url)) {
|
||||
$content = file_get_contents($site_icon_url);
|
||||
|
||||
$mime_type = '';
|
||||
foreach ($http_response_header as $value) {
|
||||
if (false !== stripos($value, 'content-type:')) {
|
||||
list(, $mime_type) = explode(':', preg_replace('/\s+/', '', $value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($content && !empty($mime_type)) {
|
||||
$site_icon = 'data: '.$mime_type.';base64,'.base64_encode($content);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response(array('site_icon' => $site_icon));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a list of submitted commands (multiplexer)
|
||||
*
|
||||
* @param Array $query An array containing the commands to execute and a flag to indicate how to handle command execution failure.
|
||||
* @return Array An array containing the results of the process.
|
||||
*/
|
||||
public function execute_commands($query) {
|
||||
|
||||
try {
|
||||
|
||||
$commands = $query['commands'];
|
||||
$command_results = array();
|
||||
$error_count = 0;
|
||||
|
||||
/**
|
||||
* Should be one of the following options:
|
||||
* 1 = Abort on first failure
|
||||
* 2 = Abort if any command fails
|
||||
* 3 = Abort if all command fails (default)
|
||||
*/
|
||||
$error_flag = isset($query['error_flag']) ? (int) $query['error_flag'] : 3;
|
||||
|
||||
|
||||
foreach ($commands as $command => $params) {
|
||||
$command_info = apply_filters('updraftcentral_get_command_info', false, $command);
|
||||
if (!$command_info) {
|
||||
list($_prefix, $_command) = explode('.', $command);
|
||||
$command_results[$_prefix][$_command] = array('response' => 'rpcerror', 'data' => array('code' => 'unknown_rpc_command', 'data' => $command));
|
||||
|
||||
$error_count++;
|
||||
if (1 === $error_flag) break;
|
||||
} else {
|
||||
|
||||
$action = $command_info['command'];
|
||||
$command_php_class = $command_info['command_php_class'];
|
||||
|
||||
// Instantiate the command class and execute the needed action
|
||||
if (class_exists($command_php_class)) {
|
||||
$instance = new $command_php_class($this->rc);
|
||||
|
||||
if (method_exists($instance, $action)) {
|
||||
$params = empty($params) ? array() : $params;
|
||||
$call_result = call_user_func(array($instance, $action), $params);
|
||||
|
||||
$command_results[$command] = $call_result;
|
||||
if ('rpcerror' === $call_result['response'] || (isset($call_result['data']['error']) && $call_result['data']['error'])) {
|
||||
$error_count++;
|
||||
if (1 === $error_flag) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 !== $error_count) {
|
||||
// N.B. These error messages should be defined in UpdraftCentral's translation file (dashboard-translations.php)
|
||||
// before actually using this multiplexer function.
|
||||
$message = 'general_command_execution_error';
|
||||
|
||||
switch ($error_flag) {
|
||||
case 1:
|
||||
$message = 'command_execution_aborted';
|
||||
break;
|
||||
case 2:
|
||||
$message = 'failed_to_execute_some_commands';
|
||||
break;
|
||||
case 3:
|
||||
if (count($commands) === $error_count) {
|
||||
$message = 'failed_to_execute_all_commands';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$result = array('error' => true, 'message' => $message, 'values' => $command_results);
|
||||
} else {
|
||||
$result = $command_results;
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the credentials entered by the user
|
||||
*
|
||||
* @param array $creds an array of filesystem credentials
|
||||
* @return array An array containing the result of the validation process.
|
||||
*/
|
||||
public function validate_credentials($creds) {
|
||||
|
||||
try {
|
||||
|
||||
$entity = $creds['entity'];
|
||||
if (isset($creds['filesystem_credentials'])) {
|
||||
parse_str($creds['filesystem_credentials'], $filesystem_credentials);
|
||||
if (is_array($filesystem_credentials)) {
|
||||
foreach ($filesystem_credentials as $key => $value) {
|
||||
// Put them into $_POST, which is where request_filesystem_credentials() checks for them.
|
||||
$_POST[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Include the needed WP Core file(s)
|
||||
// template.php needed for submit_button() which is called by request_filesystem_credentials()
|
||||
$this->_admin_include('file.php', 'template.php');
|
||||
|
||||
// Directory entities that we currently need permissions
|
||||
// to update.
|
||||
$entity_directories = array(
|
||||
'plugins' => WP_PLUGIN_DIR,
|
||||
'themes' => WP_CONTENT_DIR.'/themes',
|
||||
'core' => untrailingslashit(ABSPATH)
|
||||
);
|
||||
|
||||
if ('translations' === $entity) {
|
||||
// 'en_US' don't usually have the "languages" folder, thus, we
|
||||
// check if there's a need to ask for filesystem credentials for that
|
||||
// folder if it exists, most especially for locale other than 'en_US'.
|
||||
$language_dir = WP_CONTENT_DIR.'/languages';
|
||||
if ('en_US' !== get_locale() && is_dir($language_dir)) {
|
||||
$entity_directories['translations'] = $language_dir;
|
||||
}
|
||||
}
|
||||
|
||||
$url = wp_nonce_url(site_url());
|
||||
|
||||
$passed = false;
|
||||
if (isset($entity_directories[$entity])) {
|
||||
$directory = $entity_directories[$entity];
|
||||
|
||||
// Check if credentials are valid and have sufficient
|
||||
// privileges to create and delete (e.g. write)
|
||||
ob_start();
|
||||
$credentials = request_filesystem_credentials($url, '', false, $directory);
|
||||
ob_end_clean();
|
||||
|
||||
// The "WP_Filesystem" will suffice in validating the inputted credentials
|
||||
// from UpdraftCentral, as it is already attempting to connect to the filesystem
|
||||
// using the chosen transport (e.g. ssh, ftp, etc.)
|
||||
$passed = WP_Filesystem($credentials, $directory);
|
||||
}
|
||||
|
||||
if ($passed) {
|
||||
$result = array('error' => false, 'message' => 'credentials_ok', 'values' => array());
|
||||
} else {
|
||||
// We're adding some useful error information to help troubleshooting any problems
|
||||
// that may arise in the future. If the user submitted a wrong password or username
|
||||
// it usually falls through here.
|
||||
global $wp_filesystem;
|
||||
|
||||
$errors = array();
|
||||
if (isset($wp_filesystem->errors) && is_wp_error($wp_filesystem->errors)) {
|
||||
$errors = $wp_filesystem->errors->errors;
|
||||
}
|
||||
|
||||
$result = array('error' => true, 'message' => 'failed_credentials', 'values' => array('errors' => $errors));
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => $e->getMessage(), 'values' => array());
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the FileSystem Credentials
|
||||
*
|
||||
* Extract the needed filesystem credentials (permissions) to be used
|
||||
* to update/upgrade the plugins, themes and the WP core.
|
||||
*
|
||||
* @return array $result - An array containing the creds form and some flags
|
||||
* to determine whether we need to extract the creds
|
||||
* manually from the user.
|
||||
*/
|
||||
public function get_credentials() {
|
||||
|
||||
try {
|
||||
|
||||
// Check whether user has enough permission to update entities
|
||||
if (!current_user_can('update_plugins') && !current_user_can('update_themes') && !current_user_can('update_core')) return $this->_generic_error_response('updates_permission_denied');
|
||||
|
||||
// Include the needed WP Core file(s)
|
||||
$this->_admin_include('file.php', 'template.php');
|
||||
|
||||
// A container that will hold the state (in this case, either true or false) of
|
||||
// each directory entities (plugins, themes, core) that will be used to determine
|
||||
// whether or not there's a need to show a form that will ask the user for their credentials
|
||||
// manually.
|
||||
$request_filesystem_credentials = array();
|
||||
|
||||
// A container for the filesystem credentials form if applicable.
|
||||
$filesystem_form = '';
|
||||
|
||||
// Directory entities that we currently need permissions
|
||||
// to update.
|
||||
$check_fs = array(
|
||||
'plugins' => WP_PLUGIN_DIR,
|
||||
'themes' => WP_CONTENT_DIR.'/themes',
|
||||
'core' => untrailingslashit(ABSPATH)
|
||||
);
|
||||
|
||||
// Here, we're looping through each entities and find output whether
|
||||
// we have sufficient permissions to update objects belonging to them.
|
||||
foreach ($check_fs as $entity => $dir) {
|
||||
|
||||
// We're determining which method to use when updating
|
||||
// the files in the filesystem.
|
||||
$filesystem_method = get_filesystem_method(array(), $dir);
|
||||
|
||||
// Buffering the output to pull the actual credentials form
|
||||
// currently being used by this WP instance if no sufficient permissions
|
||||
// is found.
|
||||
$url = wp_nonce_url(site_url());
|
||||
|
||||
ob_start();
|
||||
$filesystem_credentials_are_stored = request_filesystem_credentials($url, $filesystem_method);
|
||||
$form = strip_tags(ob_get_contents(), '<div><h2><p><input><label><fieldset><legend><span><em>');
|
||||
|
||||
if (!empty($form)) {
|
||||
$filesystem_form = $form;
|
||||
}
|
||||
ob_end_clean();
|
||||
|
||||
// Save the state whether or not there's a need to show the
|
||||
// credentials form to the user.
|
||||
$request_filesystem_credentials[$entity] = ('direct' !== $filesystem_method && !$filesystem_credentials_are_stored);
|
||||
}
|
||||
|
||||
// Wrapping the credentials info before passing it back
|
||||
// to the client issuing the request.
|
||||
$result = array(
|
||||
'request_filesystem_credentials' => $request_filesystem_credentials,
|
||||
'filesystem_form' => $filesystem_form
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$result = array('error' => true, 'message' => $e->getMessage(), 'values' => array());
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a browser-usable URL which will automatically log the user in to the site
|
||||
*
|
||||
* @param String $redirect_to - the URL to got to after logging in
|
||||
* @param Array $extra_info - valid keys are user_id, which should be a numeric user ID to log in as.
|
||||
*/
|
||||
public function get_login_url($redirect_to, $extra_info) {
|
||||
|
||||
if (is_array($extra_info) && !empty($extra_info['user_id']) && is_numeric($extra_info['user_id'])) {
|
||||
|
||||
$user_id = $extra_info['user_id'];
|
||||
|
||||
if (false == ($login_key = $this->_get_autologin_key($user_id))) return $this->_generic_error_response('user_key_failure');
|
||||
|
||||
// Default value
|
||||
$redirect_url = network_admin_url();
|
||||
if (is_array($redirect_to) && !empty($redirect_to['module'])) {
|
||||
switch ($redirect_to['module']) {
|
||||
case 'updraftplus':
|
||||
if ('initiate_restore' == $redirect_to['action'] && class_exists('UpdraftPlus_Options')) {
|
||||
$redirect_url = UpdraftPlus_Options::admin_page_url().'?page=updraftplus&udaction=initiate_restore&entities='.urlencode($redirect_to['data']['entities']).'&showdata='.urlencode($redirect_to['data']['showdata']).'&backup_timestamp='.(int) $redirect_to['data']['backup_timestamp'];
|
||||
|
||||
} elseif ('download_file' == $redirect_to['action']) {
|
||||
$findex = empty($redirect_to['data']['findex']) ? 0 : (int) $redirect_to['data']['findex'];
|
||||
// e.g. ?udcentral_action=dl&action=updraftplus_spool_file&backup_timestamp=1455101696&findex=0&what=plugins
|
||||
$redirect_url = site_url().'?udcentral_action=spool_file&action=updraftplus_spool_file&findex='.$findex.'&what='.urlencode($redirect_to['data']['what']).'&backup_timestamp='.(int) $redirect_to['data']['backup_timestamp'];
|
||||
}
|
||||
break;
|
||||
case 'direct_url':
|
||||
$redirect_url = $redirect_to['url'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$login_key = apply_filters('updraftplus_remotecontrol_login_key', array(
|
||||
'key' => $login_key,
|
||||
'created' => time(),
|
||||
'redirect_url' => $redirect_url
|
||||
), $redirect_to, $extra_info);
|
||||
|
||||
// Over-write any previous value - only one can be valid at a time)
|
||||
update_user_meta($user_id, 'updraftcentral_login_key', $login_key);
|
||||
|
||||
return $this->_response(array(
|
||||
'login_url' => network_site_url('?udcentral_action=login&login_id='.$user_id.'&login_key='.$login_key['key'])
|
||||
));
|
||||
|
||||
} else {
|
||||
return $this->_generic_error_response('user_unknown');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information derived from phpinfo()
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public function phpinfo() {
|
||||
$phpinfo = $this->_get_phpinfo_array();
|
||||
|
||||
if (!empty($phpinfo)) {
|
||||
return $this->_response($phpinfo);
|
||||
}
|
||||
|
||||
return $this->_generic_error_response('phpinfo_fail');
|
||||
}
|
||||
|
||||
/**
|
||||
* The key obtained is only intended to be short-lived. Hence, there's no intention other than that it is random and only used once - only the most recent one is valid.
|
||||
*
|
||||
* @param Integer $user_id Specific user ID to get the autologin key
|
||||
* @return Array
|
||||
*/
|
||||
public function _get_autologin_key($user_id) {
|
||||
$secure_auth_key = defined('SECURE_AUTH_KEY') ? SECURE_AUTH_KEY : hash('sha256', DB_PASSWORD).'_'.rand(0, 999999999);
|
||||
if (!defined('SECURE_AUTH_KEY')) return false;
|
||||
$hash_it = $user_id.'_'.microtime(true).'_'.rand(0, 999999999).'_'.$secure_auth_key;
|
||||
$hash = hash('sha256', $hash_it);
|
||||
return $hash;
|
||||
}
|
||||
|
||||
public function site_info() {
|
||||
global $wpdb;
|
||||
|
||||
// THis is included so we can get $wp_version
|
||||
@include(ABSPATH.WPINC.'/version.php');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
|
||||
|
||||
$ud_version = is_a($this->ud, 'UpdraftPlus') ? $this->ud->version : 'none';
|
||||
|
||||
return $this->_response(array(
|
||||
'versions' => array(
|
||||
'ud' => $ud_version,
|
||||
'php' => PHP_VERSION,
|
||||
'wp' => $wp_version,// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
|
||||
'mysql' => $wpdb->db_version(),
|
||||
'udrpc_php' => $this->rc->udrpc_version,
|
||||
),
|
||||
'bloginfo' => array(
|
||||
'url' => network_site_url(),
|
||||
'name' => get_bloginfo('name'),
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* This calls the WP_Action within WP
|
||||
*
|
||||
* @param array $data Array of Data to be used within call_wp_action
|
||||
* @return array
|
||||
*/
|
||||
public function call_wordpress_action($data) {
|
||||
if (false === ($updraftplus_admin = $this->_load_ud_admin())) return $this->_generic_error_response('no_updraftplus');
|
||||
$response = $updraftplus_admin->call_wp_action($data);
|
||||
|
||||
if (empty($data["wpaction"])) {
|
||||
return $this->_generic_error_response("error", "no command sent");
|
||||
}
|
||||
|
||||
return $this->_response(array(
|
||||
"response" => $response['response'],
|
||||
"status" => $response['status'],
|
||||
"log" => $response['log']
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get disk space used
|
||||
*
|
||||
* @uses UpdraftPlus_Filesystem_Functions::get_disk_space_used()
|
||||
*
|
||||
* @param String $entity - the entity to count (e.g. 'plugins', 'themes')
|
||||
*
|
||||
* @return Array - response
|
||||
*/
|
||||
public function count($entity) {
|
||||
if (!class_exists('UpdraftPlus_Filesystem_Functions')) return $this->_generic_error_response('no_updraftplus');
|
||||
$response = UpdraftPlus_Filesystem_Functions::get_disk_space_used($entity);
|
||||
|
||||
return $this->_response($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* https://secure.php.net/phpinfo
|
||||
*
|
||||
* @return null|array
|
||||
*/
|
||||
private function _get_phpinfo_array() {
|
||||
if (!function_exists('phpinfo')) return null;
|
||||
ob_start();
|
||||
phpinfo(INFO_GENERAL|INFO_CREDITS|INFO_MODULES);
|
||||
$phpinfo = array('phpinfo' => array());
|
||||
|
||||
if (preg_match_all('#(?:<h2>(?:<a name=".*?">)?(.*?)(?:</a>)?</h2>)|(?:<tr(?: class=".*?")?><t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>)?)?</tr>)#s', ob_get_clean(), $matches, PREG_SET_ORDER)) {
|
||||
foreach ($matches as $match) {
|
||||
if (strlen($match[1])) {
|
||||
$phpinfo[$match[1]] = array();
|
||||
} elseif (isset($match[3])) {
|
||||
$keys1 = array_keys($phpinfo);
|
||||
$phpinfo[end($keys1)][$match[2]] = isset($match[4]) ? array($match[3], $match[4]) : $match[3];
|
||||
} else {
|
||||
$keys1 = array_keys($phpinfo);
|
||||
$phpinfo[end($keys1)][] = $match[2];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return $phpinfo;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an UpdraftPlus_Admin object
|
||||
*
|
||||
* @return UpdraftPlus_Admin|Boolean - false in case of failure
|
||||
*/
|
||||
private function _load_ud_admin() {
|
||||
if (!defined('UPDRAFTPLUS_DIR') || !is_file(UPDRAFTPLUS_DIR.'/admin.php')) return false;
|
||||
updraft_try_include_file('admin.php', 'include_once');
|
||||
global $updraftplus_admin;
|
||||
return $updraftplus_admin;
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+601
@@ -0,0 +1,601 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles Media Commands
|
||||
*/
|
||||
class UpdraftCentral_Media_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
private $switched = false;
|
||||
|
||||
/**
|
||||
* Function that gets called before every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _pre_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- This function is called from listener.php and $extra_info is being sent.
|
||||
// Here we assign the current blog_id to a variable $blog_id
|
||||
$blog_id = get_current_blog_id();
|
||||
if (!empty($data['site_id'])) $blog_id = $data['site_id'];
|
||||
|
||||
if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
|
||||
$this->switched = switch_to_blog($blog_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that gets called after every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _post_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the caller from UpdraftCentral_Listener class uses 3 arguments.
|
||||
// Here, we're restoring to the current (default) blog before we switched
|
||||
if ($this->switched) restore_current_blog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and retrieves posts based from the submitted parameters
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function get_media_items($params) {
|
||||
$error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
// check paged parameter; if empty set to defaults
|
||||
$paged = !empty($params['paged']) ? (int) $params['paged'] : 1;
|
||||
$numberposts = !empty($params['numberposts']) ? (int) $params['numberposts'] : 10;
|
||||
$offset = ($paged - 1) * $numberposts;
|
||||
|
||||
$args = array(
|
||||
'posts_per_page' => $numberposts,
|
||||
'paged' => $paged,
|
||||
'offset' => $offset,
|
||||
'post_type' => 'attachment',
|
||||
'post_status' => 'inherit',
|
||||
);
|
||||
|
||||
if (!empty($params['keyword'])) {
|
||||
$args['s'] = $params['keyword'];
|
||||
}
|
||||
|
||||
if (!empty($params['category'])) {
|
||||
if (in_array($params['category'], array('detached', 'unattached'))) {
|
||||
$attachment_ids = $this->get_unattached_ids();
|
||||
} else {
|
||||
$attachment_ids = $this->get_type_ids($params['category']);
|
||||
}
|
||||
|
||||
$args['post__in'] = $attachment_ids;
|
||||
}
|
||||
|
||||
if (!empty($params['date'])) {
|
||||
list($monthnum, $year) = explode(':', $params['date']);
|
||||
|
||||
$args['monthnum'] = $monthnum;
|
||||
$args['year'] = $year;
|
||||
}
|
||||
|
||||
$query = new WP_Query($args);
|
||||
$result = $query->posts;
|
||||
|
||||
$count_posts = (int) $query->found_posts;
|
||||
$page_count = 0;
|
||||
|
||||
if ($count_posts > 0) {
|
||||
$page_count = absint($count_posts / $numberposts);
|
||||
$remainder = absint($count_posts % $numberposts);
|
||||
$page_count = ($remainder > 0) ? ++$page_count : $page_count;
|
||||
}
|
||||
|
||||
$info = array(
|
||||
'page' => $paged,
|
||||
'pages' => $page_count,
|
||||
'results' => $count_posts,
|
||||
'items_from' => (($paged * $numberposts) - $numberposts) + 1,
|
||||
'items_to' => ($paged == $page_count) ? $count_posts : $paged * $numberposts,
|
||||
);
|
||||
|
||||
$media_items = array();
|
||||
if (!empty($result)) {
|
||||
foreach ($result as $item) {
|
||||
$media = $this->get_media_item($item, null, true);
|
||||
if (!empty($media)) {
|
||||
array_push($media_items, $media);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'items' => $media_items,
|
||||
'info' => $info,
|
||||
'options' => array(
|
||||
'date' => $this->get_date_options(),
|
||||
'type' => $this->get_type_options()
|
||||
)
|
||||
);
|
||||
|
||||
return $this->_response($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we have an image editor (e.g. GD, Imagick, etc.) set in place to handle the basic editing
|
||||
* functions such as rotate, crop, etc. If not, then we hide that feature in UpdraftCentral
|
||||
*
|
||||
* @param object $media The media item/object to check
|
||||
* @return boolean
|
||||
*/
|
||||
private function has_image_editor($media) {
|
||||
// Most of the time image library are enabled by default in the php.ini but there's a possbility that users don't
|
||||
// enable them as they have no need for them at the moment or for some other reasons. Thus, we need to confirm
|
||||
// that here through the wp_get_image_editor method.
|
||||
$has_image_editor = true;
|
||||
if (!empty($media)) {
|
||||
if (!function_exists('wp_get_image_editor')) {
|
||||
require_once(ABSPATH.'wp-includes/media.php');
|
||||
}
|
||||
|
||||
if (!function_exists('_load_image_to_edit_path')) {
|
||||
require_once(ABSPATH.'wp-admin/includes/image.php');
|
||||
}
|
||||
|
||||
$image_editor = wp_get_image_editor(_load_image_to_edit_path($media->ID));
|
||||
if (is_wp_error($image_editor)) {
|
||||
$has_image_editor = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $has_image_editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a single media item information
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @param array|null $extra_info Additional information from the current request
|
||||
* @param boolean $raw If set, returns the result of the fetch process unwrapped by the response array
|
||||
* @return array
|
||||
*/
|
||||
public function get_media_item($params, $extra_info = null, $raw = false) {
|
||||
$error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
// Raw means that we need to return the result without wrapping it
|
||||
// with the "$this->_response" function which indicates that the call
|
||||
// was done locally (within the class) and not directly from UpdraftCentral.
|
||||
if ($raw && is_object($params) && isset($params->ID)) {
|
||||
$media = $params;
|
||||
} elseif (is_array($params) && !empty($params['id'])) {
|
||||
$media = get_post($params['id']);
|
||||
}
|
||||
|
||||
if (!function_exists('get_post_mime_types')) {
|
||||
global $updraftcentral_main;
|
||||
|
||||
// For a much later version of WP the "get_post_mime_types" is located
|
||||
// in a different folder. So, we make sure that we have it loaded before
|
||||
// actually using it.
|
||||
if (version_compare($updraftcentral_main->get_wordpress_version(), '3.5', '>=')) {
|
||||
require_once(ABSPATH.WPINC.'/post.php');
|
||||
} else {
|
||||
// For WP 3.4, the "get_post_mime_types" is located in the location provided below.
|
||||
require_once(ABSPATH.'wp-admin/includes/post.php');
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('wp_image_editor')) {
|
||||
require_once(ABSPATH.'wp-admin/includes/image-edit.php');
|
||||
}
|
||||
|
||||
if (!function_exists('get_media_item')) {
|
||||
require_once(ABSPATH.'wp-admin/includes/template.php');
|
||||
require_once(ABSPATH.'wp-admin/includes/media.php');
|
||||
}
|
||||
|
||||
|
||||
if ($media) {
|
||||
$thumb = wp_get_attachment_image_src($media->ID, 'thumbnail', true);
|
||||
if (!empty($thumb)) $media->thumb_url = $thumb[0];
|
||||
|
||||
$media->url = wp_get_attachment_url($media->ID);
|
||||
$media->parent_post_title = get_the_title($media->post_parent);
|
||||
$media->author = get_the_author_meta('display_name', $media->post_author);
|
||||
$media->filename = basename($media->url);
|
||||
$media->date = date('Y/m/d', strtotime($media->post_date));
|
||||
$media->upload_date = mysql2date(get_option('date_format'), $media->post_date);
|
||||
|
||||
$media->filesize = 0;
|
||||
$file = get_attached_file($media->ID);
|
||||
if (!empty($file) && file_exists($file)) {
|
||||
$media->filesize = size_format(filesize($file));
|
||||
}
|
||||
|
||||
$media->nonce = wp_create_nonce('image_editor-'.$media->ID);
|
||||
if (false !== strpos($media->post_mime_type, 'image/')) {
|
||||
$meta = wp_get_attachment_metadata($media->ID);
|
||||
|
||||
$thumb = image_get_intermediate_size($media->ID, 'thumbnail');
|
||||
$sub_sizes = isset($meta['sizes']) && is_array($meta['sizes']);
|
||||
|
||||
// Pulling details
|
||||
$sizer = 1;
|
||||
if (isset($meta['width'], $meta['height'])) {
|
||||
$big = max($meta['width'], $meta['height']);
|
||||
$sizer = $big > 400 ? 400 / $big : 1;
|
||||
}
|
||||
|
||||
$constrained_dims = array();
|
||||
if ($thumb && $sub_sizes) {
|
||||
$constrained_dims = wp_constrain_dimensions($thumb['width'], $thumb['height'], 160, 120);
|
||||
}
|
||||
|
||||
$rotate_supported = false;
|
||||
if (function_exists('imagerotate') || wp_image_editor_supports(array('mime_type' => get_post_mime_type($media->ID), 'methods' => array('rotate')))) {
|
||||
$rotate_supported = true;
|
||||
}
|
||||
|
||||
// Check for alternative text if present
|
||||
$alt = get_post_meta($media->ID, '_wp_attachment_image_alt', true);
|
||||
$media->alt = !empty($alt) ? $alt : '';
|
||||
|
||||
// Check whether edited images are restorable
|
||||
$backup_sizes = get_post_meta($media->ID, '_wp_attachment_backup_sizes', true);
|
||||
$can_restore = !empty($backup_sizes) && isset($backup_sizes['full-orig']) && basename($meta['file']) != $backup_sizes['full-orig']['file'];
|
||||
|
||||
$image_edit_overwrite = (!defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE) ? 0 : 1;
|
||||
$media->misc = array(
|
||||
'sizer' => $sizer,
|
||||
'rand' => rand(1, 99999),
|
||||
'constrained_dims' => $constrained_dims,
|
||||
'rotate_supported' => (int) $rotate_supported,
|
||||
'thumb' => $thumb,
|
||||
'meta' => $meta,
|
||||
'alt_text' => $alt,
|
||||
'can_restore' => $can_restore,
|
||||
'image_edit_overwrite' => $image_edit_overwrite
|
||||
);
|
||||
|
||||
$media->has_image_editor = $this->has_image_editor($media);
|
||||
}
|
||||
}
|
||||
|
||||
return $raw ? $media : $this->_response(array('item' => $media));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and retrieves posts based from the submitted parameters
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function get_posts($params) {
|
||||
$error = $this->_validate_capabilities(array('edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
// check paged parameter; if empty set to defaults
|
||||
$paged = !empty($params['paged']) ? (int) $params['paged'] : 1;
|
||||
$numberposts = !empty($params['numberposts']) ? (int) $params['numberposts'] : 10;
|
||||
$offset = ($paged - 1) * $numberposts;
|
||||
|
||||
$args = array(
|
||||
'posts_per_page' => $numberposts,
|
||||
'paged' => $paged,
|
||||
'offset' => $offset,
|
||||
'post_type' => 'post',
|
||||
'post_status' => 'publish,private,draft,pending,future',
|
||||
);
|
||||
|
||||
if (!empty($params['keyword'])) {
|
||||
$args['s'] = $params['keyword'];
|
||||
}
|
||||
|
||||
$query = new WP_Query($args);
|
||||
$result = $query->posts;
|
||||
|
||||
$count_posts = (int) $query->found_posts;
|
||||
$page_count = 0;
|
||||
|
||||
if ($count_posts > 0) {
|
||||
$page_count = absint($count_posts / $numberposts);
|
||||
$remainder = absint($count_posts % $numberposts);
|
||||
$page_count = ($remainder > 0) ? ++$page_count : $page_count;
|
||||
}
|
||||
|
||||
$info = array(
|
||||
'page' => $paged,
|
||||
'pages' => $page_count,
|
||||
'results' => $count_posts,
|
||||
'items_from' => (($paged * $numberposts) - $numberposts) + 1,
|
||||
'items_to' => ($paged == $page_count) ? $count_posts : $paged * $numberposts,
|
||||
);
|
||||
|
||||
$posts = array();
|
||||
if (!empty($result)) {
|
||||
foreach ($result as $post) {
|
||||
array_push($posts, array('ID' => $post->ID, 'title' => $post->post_title));
|
||||
}
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'posts' => $posts,
|
||||
'info' => $info
|
||||
);
|
||||
return $this->_response($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves media changes from UpdraftCentral
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function save_media_item($params) {
|
||||
$error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
$args = array(
|
||||
'post_title' => $params['image_title'],
|
||||
'post_excerpt' => $params['image_caption'],
|
||||
'post_content' => $params['image_description']
|
||||
);
|
||||
|
||||
if (!empty($params['new'])) {
|
||||
$args['post_type'] = 'attachment';
|
||||
$media_id = wp_insert_post($args, true);
|
||||
} else {
|
||||
$args['ID'] = $params['id'];
|
||||
$args['post_modified'] = date('Y-m-d H:i:s');
|
||||
$args['post_modified_gmt'] = gmdate('Y-m-d H:i:s');
|
||||
|
||||
$media_id = wp_update_post($args, true);
|
||||
}
|
||||
|
||||
if (!empty($media_id)) {
|
||||
// Update alternative text if not empty
|
||||
if (!empty($params['image_alternative_text'])) {
|
||||
update_post_meta($media_id, '_wp_attachment_image_alt', $params['image_alternative_text']);
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'status' => 'success',
|
||||
'item' => $this->get_media_item(array('id' => $media_id), null, true)
|
||||
);
|
||||
} else {
|
||||
$result = array('status' => 'failed');
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes media action (e.g. attach, detach and delete)
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function execute_media_action($params) {
|
||||
global $updraftcentral_host_plugin;
|
||||
|
||||
$error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
$result = array();
|
||||
switch ($params['do']) {
|
||||
case 'attach':
|
||||
global $wpdb;
|
||||
$query_result = $wpdb->query($wpdb->prepare("UPDATE {$wpdb->posts} SET `post_parent` = %d WHERE `post_type` = 'attachment' AND ID = %d", $params['parent_id'], $params['id']));
|
||||
|
||||
if (false === $query_result) {
|
||||
$result['error'] = $updraftcentral_host_plugin->retrieve_show_message('failed_to_attach_media');
|
||||
} else {
|
||||
$result['msg'] = $updraftcentral_host_plugin->retrieve_show_message('media_attached');
|
||||
}
|
||||
break;
|
||||
case 'detach':
|
||||
global $wpdb;
|
||||
$query_result = $wpdb->query($wpdb->prepare("UPDATE {$wpdb->posts} SET `post_parent` = 0 WHERE `post_type` = 'attachment' AND ID = %d", $params['id']));
|
||||
|
||||
if (false === $query_result) {
|
||||
$result['error'] = $updraftcentral_host_plugin->retrieve_show_message('failed_to_detach_media');
|
||||
} else {
|
||||
$result['msg'] = $updraftcentral_host_plugin->retrieve_show_message('media_detached');
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
$failed_items = array();
|
||||
foreach ($params['ids'] as $id) {
|
||||
// Delete permanently
|
||||
if (false === wp_delete_attachment($id, true)) {
|
||||
$failed_items[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($failed_items)) {
|
||||
$result['error'] = $updraftcentral_host_plugin->retrieve_show_message('failed_to_delete_media');
|
||||
$result['items'] = $failed_items;
|
||||
} else {
|
||||
$result['msg'] = $updraftcentral_host_plugin->retrieve_show_message('selected_media_deleted');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a collection of formatted dates found for the given post statuses.
|
||||
* It will be used as options for the date filter when managing the media items in UpdraftCentral.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_date_options() {
|
||||
global $wpdb;
|
||||
$options = array();
|
||||
|
||||
$date_options = $wpdb->get_col("SELECT DATE_FORMAT(`post_date`, '%M %Y') as `formatted_post_date` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' GROUP BY `formatted_post_date` ORDER BY `post_date` DESC");
|
||||
|
||||
if (!empty($date_options)) {
|
||||
foreach ($date_options as $monthyear) {
|
||||
$timestr = strtotime($monthyear);
|
||||
$options[] = array('label' => date('F Y', $timestr), 'value' => date('n:Y', $timestr));
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves mime types that will be use as filter option in UpdraftCentral
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_type_options() {
|
||||
global $wpdb, $updraftcentral_host_plugin, $updraftcentral_main;
|
||||
|
||||
$options = array();
|
||||
if (!function_exists('get_post_mime_types')) {
|
||||
// For a much later version of WP the "get_post_mime_types" is located
|
||||
// in a different folder. So, we make sure that we have it loaded before
|
||||
// actually using it.
|
||||
if (version_compare($updraftcentral_main->get_wordpress_version(), '3.5', '>=')) {
|
||||
require_once(ABSPATH.WPINC.'/post.php');
|
||||
} else {
|
||||
// For WP 3.4, the "get_post_mime_types" is located in the location provided below.
|
||||
require_once(ABSPATH.'wp-admin/includes/post.php');
|
||||
}
|
||||
}
|
||||
|
||||
$post_mime_types = get_post_mime_types();
|
||||
$type_options = $wpdb->get_col("SELECT `post_mime_type` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' GROUP BY `post_mime_type` ORDER BY `post_mime_type` DESC");
|
||||
|
||||
foreach ($post_mime_types as $mime_type => $label) {
|
||||
if (!wp_match_mime_types($mime_type, $type_options)) continue;
|
||||
$options[] = array('label' => $label[0], 'value' => esc_attr($mime_type));
|
||||
}
|
||||
|
||||
$options[] = array('label' => $updraftcentral_host_plugin->retrieve_show_message('unattached'), 'value' => 'detached');
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves media items that haven't been attached to any posts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_unattached_ids() {
|
||||
global $wpdb;
|
||||
return $wpdb->get_col("SELECT `ID` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' AND `post_parent` = '0'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves IDs of media items that has the given mime type
|
||||
*
|
||||
* @param string $type The mime type to search for
|
||||
* @return array
|
||||
*/
|
||||
private function get_type_ids($type) {
|
||||
global $wpdb;
|
||||
return $wpdb->get_col($wpdb->prepare("SELECT `ID` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' AND `post_mime_type` LIKE %s", $type.'/%'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we have the required fields submitted and the user has
|
||||
* the capabilities to execute the requested action
|
||||
*
|
||||
* @param array $capabilities The capabilities to check and validate
|
||||
*
|
||||
* @return array|void
|
||||
*/
|
||||
private function _validate_capabilities($capabilities) {
|
||||
foreach ($capabilities as $capability) {
|
||||
if (!current_user_can($capability)) {
|
||||
return $this->_generic_error_response('insufficient_permission');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the $_REQUEST global variable with the submitted data
|
||||
*
|
||||
* @param array $params Submitted data received from UpdraftCentral
|
||||
* @return array
|
||||
*/
|
||||
private function populate_request($params) {
|
||||
if (!empty($params)) {
|
||||
foreach ($params as $key => $value) {
|
||||
$_REQUEST[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles image editing requests coming from UpdraftCentral
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function image_editor($params) {
|
||||
$error = $this->_validate_capabilities(array('edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
$attachment_id = (int) $params['postid'];
|
||||
$this->populate_request($params);
|
||||
|
||||
if (!function_exists('load_image_to_edit')) {
|
||||
require_once(ABSPATH.'wp-admin/includes/image.php');
|
||||
}
|
||||
|
||||
include_once(ABSPATH.'wp-admin/includes/image-edit.php');
|
||||
$msg = false;
|
||||
switch ($params['do']) {
|
||||
case 'save':
|
||||
case 'scale':
|
||||
$msg = wp_save_image($attachment_id);
|
||||
break;
|
||||
case 'restore':
|
||||
$msg = wp_restore_image($attachment_id);
|
||||
break;
|
||||
}
|
||||
|
||||
$msg = (false !== $msg) ? json_encode($msg) : $msg;
|
||||
return $this->_response(array('content' => $msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles image preview requests coming from UpdraftCentral
|
||||
*
|
||||
* @param array $params Containing all the needed information to filter the results of the current request
|
||||
* @return array
|
||||
*/
|
||||
public function image_preview($params) {
|
||||
$error = $this->_validate_capabilities(array('edit_posts'));
|
||||
if (!empty($error)) return $error;
|
||||
|
||||
if (!function_exists('load_image_to_edit')) {
|
||||
require_once(ABSPATH.'wp-admin/includes/image.php');
|
||||
}
|
||||
|
||||
include_once(ABSPATH.'wp-admin/includes/image-edit.php');
|
||||
$this->populate_request($params);
|
||||
$post_id = (int) $params['postid'];
|
||||
|
||||
ob_start();
|
||||
stream_preview_image($post_id);
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $this->_response(array('content' => base64_encode($content)));
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+15
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
// Load the posts command class since we're going to be extending it for our page module service/command
|
||||
// class in order to minimize redundant shareable methods.
|
||||
if (!class_exists('UpdraftCentral_Posts_Commands')) require_once('posts.php');
|
||||
|
||||
/**
|
||||
* Handles Pages Commands
|
||||
*/
|
||||
class UpdraftCentral_Pages_Commands extends UpdraftCentral_Posts_Commands {
|
||||
|
||||
protected $post_type = 'page';
|
||||
}
|
||||
Vendored
Executable
+700
@@ -0,0 +1,700 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles UpdraftCentral Plugin Commands which basically handles
|
||||
* the installation and activation of a plugin
|
||||
*/
|
||||
class UpdraftCentral_Plugin_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
private $switched = false;
|
||||
|
||||
/**
|
||||
* Function that gets called before every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _pre_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- This function is called from listener.php and $extra_info is being sent.
|
||||
// Here we assign the current blog_id to a variable $blog_id
|
||||
$blog_id = get_current_blog_id();
|
||||
if (!empty($data['site_id'])) $blog_id = $data['site_id'];
|
||||
|
||||
if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
|
||||
$this->switched = switch_to_blog($blog_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that gets called after every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _post_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the caller from UpdraftCentral_Listener class uses 3 arguments.
|
||||
// Here, we're restoring to the current (default) blog before we switched
|
||||
if ($this->switched) restore_current_blog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->_admin_include('plugin.php', 'file.php', 'template.php', 'class-wp-upgrader.php', 'plugin-install.php', 'update.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs and activates a plugin through upload
|
||||
*
|
||||
* @param array $params Parameter array containing information pertaining the currently uploaded plugin
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function upload_plugin($params) {
|
||||
return $this->process_chunk_upload($params, 'plugin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the plugin is currently installed and activated.
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the plugin to check
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function is_plugin_installed($query) {
|
||||
|
||||
if (!isset($query['plugin']))
|
||||
return $this->_generic_error_response('plugin_name_required');
|
||||
|
||||
|
||||
$result = $this->_get_plugin_info($query);
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies currently requested action for plugin processing
|
||||
*
|
||||
* @param string $action The action to apply (e.g. activate or install)
|
||||
* @param array $query Parameter array containing information for the currently requested action
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _apply_plugin_action($action, $query) {
|
||||
|
||||
$result = array();
|
||||
switch ($action) {
|
||||
case 'activate':
|
||||
case 'network_activate':
|
||||
$info = $this->_get_plugin_info($query);
|
||||
if ($info['installed']) {
|
||||
$activate = activate_plugin($info['plugin_path']);
|
||||
if (is_wp_error($activate)) {
|
||||
$result = $this->_generic_error_response('generic_response_error', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'generic_response_error',
|
||||
'error_message' => $activate->get_error_message(),
|
||||
'info' => $this->_get_plugin_info($query)
|
||||
));
|
||||
} else {
|
||||
$result = array('activated' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
|
||||
}
|
||||
} else {
|
||||
$result = $this->_generic_error_response('plugin_not_installed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'plugin_not_installed',
|
||||
'error_message' => __('The plugin you wish to activate is either not installed or has been removed recently.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 'deactivate':
|
||||
case 'network_deactivate':
|
||||
$info = $this->_get_plugin_info($query);
|
||||
if ($info['active']) {
|
||||
deactivate_plugins($info['plugin_path']);
|
||||
if (!is_plugin_active($info['plugin_path'])) {
|
||||
$result = array('deactivated' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
|
||||
} else {
|
||||
$result = $this->_generic_error_response('deactivate_plugin_failed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'deactivate_plugin_failed',
|
||||
'error_message' => __('There appears to be a problem deactivating the intended plugin.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('Please check your permissions and try again.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'info' => $this->_get_plugin_info($query)
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$result = $this->_generic_error_response('not_active', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'not_active',
|
||||
'error_message' => __('The plugin you wish to deactivate is currently not active or is already deactivated.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 'install':
|
||||
$api = plugins_api('plugin_information', array(
|
||||
'slug' => $query['slug'],
|
||||
'fields' => array(
|
||||
'short_description' => false,
|
||||
'sections' => false,
|
||||
'requires' => false,
|
||||
'rating' => false,
|
||||
'ratings' => false,
|
||||
'downloaded' => false,
|
||||
'last_updated' => false,
|
||||
'added' => false,
|
||||
'tags' => false,
|
||||
'compatibility' => false,
|
||||
'homepage' => false,
|
||||
'donate_link' => false,
|
||||
)
|
||||
));
|
||||
|
||||
$info = $this->_get_plugin_info($query);
|
||||
if (is_wp_error($api)) {
|
||||
$result = $this->_generic_error_response('generic_response_error', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'generic_response_error',
|
||||
'error_message' => $api->get_error_message(),
|
||||
'info' => $info
|
||||
));
|
||||
} else {
|
||||
$installed = $info['installed'];
|
||||
|
||||
$error_code = $error_message = '';
|
||||
if (!$installed) {
|
||||
// WP < 3.7
|
||||
if (!class_exists('Automatic_Upgrader_Skin')) include_once(dirname(dirname(__FILE__)).'/classes/class-automatic-upgrader-skin.php');
|
||||
|
||||
$skin = new Automatic_Upgrader_Skin();
|
||||
$upgrader = new Plugin_Upgrader($skin);
|
||||
|
||||
$download_link = $api->download_link;
|
||||
$installed = $upgrader->install($download_link);
|
||||
|
||||
if (is_wp_error($installed)) {
|
||||
$error_code = $installed->get_error_code();
|
||||
$error_message = $installed->get_error_message();
|
||||
} elseif (is_wp_error($skin->result)) {
|
||||
$error_code = $skin->result->get_error_code();
|
||||
$error_message = $skin->result->get_error_message();
|
||||
|
||||
$error_data = $skin->result->get_error_data($error_code);
|
||||
if (!empty($error_data)) {
|
||||
if (is_array($error_data)) $error_data = json_encode($error_data);
|
||||
$error_message .= ' '.$error_data;
|
||||
}
|
||||
} elseif (is_null($installed) || !$installed) {
|
||||
global $wp_filesystem;
|
||||
$upgrade_messages = $skin->get_upgrade_messages();
|
||||
|
||||
if (!class_exists('WP_Filesystem_Base')) include_once(ABSPATH.'/wp-admin/includes/class-wp-filesystem-base.php');
|
||||
|
||||
// Pass through the error from WP_Filesystem if one was raised.
|
||||
if ($wp_filesystem instanceof WP_Filesystem_Base && is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
|
||||
$error_code = $wp_filesystem->errors->get_error_code();
|
||||
$error_message = $wp_filesystem->errors->get_error_message();
|
||||
} elseif (!empty($upgrade_messages)) {
|
||||
// We're only after for the last feedback that we received from the install process. Mostly,
|
||||
// that is where the last error has been inserted.
|
||||
$messages = $skin->get_upgrade_messages();
|
||||
$error_code = 'install_failed';
|
||||
$error_message = end($messages);
|
||||
} else {
|
||||
$error_code = 'unable_to_connect_to_filesystem';
|
||||
$error_message = __('Unable to connect to the filesystem.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('Please confirm your credentials.', UPDRAFTCENTRAL_TEXT_DOMAIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$installed || is_wp_error($installed)) {
|
||||
$result = $this->_generic_error_response('plugin_install_failed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => $error_code,
|
||||
'error_message' => $error_message,
|
||||
'info' => $this->_get_plugin_info($query)
|
||||
));
|
||||
} else {
|
||||
$result = array('installed' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preloads the submitted credentials to the global $_POST variable
|
||||
*
|
||||
* @param array $query Parameter array containing information for the currently requested action
|
||||
*/
|
||||
private function _preload_credentials($query) {
|
||||
if (!empty($query) && isset($query['filesystem_credentials'])) {
|
||||
parse_str($query['filesystem_credentials'], $filesystem_credentials);
|
||||
if (is_array($filesystem_credentials)) {
|
||||
foreach ($filesystem_credentials as $key => $value) {
|
||||
// Put them into $_POST, which is where request_filesystem_credentials() checks for them.
|
||||
$_POST[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we have the required fields submitted and the user has
|
||||
* the capabilities to execute the requested action
|
||||
*
|
||||
* @param array $query The submitted information
|
||||
* @param array $fields The required fields to check
|
||||
* @param array $capabilities The capabilities to check and validate
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
private function _validate_fields_and_capabilities($query, $fields, $capabilities) {
|
||||
|
||||
$error = '';
|
||||
if (!empty($fields)) {
|
||||
for ($i=0; $i<count($fields); $i++) {
|
||||
$field = $fields[$i];
|
||||
|
||||
if (!isset($query[$field])) {
|
||||
if ('keyword' === $field) {
|
||||
$error = $this->_generic_error_response('keyword_required');
|
||||
} else {
|
||||
$error = $this->_generic_error_response('plugin_'.$query[$field].'_required');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($error) && !empty($capabilities)) {
|
||||
for ($i=0; $i<count($capabilities); $i++) {
|
||||
if (!current_user_can($capabilities[$i])) {
|
||||
$error = $this->_generic_error_response('plugin_insufficient_permission');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processing an action for multiple items
|
||||
*
|
||||
* @param array $query Parameter array containing a list of plugins to process
|
||||
* @return array Contains the results of the bulk process
|
||||
*/
|
||||
public function process_action_in_bulk($query) {
|
||||
$action = isset($query['action']) ? $query['action'] : '';
|
||||
$items = isset($query['args']) ? $query['args']['items'] : array();
|
||||
|
||||
$results = array();
|
||||
if (!empty($action) && !empty($items) && is_array($items)) {
|
||||
foreach ($items as $value) {
|
||||
if (method_exists($this, $action)) {
|
||||
$results[] = $this->$action($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the plugin to activate
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function activate_plugin($query) {
|
||||
|
||||
$fields = array('plugin');
|
||||
$permissions = array('activate_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_plugin_action((!empty($query['multisite']) && (bool) $query['multisite']) ? 'network_activate' : 'activate', $query);
|
||||
if (empty($result['activated'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the plugin to deactivate
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function deactivate_plugin($query) {
|
||||
|
||||
$fields = array('plugin');
|
||||
$permissions = array('activate_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_plugin_action((!empty($query['multisite']) && (bool) $query['multisite']) ? 'network_deactivate' : 'deactivate', $query);
|
||||
if (empty($result['deactivated'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download, install and activates the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function install_activate_plugin($query) {
|
||||
|
||||
$fields = array('plugin', 'slug');
|
||||
$permissions = array('install_plugins', 'activate_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_plugin_action('install', $query);
|
||||
if (!empty($result['installed']) && $result['installed']) {
|
||||
$result = $this->_apply_plugin_action((!empty($query['multisite']) && (bool) $query['multisite']) ? 'network_activate' : 'activate', $query);
|
||||
if (empty($result['activated'])) {
|
||||
return $result;
|
||||
}
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download, install the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function install_plugin($query) {
|
||||
|
||||
$fields = array('plugin', 'slug');
|
||||
$permissions = array('install_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_plugin_action('install', $query);
|
||||
if (empty($result['installed'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall/delete the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function delete_plugin($query) {
|
||||
|
||||
$fields = array('plugin');
|
||||
$permissions = array('delete_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$info = $this->_get_plugin_info($query);
|
||||
if ($info['installed']) {
|
||||
// Deactivate first before delete to invalidate the activate
|
||||
// state/status prior to deleting the item. Otherwise, WordPress will keep
|
||||
// that state, and as soon as you install the same plugin it will be automatically
|
||||
// activated since it's previous state was kept.
|
||||
deactivate_plugins($info['plugin_path']);
|
||||
|
||||
$deleted = delete_plugins(array($info['plugin_path']));
|
||||
if ($deleted) {
|
||||
$result = array('deleted' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
|
||||
} else {
|
||||
return $this->_generic_error_response('delete_plugin_failed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'delete_plugin_failed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return $this->_generic_error_response('plugin_not_installed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'plugin_not_installed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates/upgrade the plugin
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function update_plugin($query) {
|
||||
|
||||
$fields = array('plugin', 'slug');
|
||||
$permissions = array('update_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
// Make sure that we still have the plugin installed before running
|
||||
// the update process
|
||||
$info = $this->_get_plugin_info($query);
|
||||
if ($info['installed']) {
|
||||
// Load the updates command class if not existed
|
||||
if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
|
||||
$update_command = new UpdraftCentral_Updates_Commands($this->rc);
|
||||
|
||||
$result = $update_command->update_plugin($info['plugin_path'], $query['slug']);
|
||||
if (!empty($result['error'])) {
|
||||
$result['values'] = array('plugin' => $query['plugin'], 'info' => $info);
|
||||
}
|
||||
} else {
|
||||
return $this->_generic_error_response('plugin_not_installed', array(
|
||||
'plugin' => $query['plugin'],
|
||||
'error_code' => 'plugin_not_installed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugin information along with its active and install status
|
||||
*
|
||||
* @internal
|
||||
* @param array $query Contains either the plugin name or slug or both to be used when retrieving information
|
||||
* @return array
|
||||
*/
|
||||
private function _get_plugin_info($query) {
|
||||
|
||||
$info = array(
|
||||
'active' => false,
|
||||
'installed' => false
|
||||
);
|
||||
|
||||
// Clear plugin cache so that newly installed/downloaded plugins
|
||||
// gets reflected when calling "get_plugins"
|
||||
if (function_exists('wp_clean_plugins_cache')) {
|
||||
wp_clean_plugins_cache();
|
||||
}
|
||||
|
||||
// Gets all plugins available.
|
||||
$get_plugins = get_plugins();
|
||||
|
||||
// Loops around each plugin available.
|
||||
foreach ($get_plugins as $key => $value) {
|
||||
$slug = $this->extract_slug_from_info($key, $value);
|
||||
|
||||
// If the plugin name matches that of the specified name, it will gather details.
|
||||
// In case name check isn't enough, we'll use slug to verify if the plugin being queried is actually installed.
|
||||
//
|
||||
// Reason for name check failure:
|
||||
// Due to plugin name inconsistencies - where wordpress.org registered plugin name is different
|
||||
// from the actual plugin files's metadata (found inside the plugin's PHP file itself).
|
||||
if ((!empty($query['plugin']) && html_entity_decode($value['Name']) === html_entity_decode($query['plugin'])) || (!empty($query['slug']) && $slug === $query['slug'])) {
|
||||
$info['installed'] = true;
|
||||
$info['active'] = is_plugin_active($key);
|
||||
$info['plugin_path'] = $key;
|
||||
$info['data'] = $value;
|
||||
$info['name'] = $value['Name'];
|
||||
$info['slug'] = $slug;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the slug from the plugin data
|
||||
*
|
||||
* @param string $key They key of the current info
|
||||
* @param array $info Data pulled from the plugin file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function extract_slug_from_info($key, $info) {
|
||||
if (!is_array($info) || empty($info) || empty($key)) return '';
|
||||
|
||||
$temp = explode('/', $key);
|
||||
|
||||
// With WP standards textdomain must always be equal to the plugin's folder name
|
||||
// but for premium plugins this may not always be the case thus, we extract the folder
|
||||
// name from the key as the default slug.
|
||||
$slug = basename($temp[0], '.php');
|
||||
|
||||
if (!empty($info['TextDomain']) && 1 === count($temp)) {
|
||||
// For plugin without folder we compare the extracted slug with the 'TextDomain'
|
||||
// and if they're not equal then 'TextDomain' will assume as slug.
|
||||
if ($slug != $info['TextDomain']) $slug = $info['TextDomain'];
|
||||
}
|
||||
|
||||
// If in case the user kept the hello-dolly plugin then we'll make sure that it gets
|
||||
// the proper slug for it, otherwise, we'll end up with the wrong slug 'hello' instead of
|
||||
// 'hello-dolly'. Wrong slug will produce error in UpdraftCentral when running it against
|
||||
// wordpress.org for further information retrieval.
|
||||
$slug = ('Hello Dolly' === $info['Name']) ? 'hello-dolly' : $slug;
|
||||
|
||||
return $slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all available plugins with additional attributes and settings needed by UpdraftCentral
|
||||
*
|
||||
* @param array $query Parameter array Any available parameters needed for this action
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function load_plugins($query) {
|
||||
|
||||
$permissions = array('install_plugins', 'activate_plugins');
|
||||
if (is_multisite() && !is_super_admin(get_current_user_id())) $permissions = array('activate_plugins');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, array(), $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$website = get_bloginfo('name');
|
||||
$results = array();
|
||||
|
||||
// Load the updates command class if not existed
|
||||
if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
|
||||
$updates = new UpdraftCentral_Updates_Commands($this->rc);
|
||||
|
||||
// Get plugins for update
|
||||
$plugin_updates = $updates->get_item_updates('plugins');
|
||||
|
||||
// Get all plugins
|
||||
$plugins = get_plugins();
|
||||
|
||||
if (is_multisite() && !is_super_admin(get_current_user_id())) {
|
||||
|
||||
// If the "Plugins" menu is disabled for the subsites on a multisite
|
||||
// network then we return an empty "plugins" array.
|
||||
$menu_items = get_site_option('menu_items');
|
||||
if (empty($menu_items) || !isset($menu_items['plugins'])) {
|
||||
$plugins = array();
|
||||
} else {
|
||||
$show_network_active = apply_filters('show_network_active_plugins', current_user_can('manage_network_plugins'));
|
||||
|
||||
$filtered_plugins = array();
|
||||
foreach ($plugins as $file => $data) {
|
||||
if (is_network_only_plugin($file) && !is_plugin_active($file)) {
|
||||
if ($show_network_active) $filtered_plugins[$file] = $data;
|
||||
} elseif (is_plugin_active_for_network($file)) {
|
||||
if ($show_network_active) $filtered_plugins[$file] = $data;
|
||||
} else {
|
||||
$filtered_plugins[$file] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
$plugins = $filtered_plugins;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($plugins as $key => $value) {
|
||||
$slug = $this->extract_slug_from_info($key, $value);
|
||||
|
||||
$plugin = new stdClass();
|
||||
$plugin->name = $value['Name'];
|
||||
$plugin->description = $value['Description'];
|
||||
$plugin->slug = $slug;
|
||||
$plugin->version = $value['Version'];
|
||||
$plugin->author = $value['Author'];
|
||||
$plugin->status = is_plugin_active($key) ? 'active' : 'inactive';
|
||||
$plugin->website = $website;
|
||||
$plugin->multisite = is_multisite();
|
||||
$plugin->site_url = trailingslashit(get_bloginfo('url'));
|
||||
|
||||
if (!empty($plugin_updates[$key])) {
|
||||
$update_info = $plugin_updates[$key];
|
||||
|
||||
if (version_compare($update_info->Version, $update_info->update->new_version, '<')) {
|
||||
if (!empty($update_info->update->new_version)) $plugin->latest_version = $update_info->update->new_version;
|
||||
if (!empty($update_info->update->package)) $plugin->download_link = $update_info->update->package;
|
||||
if (!empty($update_info->update->sections)) $plugin->sections = $update_info->update->sections;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($plugin->short_description) && !empty($plugin->description)) {
|
||||
// Only pull the first sentence as short description, it should be enough rather than displaying
|
||||
// an empty description or a full blown one which the user can access anytime if they press on
|
||||
// the view details link in UpdraftCentral.
|
||||
$temp = explode('.', $plugin->description);
|
||||
$short_description = $temp[0];
|
||||
|
||||
// Adding the second sentence wouldn't hurt, in case the first sentence is too short.
|
||||
if (isset($temp[1])) $short_description .= '.'.$temp[1];
|
||||
|
||||
$plugin->short_description = $short_description.'.';
|
||||
}
|
||||
|
||||
$results[] = $plugin;
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'plugins' => $results,
|
||||
'is_super_admin' => is_super_admin(),
|
||||
);
|
||||
|
||||
$result = array_merge($result, $this->_get_backup_credentials_settings(WP_PLUGIN_DIR));
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the backup and security credentials settings for this website
|
||||
*
|
||||
* @param array $query Parameter array Any available parameters needed for this action
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function get_plugin_requirements() {
|
||||
return $this->_response($this->_get_backup_credentials_settings(WP_PLUGIN_DIR));
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+2034
File diff suppressed because it is too large
Load Diff
Vendored
Executable
+721
@@ -0,0 +1,721 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles UpdraftCentral Theme Commands which basically handles
|
||||
* the installation and activation of a theme
|
||||
*/
|
||||
class UpdraftCentral_Theme_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
private $switched = false;
|
||||
|
||||
/**
|
||||
* Function that gets called before every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _pre_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- This function is called from listener.php and $extra_info is being sent.
|
||||
// Here we assign the current blog_id to a variable $blog_id
|
||||
$blog_id = get_current_blog_id();
|
||||
if (!empty($data['site_id'])) $blog_id = $data['site_id'];
|
||||
|
||||
if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
|
||||
$this->switched = switch_to_blog($blog_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that gets called after every action
|
||||
*
|
||||
* @param string $command a string that corresponds to UDC command to call a certain method for this class.
|
||||
* @param array $data an array of data post or get fields
|
||||
* @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
|
||||
*
|
||||
* link to udrpc_action main function in class UpdraftCentral_Listener
|
||||
*/
|
||||
public function _post_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the caller from UpdraftCentral_Listener class uses 3 arguments.
|
||||
// Here, we're restoring to the current (default) blog before we switched
|
||||
if ($this->switched) restore_current_blog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->_admin_include('theme.php', 'file.php', 'template.php', 'class-wp-upgrader.php', 'theme-install.php', 'update.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs and activates a theme through upload
|
||||
*
|
||||
* @param array $params Parameter array containing information pertaining the currently uploaded theme
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function upload_theme($params) {
|
||||
return $this->process_chunk_upload($params, 'theme');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the theme is currently installed and activated.
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the theme to check
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function is_theme_installed($query) {
|
||||
|
||||
if (!isset($query['theme']))
|
||||
return $this->_generic_error_response('theme_name_required');
|
||||
|
||||
|
||||
$result = $this->_get_theme_info($query['theme']);
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies currently requested action for theme processing
|
||||
*
|
||||
* @param string $action The action to apply (e.g. activate or install)
|
||||
* @param array $query Parameter array containing information for the currently requested action
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _apply_theme_action($action, $query) {
|
||||
|
||||
$result = array();
|
||||
switch ($action) {
|
||||
case 'activate':
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if ($info['installed']) {
|
||||
switch_theme($info['slug']);
|
||||
if (wp_get_theme()->get_stylesheet() === $info['slug']) {
|
||||
$result = array('activated' => true, 'info' => $this->_get_theme_info($query['theme']), 'last_state' => $info);
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_activated', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_activated',
|
||||
'error_message' => __('There appears to be a problem activating or switching to the intended theme.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('Please check your permissions and try again.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'info' => $this->_get_theme_info($query['theme'])
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_installed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'error_message' => __('The theme you wish to activate is either not installed or has been removed recently.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 'network_enable':
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if ($info['installed']) {
|
||||
if (current_user_can('manage_network_themes')) {
|
||||
// Make sure that network_enable_theme is present and callable since
|
||||
// it is only available at 4.6. If not, we'll do things the old fashion way
|
||||
if (is_callable(array('WP_Theme', 'network_enable_theme'))) {
|
||||
WP_Theme::network_enable_theme($info['slug']);
|
||||
} else {
|
||||
$allowed_themes = get_site_option('allowedthemes');
|
||||
$allowed_themes[$info['slug']] = true;
|
||||
|
||||
update_site_option('allowedthemes', $allowed_themes);
|
||||
}
|
||||
}
|
||||
|
||||
$allowed = WP_Theme::get_allowed_on_network();
|
||||
if (is_array($allowed) && !empty($allowed[$info['slug']])) {
|
||||
$result = array('enabled' => true, 'info' => $this->_get_theme_info($query['theme']), 'last_state' => $info);
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_enabled', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_enabled',
|
||||
'error_message' => __('There appears to be a problem enabling the intended theme on your network.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('Please kindly check your permission and try again.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'info' => $this->_get_theme_info($query['theme'])
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_installed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'error_message' => __('The theme you wish to enable on your network is either not installed or has been removed recently.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 'network_disable':
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if ($info['installed']) {
|
||||
if (current_user_can('manage_network_themes')) {
|
||||
// Make sure that network_disable_theme is present and callable since
|
||||
// it is only available at 4.6. If not, we'll do things the old fashion way
|
||||
if (is_callable(array('WP_Theme', 'network_disable_theme'))) {
|
||||
WP_Theme::network_disable_theme($info['slug']);
|
||||
} else {
|
||||
$allowed_themes = get_site_option('allowedthemes');
|
||||
if (isset($allowed_themes[$info['slug']])) {
|
||||
unset($allowed_themes[$info['slug']]);
|
||||
}
|
||||
|
||||
update_site_option('allowedthemes', $allowed_themes);
|
||||
}
|
||||
}
|
||||
|
||||
$allowed = WP_Theme::get_allowed_on_network();
|
||||
if (is_array($allowed) && empty($allowed[$info['slug']])) {
|
||||
$result = array('disabled' => true, 'info' => $this->_get_theme_info($query['theme']), 'last_state' => $info);
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_disabled', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_disabled',
|
||||
'error_message' => __('There appears to be a problem disabling the intended theme from your network.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('Please kindly check your permission and try again.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'info' => $this->_get_theme_info($query['theme'])
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$result = $this->_generic_error_response('theme_not_installed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'error_message' => __('The theme you wish to disable from your network is either not installed or has been removed recently.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 'install':
|
||||
$api = themes_api('theme_information', array(
|
||||
'slug' => $query['slug'],
|
||||
'fields' => array(
|
||||
'description' => true,
|
||||
'sections' => false,
|
||||
'rating' => true,
|
||||
'ratings' => true,
|
||||
'downloaded' => true,
|
||||
'downloadlink' => true,
|
||||
'last_updated' => true,
|
||||
'screenshot_url' => true,
|
||||
'parent' => true,
|
||||
)
|
||||
));
|
||||
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if (is_wp_error($api)) {
|
||||
$result = $this->_generic_error_response('generic_response_error', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'error_message' => $api->get_error_message(),
|
||||
'info' => $info
|
||||
));
|
||||
} else {
|
||||
$installed = $info['installed'];
|
||||
|
||||
$error_code = $error_message = '';
|
||||
if (!$installed) {
|
||||
// WP < 3.7
|
||||
if (!class_exists('Automatic_Upgrader_Skin')) include_once(dirname(dirname(__FILE__)).'/classes/class-automatic-upgrader-skin.php');
|
||||
|
||||
$skin = new Automatic_Upgrader_Skin();
|
||||
$upgrader = new Theme_Upgrader($skin);
|
||||
|
||||
$download_link = $api->download_link;
|
||||
$installed = $upgrader->install($download_link);
|
||||
|
||||
if (is_wp_error($installed)) {
|
||||
$error_code = $installed->get_error_code();
|
||||
$error_message = $installed->get_error_message();
|
||||
} elseif (is_wp_error($skin->result)) {
|
||||
$error_code = $skin->result->get_error_code();
|
||||
$error_message = $skin->result->get_error_message();
|
||||
|
||||
$error_data = $skin->result->get_error_data($error_code);
|
||||
if (!empty($error_data)) {
|
||||
if (is_array($error_data)) $error_data = json_encode($error_data);
|
||||
$error_message .= ' '.$error_data;
|
||||
}
|
||||
} elseif (is_null($installed) || !$installed) {
|
||||
global $wp_filesystem;
|
||||
$upgrade_messages = $skin->get_upgrade_messages();
|
||||
|
||||
if (!class_exists('WP_Filesystem_Base')) include_once(ABSPATH.'/wp-admin/includes/class-wp-filesystem-base.php');
|
||||
|
||||
// Pass through the error from WP_Filesystem if one was raised.
|
||||
if ($wp_filesystem instanceof WP_Filesystem_Base && is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
|
||||
$error_code = $wp_filesystem->errors->get_error_code();
|
||||
$error_message = $wp_filesystem->errors->get_error_message();
|
||||
} elseif (!empty($upgrade_messages)) {
|
||||
// We're only after for the last feedback that we received from the install process. Mostly,
|
||||
// that is where the last error has been inserted.
|
||||
$messages = $skin->get_upgrade_messages();
|
||||
$error_code = 'install_failed';
|
||||
$error_message = end($messages);
|
||||
} else {
|
||||
$error_code = 'unable_to_connect_to_filesystem';
|
||||
$error_message = __('Unable to connect to the filesystem.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('Please confirm your credentials.', UPDRAFTCENTRAL_TEXT_DOMAIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$installed || is_wp_error($installed)) {
|
||||
$result = $this->_generic_error_response('theme_install_failed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => $error_code,
|
||||
'error_message' => $error_message,
|
||||
'info' => $this->_get_theme_info($query['theme'])
|
||||
));
|
||||
} else {
|
||||
$result = array('installed' => true, 'info' => $this->_get_theme_info($query['theme']), 'last_state' => $info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preloads the submitted credentials to the global $_POST variable
|
||||
*
|
||||
* @param array $query Parameter array containing information for the currently requested action
|
||||
*/
|
||||
private function _preload_credentials($query) {
|
||||
if (!empty($query) && isset($query['filesystem_credentials'])) {
|
||||
parse_str($query['filesystem_credentials'], $filesystem_credentials);
|
||||
if (is_array($filesystem_credentials)) {
|
||||
foreach ($filesystem_credentials as $key => $value) {
|
||||
// Put them into $_POST, which is where request_filesystem_credentials() checks for them.
|
||||
$_POST[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we have the required fields submitted and the user has
|
||||
* the capabilities to execute the requested action
|
||||
*
|
||||
* @param array $query The submitted information
|
||||
* @param array $fields The required fields to check
|
||||
* @param array $capabilities The capabilities to check and validate
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
private function _validate_fields_and_capabilities($query, $fields, $capabilities) {
|
||||
|
||||
$error = '';
|
||||
if (!empty($fields)) {
|
||||
for ($i=0; $i<count($fields); $i++) {
|
||||
$field = $fields[$i];
|
||||
|
||||
if (!isset($query[$field])) {
|
||||
if ('keyword' === $field) {
|
||||
$error = $this->_generic_error_response('keyword_required');
|
||||
} else {
|
||||
$error = $this->_generic_error_response('theme_'.$query[$field].'_required');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($error) && !empty($capabilities)) {
|
||||
for ($i=0; $i<count($capabilities); $i++) {
|
||||
if (!current_user_can($capabilities[$i])) {
|
||||
$error = $this->_generic_error_response('theme_insufficient_permission');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processing an action for multiple items
|
||||
*
|
||||
* @param array $query Parameter array containing a list of themes to process
|
||||
* @return array Contains the results of the bulk process
|
||||
*/
|
||||
public function process_action_in_bulk($query) {
|
||||
$action = isset($query['action']) ? $query['action'] : '';
|
||||
$items = isset($query['args']) ? $query['args']['items'] : array();
|
||||
|
||||
$results = array();
|
||||
if (!empty($action) && !empty($items) && is_array($items)) {
|
||||
foreach ($items as $value) {
|
||||
if (method_exists($this, $action)) {
|
||||
$results[] = $this->$action($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_response($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the theme
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the theme to activate
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function activate_theme($query) {
|
||||
|
||||
$fields = array('theme');
|
||||
$permissions = array('switch_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_theme_action('activate', $query);
|
||||
if (empty($result['activated'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables theme for network
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the theme to activate
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function network_enable_theme($query) {
|
||||
|
||||
$fields = array('theme');
|
||||
$permissions = array('switch_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_theme_action('network_enable', $query);
|
||||
if (empty($result['enabled'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables theme from network
|
||||
*
|
||||
* @param array $query Parameter array containing the name of the theme to activate
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function network_disable_theme($query) {
|
||||
|
||||
$fields = array('theme');
|
||||
$permissions = array('switch_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_theme_action('network_disable', $query);
|
||||
if (empty($result['disabled'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download, install and activates the theme
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the theme name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function install_activate_theme($query) {
|
||||
|
||||
$fields = array('theme', 'slug');
|
||||
$permissions = array('install_themes', 'switch_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_theme_action('install', $query);
|
||||
if (!empty($result['installed']) && $result['installed']) {
|
||||
$result = $this->_apply_theme_action('activate', $query);
|
||||
if (empty($result['activated'])) {
|
||||
return $result;
|
||||
}
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download, install the theme
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the theme name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function install_theme($query) {
|
||||
|
||||
$fields = array('theme', 'slug');
|
||||
$permissions = array('install_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$result = $this->_apply_theme_action('install', $query);
|
||||
if (empty($result['installed'])) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall/delete the theme
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the theme name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function delete_theme($query) {
|
||||
|
||||
$fields = array('theme');
|
||||
$permissions = array('delete_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if ($info['installed']) {
|
||||
$deleted = delete_theme($info['slug']);
|
||||
|
||||
if ($deleted) {
|
||||
$result = array('deleted' => true, 'info' => $this->_get_theme_info($query['theme']), 'last_state' => $info);
|
||||
} else {
|
||||
return $this->_generic_error_response('delete_theme_failed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'delete_theme_failed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return $this->_generic_error_response('theme_not_installed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates/upgrade the theme
|
||||
*
|
||||
* @param array $query Parameter array containing the filesystem credentials entered by the user along with the theme name and slug
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function update_theme($query) {
|
||||
|
||||
$fields = array('theme');
|
||||
$permissions = array('update_themes');
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->_preload_credentials($query);
|
||||
|
||||
// Make sure that we still have the theme installed before running
|
||||
// the update process
|
||||
$info = $this->_get_theme_info($query['theme']);
|
||||
if ($info['installed']) {
|
||||
// Load the updates command class if not existed
|
||||
if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
|
||||
$update_command = new UpdraftCentral_Updates_Commands($this->rc);
|
||||
|
||||
$result = $update_command->update_theme($info['slug']);
|
||||
if (!empty($result['error'])) {
|
||||
$result['values'] = array('theme' => $query['theme'], 'info' => $info);
|
||||
}
|
||||
} else {
|
||||
return $this->_generic_error_response('theme_not_installed', array(
|
||||
'theme' => $query['theme'],
|
||||
'error_code' => 'theme_not_installed',
|
||||
'info' => $info
|
||||
));
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the theme information along with its active and install status
|
||||
*
|
||||
* @internal
|
||||
* @param array $theme The name of the theme to pull the information from
|
||||
* @return array Contains the theme information
|
||||
*/
|
||||
private function _get_theme_info($theme) {
|
||||
|
||||
$info = array(
|
||||
'active' => false,
|
||||
'installed' => false
|
||||
);
|
||||
|
||||
// Clear theme cache so that newly installed/downloaded themes
|
||||
// gets reflected when calling "get_themes"
|
||||
if (function_exists('wp_clean_themes_cache')) {
|
||||
wp_clean_themes_cache();
|
||||
}
|
||||
|
||||
// Gets all themes available.
|
||||
$themes = wp_get_themes();
|
||||
$current_theme_slug = basename(get_stylesheet_directory());
|
||||
|
||||
// Loops around each theme available.
|
||||
foreach ($themes as $slug => $value) {
|
||||
$name = $value->get('Name');
|
||||
$theme_name = !empty($name) ? $name : $slug;
|
||||
|
||||
// If the theme name matches that of the specified name, it will gather details.
|
||||
if ($theme_name === $theme) {
|
||||
$info['installed'] = true;
|
||||
$info['active'] = ($slug === $current_theme_slug) ? true : false;
|
||||
$info['slug'] = $slug;
|
||||
$info['data'] = $value;
|
||||
$info['name'] = $theme_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all available themes with additional attributes and settings needed by UpdraftCentral
|
||||
*
|
||||
* @param array $query Parameter array Any available parameters needed for this action
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function load_themes($query) {
|
||||
|
||||
$permissions = array('install_themes', 'switch_themes');
|
||||
$args = array();
|
||||
if (is_multisite() && !is_super_admin(get_current_user_id())) {
|
||||
$permissions = array('switch_themes');
|
||||
$args = array('allowed' => true, 'blog_id' => get_current_blog_id());
|
||||
}
|
||||
|
||||
$error = $this->_validate_fields_and_capabilities($query, array(), $permissions);
|
||||
if (!empty($error)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$website = get_bloginfo('name');
|
||||
$results = array();
|
||||
|
||||
// Load the updates command class if not existed
|
||||
if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
|
||||
$updates = new UpdraftCentral_Updates_Commands($this->rc);
|
||||
|
||||
// Get themes for update
|
||||
$theme_updates = (array) $updates->get_item_updates('themes');
|
||||
|
||||
// Get all themes
|
||||
$themes = wp_get_themes($args);
|
||||
$current_theme_slug = basename(get_stylesheet_directory());
|
||||
|
||||
foreach ($themes as $slug => $value) {
|
||||
$name = $value->get('Name');
|
||||
$theme_name = !empty($name) ? $name : $slug;
|
||||
|
||||
$theme = new stdClass();
|
||||
$theme->name = $theme_name;
|
||||
$theme->description = $value->get('Description');
|
||||
$theme->slug = $slug;
|
||||
$theme->version = $value->get('Version');
|
||||
$theme->author = $value->get('Author');
|
||||
$theme->status = ($slug === $current_theme_slug) ? 'active' : 'inactive';
|
||||
|
||||
$template = $value->get('Template');
|
||||
$theme->child_theme = !empty($template) ? true : false;
|
||||
$theme->website = $website;
|
||||
$theme->multisite = is_multisite();
|
||||
$theme->site_url = trailingslashit(get_bloginfo('url'));
|
||||
|
||||
if ($theme->child_theme) {
|
||||
$parent_theme = wp_get_theme($template);
|
||||
$parent_name = $parent_theme->get('Name');
|
||||
|
||||
$theme->parent = !empty($parent_name) ? $parent_name : $parent_theme->get_stylesheet();
|
||||
}
|
||||
|
||||
if (!empty($theme_updates[$slug])) {
|
||||
$update_info = $theme_updates[$slug];
|
||||
|
||||
if (version_compare($theme->version, $update_info->update['new_version'], '<')) {
|
||||
if (!empty($update_info->update['new_version'])) $theme->latest_version = $update_info->update['new_version'];
|
||||
if (!empty($update_info->update['package'])) $theme->download_link = $update_info->update['package'];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($theme->short_description) && !empty($theme->description)) {
|
||||
// Only pull the first sentence as short description, it should be enough rather than displaying
|
||||
// an empty description or a full blown one which the user can access anytime if they press on
|
||||
// the view details link in UpdraftCentral.
|
||||
$temp = explode('.', $theme->description);
|
||||
$short_description = $temp[0];
|
||||
|
||||
// Adding the second sentence wouldn't hurt, in case the first sentence is too short.
|
||||
if (isset($temp[1])) $short_description .= '.'.$temp[1];
|
||||
|
||||
$theme->short_description = $short_description.'.';
|
||||
}
|
||||
|
||||
$results[] = $theme;
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'themes' => $results,
|
||||
'theme_updates' => $theme_updates,
|
||||
'is_super_admin' => is_super_admin(),
|
||||
);
|
||||
|
||||
$result = array_merge($result, $this->_get_backup_credentials_settings(get_theme_root()));
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the backup and security credentials settings for this website
|
||||
*
|
||||
* @param array $query Parameter array Any available parameters needed for this action
|
||||
* @return array Contains the result of the current process
|
||||
*/
|
||||
public function get_theme_requirements() {
|
||||
return $this->_response($this->_get_backup_credentials_settings(get_theme_root()));
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+1028
File diff suppressed because it is too large
Load Diff
Vendored
Executable
+632
@@ -0,0 +1,632 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
|
||||
|
||||
/**
|
||||
* Handles Users Commands
|
||||
*/
|
||||
class UpdraftCentral_Users_Commands extends UpdraftCentral_Commands {
|
||||
|
||||
/**
|
||||
* Compares two user object whether one is lesser than, equal to, greater than the other
|
||||
*
|
||||
* @internal
|
||||
* @param array $a First user in the comparison
|
||||
* @param array $b Second user in the comparison
|
||||
* @return integer Comparison results (0 = equal, -1 = less than, 1 = greater than)
|
||||
*/
|
||||
private function compare_user_id($a, $b) {
|
||||
if ($a->ID === $b->ID) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($a->ID < $b->ID) ? -1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches users based from the keyword submitted
|
||||
*
|
||||
* @internal
|
||||
* @param array $query Parameter array containing the filter and keyword fields
|
||||
* @return array Contains the list of users found as well as the total users count
|
||||
*/
|
||||
private function _search_users($query) {
|
||||
$this->_admin_include('user.php');
|
||||
$query1 = new WP_User_Query(array(
|
||||
'orderby' => 'ID',
|
||||
'order' => 'ASC',
|
||||
'role'=> $query["role"],
|
||||
'search' => '*' . esc_attr($query["search"]) . '*',
|
||||
'search_columns' => array('user_login', 'user_email')
|
||||
));
|
||||
$query2 = new WP_User_Query(array(
|
||||
'orderby' => 'ID',
|
||||
'order' => 'ASC',
|
||||
'role'=> $query["role"],
|
||||
'meta_query'=>array(
|
||||
'relation' => 'OR',
|
||||
array(
|
||||
'key' => 'first_name',
|
||||
'value' => $query["search"],
|
||||
'compare' => 'LIKE'
|
||||
),
|
||||
array(
|
||||
'key' => 'last_name',
|
||||
'value' => $query["search"],
|
||||
'compare' => 'LIKE'
|
||||
),
|
||||
)
|
||||
));
|
||||
|
||||
if (empty($query1->results) && empty($query2->results)) {
|
||||
return array("message" => "users_not_found");
|
||||
} else {
|
||||
$found_users = array_merge($query1->results, $query2->results);
|
||||
$temp = array();
|
||||
foreach ($found_users as $new_user) {
|
||||
if (!isset($temp[$new_user->ID])) {
|
||||
$temp[$new_user->ID] = $new_user;
|
||||
}
|
||||
};
|
||||
|
||||
$users = array_values($temp);
|
||||
|
||||
// Sort users:
|
||||
usort($users, array($this, 'compare_user_id'));
|
||||
$offset = ((int) $query['page_no'] * (int) $query['per_page']) - (int) $query['per_page'];
|
||||
$user_list = array_slice($users, $offset, $query['per_page']);
|
||||
|
||||
return array(
|
||||
'users' => $user_list,
|
||||
'total_users' => count($users)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of pages needed to construct the pagination links
|
||||
*
|
||||
* @internal
|
||||
* @param array $query
|
||||
* @param array $total_users The total number of users found from the WP_User_Query query
|
||||
* @return array Contains information needed to construct the pagination links
|
||||
*/
|
||||
private function _calculate_pages($query, $total_users) {
|
||||
|
||||
$per_page_options = array(10, 20, 30, 40, 50);
|
||||
|
||||
if (!empty($query)) {
|
||||
|
||||
$pages = array();
|
||||
$page_count = ceil($total_users / $query["per_page"]);
|
||||
if ($page_count > 1) {
|
||||
|
||||
for ($i = 0; $i < $page_count; $i++) {
|
||||
if ($i + 1 == $query['page_no']) {
|
||||
$paginator_item = array(
|
||||
"value"=>$i+1,
|
||||
"setting"=>"disabled"
|
||||
);
|
||||
} else {
|
||||
$paginator_item = array(
|
||||
"value"=>$i+1
|
||||
);
|
||||
}
|
||||
array_push($pages, $paginator_item);
|
||||
};
|
||||
|
||||
if ($query['page_no'] >= $page_count) {
|
||||
$page_next = array(
|
||||
"value"=>$page_count,
|
||||
"setting"=>"disabled"
|
||||
);
|
||||
} else {
|
||||
$page_next = array(
|
||||
"value"=>$query['page_no'] + 1
|
||||
);
|
||||
};
|
||||
if (1 === $query['page_no']) {
|
||||
$page_prev = array(
|
||||
"value"=>1,
|
||||
"setting"=>"disabled"
|
||||
);
|
||||
} else {
|
||||
$page_prev = array(
|
||||
"value"=>$query['page_no'] - 1
|
||||
);
|
||||
};
|
||||
|
||||
return array(
|
||||
"page_no" => $query['page_no'],
|
||||
"per_page" => $query["per_page"],
|
||||
"page_count" => $page_count,
|
||||
"pages" => $pages,
|
||||
"page_next" => $page_next,
|
||||
"page_prev" => $page_prev,
|
||||
"total_results" => $total_users,
|
||||
"per_page_options" => $per_page_options
|
||||
);
|
||||
|
||||
} else {
|
||||
return array(
|
||||
"page_no" => $query['page_no'],
|
||||
"per_page" => $query["per_page"],
|
||||
"page_count" => $page_count,
|
||||
"total_results" => $total_users,
|
||||
"per_page_options" => $per_page_options
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return array(
|
||||
"per_page_options" => $per_page_options
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether the username exists
|
||||
*
|
||||
* @param array $params Contains the user name to check and validate
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function check_username($params) {
|
||||
$this->_admin_include('user.php');
|
||||
$username = $params['user_name'];
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (!empty($params['site_id'])) {
|
||||
$blog_id = $params['site_id'];
|
||||
}
|
||||
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull users from.
|
||||
|
||||
$switched = function_exists('switch_to_blog') ? switch_to_blog($blog_id) : false;
|
||||
|
||||
if (username_exists($username) && is_user_member_of_blog(username_exists($username), $blog_id)) {
|
||||
$result = array("valid" => false, "message" => 'username_exists');
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (!validate_username($username)) {
|
||||
$result = array("valid" => false, "message" => 'username_invalid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
$result = array("valid" => true, "message" => 'username_valid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls blog sites available
|
||||
* for the current WP instance.
|
||||
* If the site is a multisite, then sites under the network
|
||||
* will be pulled, otherwise, it will return an empty array.
|
||||
*
|
||||
* @return Array - an array of sites
|
||||
*/
|
||||
private function _get_blog_sites() {
|
||||
|
||||
if (!is_multisite()) return array();
|
||||
|
||||
// Initialize array container
|
||||
$sites = $network_sites = array();
|
||||
|
||||
// Check to see if latest get_sites (available on WP version >= 4.6) function is
|
||||
// available to pull any available sites from the current WP instance. If not, then
|
||||
// we're going to use the fallback function wp_get_sites (for older version).
|
||||
if (function_exists('get_sites') && class_exists('WP_Site_Query')) {
|
||||
$network_sites = get_sites();
|
||||
} else {
|
||||
if (function_exists('wp_get_sites')) {
|
||||
$network_sites = wp_get_sites();
|
||||
}
|
||||
}
|
||||
|
||||
// We only process if sites array is not empty, otherwise, bypass
|
||||
// the next block.
|
||||
if (!empty($network_sites)) {
|
||||
foreach ($network_sites as $site) {
|
||||
|
||||
// Here we're checking if the site type is an array, because
|
||||
// we're pulling the blog_id property based on the type of
|
||||
// site returned.
|
||||
// get_sites returns an array of object, whereas the wp_get_sites
|
||||
// function returns an array of array.
|
||||
$blog_id = is_array($site) ? $site['blog_id'] : $site->blog_id;
|
||||
|
||||
|
||||
// We're saving the blog_id and blog name as an associative item
|
||||
// into the sites array, that will be used as "Sites" option in
|
||||
// the frontend.
|
||||
$sites[$blog_id] = get_blog_details($blog_id)->blogname;
|
||||
}
|
||||
}
|
||||
|
||||
return $sites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether the email exists
|
||||
*
|
||||
* @param array $params Contains the email to check and validate
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function check_email($params) {
|
||||
$this->_admin_include('user.php');
|
||||
$email = $params['email'];
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['site_id']) && 0 !== $params['site_id']) {
|
||||
$blog_id = $params['site_id'];
|
||||
}
|
||||
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull users from.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
if (is_email($email) === false) {
|
||||
$result = array("valid" => false, "message" => 'email_invalid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
if (email_exists($email) && is_user_member_of_blog(email_exists($email), $blog_id)) {
|
||||
$result = array("valid" => false, "message" => 'email_exists');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
$result = array("valid" => true, "message" => 'email_valid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The get_users function pull all the users from the database
|
||||
* based on the current search parameters/filters. Please see _search_users
|
||||
* for the breakdown of these parameters.
|
||||
*
|
||||
* @param array $query Parameter array containing the filter and keyword fields
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function get_users($query) {
|
||||
$this->_admin_include('user.php');
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($query['site_id']) && 0 !== $query['site_id']) $blog_id = $query['site_id'];
|
||||
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull users from.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
// Set default:
|
||||
if (empty($query["per_page"])) {
|
||||
$query["per_page"] = 10;
|
||||
}
|
||||
if (empty($query['page_no'])) {
|
||||
$query['page_no'] = 1;
|
||||
}
|
||||
if (empty($query["role"])) {
|
||||
$query["role"] = "";
|
||||
}
|
||||
|
||||
$users = array();
|
||||
$total_users = 0;
|
||||
|
||||
if (!empty($query["search"])) {
|
||||
$search_results = $this->_search_users($query);
|
||||
|
||||
if (isset($search_results['users'])) {
|
||||
$users = $search_results['users'];
|
||||
$total_users = $search_results['total_users'];
|
||||
}
|
||||
} else {
|
||||
$user_query = new WP_User_Query(array(
|
||||
'orderby' => 'ID',
|
||||
'order' => 'ASC',
|
||||
'number' => $query["per_page"],
|
||||
'paged'=> $query['page_no'],
|
||||
'role'=> $query["role"]
|
||||
));
|
||||
|
||||
if (empty($user_query->results)) {
|
||||
$result = array("message" => 'users_not_found');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
$users = $user_query->results;
|
||||
$total_users = $user_query->get_total();
|
||||
}
|
||||
|
||||
foreach ($users as &$user) {
|
||||
$user_object = get_userdata($user->ID);
|
||||
if (method_exists($user_object, 'to_array')) {
|
||||
$user = $user_object->to_array();
|
||||
$user["roles"] = $user_object->roles;
|
||||
$user["first_name"] = $user_object->first_name;
|
||||
$user["last_name"] = $user_object->last_name;
|
||||
$user["description"] = $user_object->description;
|
||||
} else {
|
||||
$user = $user_object;
|
||||
}
|
||||
}
|
||||
|
||||
$result = array(
|
||||
"users"=>$users,
|
||||
"paging" => $this->_calculate_pages($query, $total_users)
|
||||
);
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new user for the current blog
|
||||
*
|
||||
* @param array $user User information to add
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function add_user($user) {
|
||||
$this->_admin_include('user.php');
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($user['site_id']) && 0 !== $user['site_id']) $blog_id = $user['site_id'];
|
||||
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to pull users from.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
if (!current_user_can('create_users') && !is_super_admin()) {
|
||||
$result = array('error' => true, 'message' => 'user_create_no_permission', 'data' => array('multisite' => is_multisite()));
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (is_email($user["user_email"]) === false) {
|
||||
$result = array("error" => true, "message" => "email_invalid");
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (email_exists($user["user_email"]) && is_user_member_of_blog(email_exists($user["user_email"]), $blog_id)) {
|
||||
$result = array("error" => true, "message" => "email_exists");
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (username_exists($user["user_login"]) && is_user_member_of_blog(username_exists($user["user_login"]), $blog_id)) {
|
||||
$result = array("error" => true, "message" => "username_exists");
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (!validate_username($user["user_login"])) {
|
||||
$result = array("error" => true, "message" => 'username_invalid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (isset($user['site_id']) && !current_user_can('manage_network_users')) {
|
||||
$result = array("error" => true, "message" => 'user_create_no_permission');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
if (email_exists($user["user_email"]) && !is_user_member_of_blog(email_exists($user["user_email"]), $blog_id)) {
|
||||
$user_id = email_exists($user["user_email"]);
|
||||
} else {
|
||||
$user_id = wp_insert_user($user);
|
||||
}
|
||||
$role = $user['role'];
|
||||
if (is_multisite()) {
|
||||
add_existing_user_to_blog(array('user_id' => $user_id, 'role' => $role));
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
if ($user_id > 0) {
|
||||
$result = array("error" => false, "message" => "user_created_with_user_name", "values" => array($user['user_login']));
|
||||
return $this->_response($result);
|
||||
} else {
|
||||
$result = array("error" => true, "message" => "user_create_failed", "values" => array($user));
|
||||
}
|
||||
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* [delete_user - UCP: users.delete_user]
|
||||
*
|
||||
* This function is used to check to make sure the user_id is valid and that it has has user delete permissions.
|
||||
* If there are no issues, the user is deleted.
|
||||
*
|
||||
* current_user_can: This check the user permissions from UCP
|
||||
* get_userdata: This get the user data on the data from user_id in the $user_id array
|
||||
* wp_delete_user: Deleting users on the User ID (user_id) and, IF Specified, the Assigner ID (assign_user_id).
|
||||
*
|
||||
* @param [type] $params [description] THis is an Array of params sent over from UpdraftCentral
|
||||
* @return [type] Array [description] This will send back an error array along with message if there are any issues with the user_id
|
||||
*/
|
||||
public function delete_user($params) {
|
||||
$this->_admin_include('user.php');
|
||||
$user_id = $params['user_id'];
|
||||
$assign_user_id = $params["assign_user_id"];
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($params['site_id']) && 0 !== $params['site_id']) $blog_id = $params['site_id'];
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
if (!current_user_can('delete_users') && !is_super_admin()) {
|
||||
$result = array('error' => true, 'message' => 'user_delete_no_permission', 'data' => array('multisite' => is_multisite()));
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (get_userdata($user_id) === false) {
|
||||
$result = array("error" => true, "message" => "user_not_found");
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
if (wp_delete_user($user_id, $assign_user_id)) {
|
||||
$result = array("error" => false, "message" => "user_deleted");
|
||||
} else {
|
||||
$result = array("error" => true, "message" => "user_delete_failed");
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits existing user information
|
||||
*
|
||||
* @param array $user User information to save
|
||||
* @return array An array containing the result of the current process
|
||||
*/
|
||||
public function edit_user($user) {
|
||||
$this->_admin_include('user.php');
|
||||
|
||||
// Here, we're getting the current blog id. If blog id
|
||||
// is passed along with the parameters then we override
|
||||
// that current (default) value with the parameter blog id value.
|
||||
|
||||
$blog_id = get_current_blog_id();
|
||||
if (isset($user['site_id']) && 0 !== $user['site_id']) $blog_id = $user['site_id'];
|
||||
|
||||
// Here, we're switching to the actual blog that we need
|
||||
// to apply our changes.
|
||||
|
||||
$switched = false;
|
||||
if (function_exists('switch_to_blog')) {
|
||||
$switched = switch_to_blog($blog_id);
|
||||
}
|
||||
|
||||
if (!current_user_can('edit_users') && !is_super_admin() && get_current_user_id() !== $user["ID"]) {
|
||||
$result = array('error' => true, 'message' => 'user_edit_no_permission', 'data' => array('multisite' => is_multisite()));
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
if (false === get_userdata($user["ID"])) {
|
||||
$result = array("error" => true, "message" => "user_not_found");
|
||||
return $this->_response($result);
|
||||
}
|
||||
if (get_current_user_id() == $user["ID"]) {
|
||||
unset($user["role"]);
|
||||
}
|
||||
|
||||
/* Validate Username*/
|
||||
if (!validate_username($user["user_login"])) {
|
||||
$result = array("error" => true, "message" => 'username_invalid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
/* Validate Email if not the same*/
|
||||
|
||||
$remote_user = get_userdata($user["ID"]);
|
||||
$old_email = $remote_user->user_email;
|
||||
|
||||
if ($user['user_email'] !== $old_email) {
|
||||
if (is_email($user['user_email']) === false) {
|
||||
$result = array("error" => true, "message" => 'email_invalid');
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
if (email_exists($user['user_email'])) {
|
||||
$result = array("error" => true, "message" => 'email_exists');
|
||||
return $this->_response($result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$user_id = wp_update_user($user);
|
||||
if (is_wp_error($user_id)) {
|
||||
$result = array("error" => true, "message" => "user_edit_failed_with_error", "values" => array($user_id));
|
||||
} else {
|
||||
$result = array("error" => false, "message" => "user_edited_with_user_name", "values" => array($user["user_login"]));
|
||||
}
|
||||
|
||||
// Here, we're restoring to the current (default) blog before we
|
||||
// do the switched.
|
||||
|
||||
if (function_exists('restore_current_blog') && $switched) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $this->_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves available roles to be used as filter options
|
||||
*
|
||||
* @return array An array containing all available roles
|
||||
*/
|
||||
public function get_roles() {
|
||||
$this->_admin_include('user.php');
|
||||
$roles = array_reverse(get_editable_roles());
|
||||
return $this->_response($roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information to be use as filters
|
||||
*
|
||||
* @return array An array containing the filter fields and their data
|
||||
*/
|
||||
public function get_user_filters() {
|
||||
$this->_admin_include('user.php');
|
||||
|
||||
// Pull sites options if available.
|
||||
$sites = $this->_get_blog_sites();
|
||||
|
||||
$result = array(
|
||||
"sites" => $sites,
|
||||
"roles" => array_reverse(get_editable_roles()),
|
||||
"paging" => $this->_calculate_pages(null, 0),
|
||||
);
|
||||
return $this->_response($result);
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+99
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('Security check');
|
||||
|
||||
// Translations for UpdraftCentral
|
||||
return array(
|
||||
'updraftcentral_connection' => __('UpdraftCentral Connection', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'updraftcentral_connection_successful' => __('An UpdraftCentral connection has been made successfully.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'updraftcentral_connection_failed' => __('A new UpdraftCentral connection has not been made.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'unknown_key' => __('The key referred to was unknown.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'not_logged_in' => __('You are not logged into this WordPress site in your web browser.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'must_visit_url' => __('You must visit this URL in the same browser and login session as you created the key in.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'security_check' => __('Security check.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'must_visit_link' => __('You must visit this link in the same browser and login session as you created the key in.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'connection_already_made' => __('This connection appears to already have been made.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'close' => __('Close', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'nothing_yet_logged' => __('(Nothing yet logged)', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'invalid_url' => __('An invalid URL was entered', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'updraftcentral_key_created' => __('UpdraftCentral key created successfully', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'need_to_copy_key' => __('You now need to copy the key below and enter it at your %s.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'press_add_site_button' => __('At your UpdraftCentral dashboard you should press the "Add Site" button then paste the key in the input box.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'detailed_instructions' => __('Detailed instructions for this can be found at %s', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'control_this_site' => __('You can now control this site via your UpdraftCentral dashboard at %s.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'attempt_to_register_failed' => __('A key was created, but the attempt to register it with %1$s was unsuccessful.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('You can try again, or try using the alternative connection method if the problem persists.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('For more information visit %2$s', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'key_created_successfully' => __('Key created successfully.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'copy_paste_key' => __('You must copy and paste this key now - it cannot be shown again.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'no_updraftcentral_dashboards' => __('There are no UpdraftCentral dashboards that can currently control this site.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'unknown' => __('Unknown', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'access_as_user' => __('Access this site as user:', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'public_key_sent' => __('Public key was sent to:', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'created' => __('Created:', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'key_size' => __('Key size: %d bits', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'delete' => __('Delete...', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'manage_keys' => __('Manage existing keys (%d)...', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'key_description' => __('Key description', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'details' => __('Details', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'connect_to_updraftcentral_dashboard' => __('Connect this site to an UpdraftCentral dashboard found at...', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'in_example' => __('i.e. if you have %s there', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'an_account' => __('an account', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'self_hosted_dashboard' => __('Self-hosted dashboard', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'website_installed' => __('A website where you have installed %s', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'enter_url' => __('Enter the URL where your self-hosted install of UpdraftCentral is located:', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'updraftcentral_dashboard_url' => __('URL for the site of your UpdraftCentral dashboard', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'next' => __('Next', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'updraftcentral_connection_details' => __('UpdraftCentral dashboard connection details', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'description' => __('Description', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'enter_description' => __('Enter any description', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'encryption_key_size' => __('Encryption key size:', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'bits' => __('%s bits', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'bytes' => __('%s bytes', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'easy_to_break' => __('easy to break, fastest', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'faster' => __('faster (possibility for slow PHP installs)', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'recommended' => __('recommended', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'slower' => __('slower, strongest', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'use_alternative_method' => __('Use the alternative method for making a connection with the dashboard.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'more_information' => __('More information...', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'this_is_useful' => __('This is useful if the dashboard webserver cannot be contacted with incoming traffic by this website (for example, this is the case if this website is hosted on the public Internet, but the UpdraftCentral dashboard is on localhost, or on an Intranet, or if this website has an outgoing firewall), or if the dashboard website does not have a SSL certificate.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'create' => __('Create', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'back' => __('Back...', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'view_log_events' => __('View recent UpdraftCentral log events', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'updraftcentral_remote_control' => __('UpdraftCentral (Remote Control)', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'updraftcentral_description' => __('UpdraftCentral enables control of your WordPress sites %s from a central dashboard.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'including_description' => array(
|
||||
'wp_optimize_desc' => __('(including management of WP-Optimize)', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'updraftplus_desc' => __('(including management of backups and updates)', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
),
|
||||
'read_more' => __('Read more about it here.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'create_another_key' => __('Create another key', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'unable_to_connect' => __('Unable to connect to the filesystem', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'unable_to_activate' => __('Unable to activate %s successfully.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('Make sure that this %s is compatible with your remote WordPress version.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('WordPress version currently installed in your remote website is %s.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'unable_to_install' => __('Unable to install %s.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('Make sure you upload the correct file and that the zip file is a valid %s file (not corrupted) and try uploading the file again.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'failed_to_attach_media' => __('Failed to attach media.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'media_attached' => __('Media has been attached to post.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'failed_to_detach_media' => __('Failed to detach media.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'media_detached' => __('Media has been detached from post.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'failed_to_delete_media' => __('Failed to delete selected media.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'selected_media_deleted' => __('Selected media has been deleted successfully.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'unattached' => __('Unattached', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'default_template' => __('Default template', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'parameters_missing' => __('Expected parameter(s) missing.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'fetching' => __('Fetching...', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'deleting' => __('Deleting...', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'enter_mothership_url' => __('Please enter a valid URL', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'creating_please_allow' => __('Creating...', UPDRAFTCENTRAL_TEXT_DOMAIN).(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.', UPDRAFTCENTRAL_TEXT_DOMAIN).')'),
|
||||
'unexpectedresponse' => __('Unexpected response:', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'updraftcentral_wizard_empty_url' => __('Please enter the URL where your UpdraftCentral dashboard is hosted.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'updraftcentral_wizard_invalid_url' => __('Please enter a valid URL e.g http://example.com', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'insufficient_privilege' => __('Sorry, you do not have enough privilege to execute the requested action.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'copy_to_clipboard' => __('Copy to clipboard', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'key_copied' => __('The key was copied to the clipboard.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'unable_to_copy' => __('The attempt to copy to the clipboard failed.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'wpo_not_active' => __('WP_Optimize is not installed or active.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'log_file_not_exist' => __('Log file does not exist or could not be read.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'security_check_failed' => __('Security check failed; try refreshing the page.', UPDRAFTCENTRAL_TEXT_DOMAIN).' '.__('If refreshing the page does not help then perhaps you do not have sufficient privilege to manage WP-Optimize.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'no_such_command' => __('No such command found.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'command_not_allowed' => __('You are not allowed to run this command.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'command_not_found' => __('The command is either not found or not allowed.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
'network_admin_only' => __('The command can only be executed by a network admin.', UPDRAFTCENTRAL_TEXT_DOMAIN),
|
||||
);
|
||||
Vendored
Executable
+282
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
|
||||
if (class_exists('UpdraftPlus_Host')) return;
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) define('UPDRAFTCENTRAL_CLIENT_DIR', dirname(__FILE__));
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_URL')) define('UPDRAFTCENTRAL_CLIENT_URL', plugins_url('', __FILE__));
|
||||
if (!class_exists('UpdraftCentral_Host')) {
|
||||
include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/host.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is the basic bridge between UpdraftCentral and UpdraftPlus.
|
||||
*/
|
||||
class UpdraftPlus_Host extends UpdraftCentral_Host {
|
||||
|
||||
public $plugin_name = 'updraftplus';
|
||||
|
||||
public $translations = array();
|
||||
|
||||
protected static $_instance = null;
|
||||
|
||||
/**
|
||||
* Creates an instance of this class. Singleton Pattern
|
||||
*
|
||||
* @return object Instance of this class
|
||||
*/
|
||||
public static function instance() {
|
||||
if (empty(self::$_instance)) {
|
||||
self::$_instance = new self();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action('updraftplus_debugtools_dashboard', array($this, 'debugtools_dashboard'), 20);
|
||||
add_action('updraftplus_load_translations_for_udcentral', array($this, 'load_updraftplus_translations'));
|
||||
|
||||
$this->maybe_initialize_required_objects();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the UpdraftCentral_Main instance
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load_updraftcentral() {
|
||||
$central_path = $this->is_host_dir_set() ? trailingslashit(UPDRAFTPLUS_DIR) : '';
|
||||
|
||||
if (file_exists($central_path.'central/bootstrap.php')) {
|
||||
include_once($central_path.'central/bootstrap.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current user can perform key control AJAX actions
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function current_user_can_ajax() {
|
||||
return UpdraftPlus_Options::user_can_manage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Below are interface methods' implementations that are required by UpdraftCentral to function properly. Please
|
||||
* see the "interface.php" to check all the required interface methods.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks whether the plugin's DIR constant is currently define or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_host_dir_set() {
|
||||
return defined('UPDRAFTPLUS_DIR') ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the host plugin's dir path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_host_dir() {
|
||||
return defined('UPDRAFTPLUS_DIR') ? UPDRAFTPLUS_DIR : dirname(dirname(__FILE__));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the filter used by UpdraftPlus to log errors or certain events
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_logline_filter() {
|
||||
return 'updraftplus_logline';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether debug mod is set
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_debug_mode() {
|
||||
if (class_exists('UpdraftPlus_Options')) {
|
||||
return UpdraftPlus_Options::get_updraft_option('updraft_debug_mode');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used as a central location (to avoid repetition) to register or de-register hooks into the WP HTTP API
|
||||
*
|
||||
* @param bool $register True to register, false to de-register
|
||||
* @return void
|
||||
*/
|
||||
public function register_wp_http_option_hooks($register = true) {
|
||||
global $updraftplus;
|
||||
|
||||
if ($updraftplus) {
|
||||
$updraftplus->register_wp_http_option_hooks($register);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the class name of the host plugin
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_class_name() {
|
||||
global $updraftplus;
|
||||
|
||||
if ($updraftplus) {
|
||||
return get_class($updraftplus);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the instance of the host plugin
|
||||
*
|
||||
* @return object|bool
|
||||
*/
|
||||
public function get_instance() {
|
||||
global $updraftplus;
|
||||
|
||||
if ($updraftplus) {
|
||||
return $updraftplus;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the admin instance of the host plugin
|
||||
*
|
||||
* @return object|bool
|
||||
*/
|
||||
public function get_admin_instance() {
|
||||
global $updraftplus_admin;
|
||||
|
||||
if ($updraftplus_admin) {
|
||||
return $updraftplus_admin;
|
||||
} else {
|
||||
if (defined('UPDRAFTPLUS_DIR') && file_exists(UPDRAFTPLUS_DIR.'/admin.php')) {
|
||||
updraft_try_include_file('admin.php', 'include_once');
|
||||
$updraftplus_admin = new UpdraftPlus_Admin();
|
||||
return $updraftplus_admin;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given line
|
||||
*
|
||||
* @param string $line The log line
|
||||
* @param string $level The log level: notice, warning, error, etc.
|
||||
* @param boolean|string $uniq_id Each of these will only be logged once
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log($line, $level = 'notice', $uniq_id = false) {
|
||||
global $updraftplus;
|
||||
|
||||
if ($updraftplus) {
|
||||
if (is_callable(array($updraftplus, 'log'))) {
|
||||
call_user_func(array($updraftplus, 'log'), $line, $level, $uniq_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current version of the host plugin
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_version() {
|
||||
global $updraftplus;
|
||||
|
||||
if ($updraftplus) {
|
||||
return $updraftplus->version;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filesystem class of the host's plugin
|
||||
*
|
||||
* @return class|bool
|
||||
*/
|
||||
public function get_filesystem_functions() {
|
||||
if ($this->has_filesystem_functions()) {
|
||||
return UpdraftPlus_Filesystem_Functions;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the filesystem class of the host plugin exists
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_filesystem_functions() {
|
||||
return class_exists('UpdraftPlus_Filesystem_Functions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether force debugging is set
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_force_debug() {
|
||||
return (defined('UPDRAFTPLUS_UDRPC_FORCE_DEBUG') && UPDRAFTPLUS_UDRPC_FORCE_DEBUG) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes required objects (if not yet initialized) for UpdraftCentral usage
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function maybe_initialize_required_objects() {
|
||||
global $updraftplus;
|
||||
|
||||
if (!class_exists('UpdraftPlus')) {
|
||||
if (defined('UPDRAFTPLUS_DIR') && file_exists(UPDRAFTPLUS_DIR.'/class-updraftplus.php')) {
|
||||
updraft_try_include_file('class-updraftplus.php', 'include_once');
|
||||
if (empty($updraftplus) || !is_a($updraftplus, 'UpdraftPlus')) {
|
||||
$updraftplus = new UpdraftPlus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_exists('UpdraftPlus_Options')) {
|
||||
if (defined('UPDRAFTPLUS_DIR') && file_exists(UPDRAFTPLUS_DIR.'/options.php')) {
|
||||
updraft_try_include_file('options.php', 'require_once');
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_exists('UpdraftPlus_Filesystem_Functions')) {
|
||||
if (defined('UPDRAFTPLUS_DIR') && file_exists(UPDRAFTPLUS_DIR.'/includes/class-filesystem-functions.php')) {
|
||||
updraft_try_include_file('includes/class-filesystem-functions.php', 'require_once');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load translations which are based on UpdraftPlus domain text
|
||||
*/
|
||||
public function load_updraftplus_translations() {
|
||||
// Load updraftplus translations
|
||||
if (defined('UPDRAFTCENTRAL_CLIENT_DIR') && file_exists(UPDRAFTCENTRAL_CLIENT_DIR.'/translations-central.php')) {
|
||||
$this->translations = include(UPDRAFTCENTRAL_CLIENT_DIR.'/translations-central.php');
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
Executable
+156
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
if (class_exists('WP_Optimize_Host')) return;
|
||||
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) define('UPDRAFTCENTRAL_CLIENT_DIR', dirname(__FILE__));
|
||||
if (!defined('UPDRAFTCENTRAL_CLIENT_URL')) define('UPDRAFTCENTRAL_CLIENT_URL', plugins_url('', __FILE__));
|
||||
if (!class_exists('UpdraftCentral_Host')) {
|
||||
include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/host.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is the basic bridge between UpdraftCentral and WP_Optimize.
|
||||
*/
|
||||
class WP_Optimize_Host extends UpdraftCentral_Host {
|
||||
|
||||
public $plugin_name = 'wp-optimize';
|
||||
|
||||
public $translations = array();
|
||||
|
||||
protected static $_instance = null;
|
||||
|
||||
/**
|
||||
* Creates an instance of this class. Singleton Pattern
|
||||
*
|
||||
* @return object Instance of this class
|
||||
*/
|
||||
public static function instance() {
|
||||
if (empty(self::$_instance)) {
|
||||
self::$_instance = new self();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
add_action('updraftplus_load_translations_for_udcentral', array($this, 'load_updraftplus_translations'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current user can perform key control AJAX actions
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function current_user_can_ajax() {
|
||||
return current_user_can(WP_Optimize()->capability_required());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the UpdraftCentral_Main instance
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load_updraftcentral() {
|
||||
$central_path = $this->is_host_dir_set() ? trailingslashit(WPO_PLUGIN_MAIN_PATH) : '';
|
||||
|
||||
if (!empty($central_path) && file_exists($central_path.'central/bootstrap.php')) {
|
||||
include_once($central_path.'central/bootstrap.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the plugin's DIR constant is currently define or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_host_dir_set() {
|
||||
return defined('WPO_PLUGIN_MAIN_PATH') ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the host plugin's dir path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_host_dir() {
|
||||
return defined('WPO_PLUGIN_MAIN_PATH') ? WPO_PLUGIN_MAIN_PATH : dirname(dirname(__FILE__));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current version of the host plugin
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_version() {
|
||||
return defined('WPO_VERSION') ? WPO_VERSION : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the instance of the host plugin
|
||||
*
|
||||
* @return object|bool
|
||||
*/
|
||||
public function get_instance() {
|
||||
global $wp_optimize;
|
||||
|
||||
if ($wp_optimize) {
|
||||
return $wp_optimize;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether debug mod is set
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_debug_mode() {
|
||||
return (defined('WP_OPTIMIZE_DEBUG_OPTIMIZATIONS') && WP_OPTIMIZE_DEBUG_OPTIMIZATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given line
|
||||
*
|
||||
* @param string $line The log line
|
||||
* @param string $level The log level: notice, warning, error, etc.
|
||||
* @param boolean|string $uniq_id Each of these will only be logged once
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log($line, $level = 'notice', $uniq_id = false) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the the abstract UpdraftCentral_Host class uses 3 arguments.
|
||||
global $wp_optimize;
|
||||
|
||||
if ($wp_optimize) {
|
||||
if (is_callable(array($wp_optimize, 'log'))) {
|
||||
call_user_func(array($wp_optimize, 'log'), $line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load translations which are based on UpdraftPlus domain text
|
||||
*/
|
||||
public function load_updraftplus_translations() {
|
||||
// Load wp-optimize translations
|
||||
if (defined('UPDRAFTCENTRAL_CLIENT_DIR') && file_exists(UPDRAFTCENTRAL_CLIENT_DIR.'/translations-central.php')) {
|
||||
$this->translations = include(UPDRAFTCENTRAL_CLIENT_DIR.'/translations-central.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Developer Note:
|
||||
*
|
||||
* You can add your class methods below if ever you want to extend or modify
|
||||
* the module handlers of UpdraftCentral located at central/modules. Just be
|
||||
* sure to use this class to abstract any functionality that would link to the
|
||||
* wp-optimize plugin.
|
||||
*
|
||||
* N.B. All custom methods added here will then be available from the global
|
||||
* variable $updraftcentral_host_plugin (e.g. $updraftcentral_host_plugin->YOUR_METHOD)
|
||||
*/
|
||||
}
|
||||
wp-content/plugins/all-in-one-wp-security-and-firewall/vendor/team-updraft/lib-central/composer.json
Vendored
Executable
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "team-updraft/lib-central",
|
||||
"type": "library"
|
||||
}
|
||||
Reference in New Issue
Block a user