Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/updraftp.../methods
File: googledrive.php
<?php
[0] Fix | Delete
[1] Fix | Delete
if (!defined('UPDRAFTPLUS_DIR')) die('No direct access allowed.');
[2] Fix | Delete
[3] Fix | Delete
// Converted to multi-options (Feb 2017-) and previous options conversion removed: Yes
[4] Fix | Delete
[5] Fix | Delete
if (!class_exists('UpdraftPlus_BackupModule')) require_once(UPDRAFTPLUS_DIR.'/methods/backup-module.php');
[6] Fix | Delete
[7] Fix | Delete
class UpdraftPlus_BackupModule_googledrive extends UpdraftPlus_BackupModule {
[8] Fix | Delete
[9] Fix | Delete
private $client;
[10] Fix | Delete
[11] Fix | Delete
private $ids_from_paths = array();
[12] Fix | Delete
[13] Fix | Delete
private $client_id;
[14] Fix | Delete
[15] Fix | Delete
private $callback_url;
[16] Fix | Delete
[17] Fix | Delete
private $multi_directories = array();
[18] Fix | Delete
[19] Fix | Delete
private $registered_prune = false;
[20] Fix | Delete
[21] Fix | Delete
/**
[22] Fix | Delete
* Constructor
[23] Fix | Delete
*/
[24] Fix | Delete
public function __construct() {
[25] Fix | Delete
$this->client_id = defined('UPDRAFTPLUS_GOOGLEDRIVE_CLIENT_ID') ? UPDRAFTPLUS_GOOGLEDRIVE_CLIENT_ID : '916618189494-u3ehb1fl7u3meb63nb2b4fqi0r9pcfe2.apps.googleusercontent.com';
[26] Fix | Delete
$this->callback_url = defined('UPDRAFTPLUS_GOOGLEDRIVE_CALLBACK_URL') ? UPDRAFTPLUS_GOOGLEDRIVE_CALLBACK_URL : 'https://auth.updraftplus.com/auth/googledrive';
[27] Fix | Delete
}
[28] Fix | Delete
[29] Fix | Delete
public function action_auth() {
[30] Fix | Delete
if (isset($_GET['state'])) {
[31] Fix | Delete
[32] Fix | Delete
$parts = explode(':', $_GET['state']);
[33] Fix | Delete
$state = $parts[0];
[34] Fix | Delete
[35] Fix | Delete
if ('success' == $state) {
[36] Fix | Delete
[37] Fix | Delete
if (isset($_GET['user_id']) && isset($_GET['access_token'])) {
[38] Fix | Delete
$code = array(
[39] Fix | Delete
'user_id' => $_GET['user_id'],
[40] Fix | Delete
'access_token' => $_GET['access_token']
[41] Fix | Delete
);
[42] Fix | Delete
} else {
[43] Fix | Delete
$code = array();
[44] Fix | Delete
}
[45] Fix | Delete
[46] Fix | Delete
$this->do_complete_authentication($state, $code);
[47] Fix | Delete
[48] Fix | Delete
} elseif ('token' == $state) {
[49] Fix | Delete
$this->gdrive_auth_token();
[50] Fix | Delete
} elseif ('revoke' == $state) {
[51] Fix | Delete
$this->gdrive_auth_revoke();
[52] Fix | Delete
}
[53] Fix | Delete
} elseif (isset($_GET['updraftplus_googledriveauth'])) {
[54] Fix | Delete
if ('doit' == $_GET['updraftplus_googledriveauth']) {
[55] Fix | Delete
$this->action_authenticate_storage();
[56] Fix | Delete
} elseif ('deauth' == $_GET['updraftplus_googledriveauth']) {
[57] Fix | Delete
$this->action_deauthenticate_storage();
[58] Fix | Delete
}
[59] Fix | Delete
}
[60] Fix | Delete
}
[61] Fix | Delete
[62] Fix | Delete
/**
[63] Fix | Delete
* This method overrides the parent method and lists the supported features of this remote storage option.
[64] Fix | Delete
*
[65] Fix | Delete
* @return Array - an array of supported features (any features not mentioned are asuumed to not be supported)
[66] Fix | Delete
*/
[67] Fix | Delete
public function get_supported_features() {
[68] Fix | Delete
// This options format is handled via only accessing options via $this->get_options()
[69] Fix | Delete
return array('multi_options', 'config_templates', 'multi_storage', 'conditional_logic', 'manual_authentication');
[70] Fix | Delete
}
[71] Fix | Delete
[72] Fix | Delete
/**
[73] Fix | Delete
* Retrieve default options for this remote storage module.
[74] Fix | Delete
*
[75] Fix | Delete
* @return Array - an array of options
[76] Fix | Delete
*/
[77] Fix | Delete
public function get_default_options() {
[78] Fix | Delete
// parentid is deprecated since April 2014; it should not be in the default options (its presence is used to detect an upgraded-from-previous-SDK situation). For the same reason, 'folder' is also unset; which enables us to know whether new-style settings have ever been set.
[79] Fix | Delete
return array(
[80] Fix | Delete
'clientid' => '',
[81] Fix | Delete
'secret' => '',
[82] Fix | Delete
'token' => '',
[83] Fix | Delete
);
[84] Fix | Delete
}
[85] Fix | Delete
[86] Fix | Delete
/**
[87] Fix | Delete
* Check whether options have been set up by the user, or not
[88] Fix | Delete
*
[89] Fix | Delete
* @param Array $opts - the potential options
[90] Fix | Delete
*
[91] Fix | Delete
* @return Boolean
[92] Fix | Delete
*/
[93] Fix | Delete
public function options_exist($opts) {
[94] Fix | Delete
if (is_array($opts) && (!empty($opts['user_id']) || !empty($opts['token']))) return true;
[95] Fix | Delete
return false;
[96] Fix | Delete
}
[97] Fix | Delete
[98] Fix | Delete
/**
[99] Fix | Delete
* Get the Google folder ID for the root of the drive
[100] Fix | Delete
*
[101] Fix | Delete
* @return String|Integer
[102] Fix | Delete
*/
[103] Fix | Delete
private function root_id() {
[104] Fix | Delete
if (empty($this->root_id)) $this->root_id = $this->get_storage()->about->get()->getRootFolderId();
[105] Fix | Delete
return $this->root_id;
[106] Fix | Delete
}
[107] Fix | Delete
[108] Fix | Delete
/**
[109] Fix | Delete
* Get folder id from path
[110] Fix | Delete
*
[111] Fix | Delete
* @param String $path folder path
[112] Fix | Delete
* @param Boolean $one_only if false, then will be returned as a list (Google Drive allows multiple entities with the same name)
[113] Fix | Delete
* @param Integer $retry_count how many times to retry upon a network failure
[114] Fix | Delete
*
[115] Fix | Delete
* @return Array|String|Integer|Boolean internal id of the Google Drive folder (or list of them if $one_only was false), or false upon failure
[116] Fix | Delete
*/
[117] Fix | Delete
public function id_from_path($path, $one_only = true, $retry_count = 3) {
[118] Fix | Delete
$storage = $this->get_storage();
[119] Fix | Delete
[120] Fix | Delete
try {
[121] Fix | Delete
[122] Fix | Delete
while ('/' == substr($path, 0, 1)) {
[123] Fix | Delete
$path = substr($path, 1);
[124] Fix | Delete
}
[125] Fix | Delete
[126] Fix | Delete
$cache_key = empty($path) ? '/' : ($one_only ? $path : 'multi:'.$path);
[127] Fix | Delete
if (isset($this->ids_from_paths[$cache_key])) return $this->ids_from_paths[$cache_key];
[128] Fix | Delete
[129] Fix | Delete
$current_parent_id = $this->root_id();
[130] Fix | Delete
$current_path = '/';
[131] Fix | Delete
[132] Fix | Delete
if (!empty($path)) {
[133] Fix | Delete
$nodes = explode('/', $path);
[134] Fix | Delete
foreach ($nodes as $element) {
[135] Fix | Delete
$found = array();
[136] Fix | Delete
$sub_items = $this->get_subitems($current_parent_id, 'dir', $element);
[137] Fix | Delete
[138] Fix | Delete
foreach ($sub_items as $item) {
[139] Fix | Delete
try {
[140] Fix | Delete
if ($item->getTitle() == $element) {
[141] Fix | Delete
$current_path .= $element.'/';
[142] Fix | Delete
$current_parent_id = $item->getId();
[143] Fix | Delete
$found[$current_parent_id] = strtotime($item->getCreatedDate());
[144] Fix | Delete
}
[145] Fix | Delete
} catch (Exception $e) {
[146] Fix | Delete
$this->log("id_from_path: exception: ".$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')');
[147] Fix | Delete
}
[148] Fix | Delete
}
[149] Fix | Delete
[150] Fix | Delete
if (count($found) > 1) {
[151] Fix | Delete
asort($found);
[152] Fix | Delete
reset($found);
[153] Fix | Delete
$current_parent_id = key($found);
[154] Fix | Delete
} elseif (empty($found)) {
[155] Fix | Delete
$ref = new UDP_Google_Service_Drive_ParentReference;
[156] Fix | Delete
$ref->setId($current_parent_id);
[157] Fix | Delete
$dir = new UDP_Google_Service_Drive_DriveFile();
[158] Fix | Delete
$dir->setMimeType('application/vnd.google-apps.folder');
[159] Fix | Delete
$dir->setParents(array($ref));
[160] Fix | Delete
$dir->setTitle($element);
[161] Fix | Delete
$this->log('creating path: '.$current_path.$element);
[162] Fix | Delete
$dir = $storage->files->insert(
[163] Fix | Delete
$dir,
[164] Fix | Delete
array('mimeType' => 'application/vnd.google-apps.folder')
[165] Fix | Delete
);
[166] Fix | Delete
$current_path .= $element.'/';
[167] Fix | Delete
$current_parent_id = $dir->getId();
[168] Fix | Delete
}
[169] Fix | Delete
}
[170] Fix | Delete
}
[171] Fix | Delete
[172] Fix | Delete
if (empty($this->ids_from_paths)) $this->ids_from_paths = array();
[173] Fix | Delete
$this->ids_from_paths[$cache_key] = ($one_only || empty($found) || 1 == count($found)) ? $current_parent_id : $found;
[174] Fix | Delete
[175] Fix | Delete
return $this->ids_from_paths[$cache_key];
[176] Fix | Delete
[177] Fix | Delete
} catch (Exception $e) {
[178] Fix | Delete
$msg = $e->getMessage();
[179] Fix | Delete
$this->log("id_from_path failure: exception (".get_class($e)."): ".$msg.' (line: '.$e->getLine().', file: '.$e->getFile().')');
[180] Fix | Delete
if (is_a($e, 'UDP_Google_Service_Exception') && false !== strpos($msg, 'Invalid json in service response') && function_exists('mb_strpos')) {
[181] Fix | Delete
// Aug 2015: saw a case where the gzip-encoding was not removed from the result
[182] Fix | Delete
// https://stackoverflow.com/questions/10975775/how-to-determine-if-a-string-was-compressed
[183] Fix | Delete
// @codingStandardsIgnoreLine
[184] Fix | Delete
$is_gzip = (false !== mb_strpos($msg, "\x1f\x8b\x08"));
[185] Fix | Delete
if ($is_gzip) $this->log("Error: Response appears to be gzip-encoded still; something is broken in the client HTTP stack, and you should define UPDRAFTPLUS_GOOGLEDRIVE_DISABLEGZIP as true in your wp-config.php to overcome this.");
[186] Fix | Delete
}
[187] Fix | Delete
$retry_count--;
[188] Fix | Delete
$this->log("id_from_path: retry ($retry_count)");
[189] Fix | Delete
if ($retry_count > 0) {
[190] Fix | Delete
$delay_in_seconds = defined('UPDRAFTPLUS_GOOGLE_DRIVE_GET_FOLDER_ID_SECOND_RETRY_DELAY') ? UPDRAFTPLUS_GOOGLE_DRIVE_GET_FOLDER_ID_SECOND_RETRY_DELAY : 5-$retry_count;
[191] Fix | Delete
sleep($delay_in_seconds);
[192] Fix | Delete
return $this->id_from_path($path, $one_only, $retry_count);
[193] Fix | Delete
}
[194] Fix | Delete
return false;
[195] Fix | Delete
}
[196] Fix | Delete
}
[197] Fix | Delete
[198] Fix | Delete
/**
[199] Fix | Delete
* Runs upon the WP action updraftplus_prune_retained_backups_finished
[200] Fix | Delete
*/
[201] Fix | Delete
public function prune_retained_backups_finished() {
[202] Fix | Delete
if (empty($this->multi_directories) || count($this->multi_directories) < 2) return;
[203] Fix | Delete
$storage = $this->bootstrap();
[204] Fix | Delete
if (false == $storage || is_wp_error($storage)) return;
[205] Fix | Delete
foreach (array_keys($this->multi_directories) as $drive_id) {
[206] Fix | Delete
if (!isset($oldest_reference)) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable
[207] Fix | Delete
$oldest_id = $drive_id;
[208] Fix | Delete
$oldest_reference = new UDP_Google_Service_Drive_ParentReference;
[209] Fix | Delete
$oldest_reference->setId($oldest_id);
[210] Fix | Delete
continue;
[211] Fix | Delete
}
[212] Fix | Delete
[213] Fix | Delete
// All found files should be moved to the oldest folder
[214] Fix | Delete
[215] Fix | Delete
try {
[216] Fix | Delete
$sub_items = $this->get_subitems($drive_id, 'file');
[217] Fix | Delete
} catch (Exception $e) {
[218] Fix | Delete
$this->log('list files: failed to access chosen folder: '.$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')');
[219] Fix | Delete
}
[220] Fix | Delete
[221] Fix | Delete
$without_errors = true;
[222] Fix | Delete
[223] Fix | Delete
foreach ($sub_items as $item) {
[224] Fix | Delete
$title = "(unknown)";
[225] Fix | Delete
try {
[226] Fix | Delete
$title = $item->getTitle();
[227] Fix | Delete
[228] Fix | Delete
$this->log("Moving: $title (".$item->getId().") from duplicate folder $drive_id to $oldest_id");
[229] Fix | Delete
[230] Fix | Delete
$file = new UDP_Google_Service_Drive_DriveFile();
[231] Fix | Delete
$file->setParents(array($oldest_reference));
[232] Fix | Delete
[233] Fix | Delete
$storage->files->patch($item->getId(), $file);
[234] Fix | Delete
[235] Fix | Delete
} catch (Exception $e) {
[236] Fix | Delete
$this->log("move: exception: ".$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')');
[237] Fix | Delete
$without_errors = false;
[238] Fix | Delete
continue;
[239] Fix | Delete
}
[240] Fix | Delete
}
[241] Fix | Delete
[242] Fix | Delete
if ($without_errors) {
[243] Fix | Delete
if (!empty($sub_items)) {
[244] Fix | Delete
try {
[245] Fix | Delete
$sub_items = $this->get_subitems($drive_id, 'file');
[246] Fix | Delete
} catch (Exception $e) {
[247] Fix | Delete
$this->log('list files: failed to access chosen folder: '.$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')');
[248] Fix | Delete
}
[249] Fix | Delete
}
[250] Fix | Delete
if (empty($sub_items)) {
[251] Fix | Delete
try {
[252] Fix | Delete
$storage->files->delete($drive_id);
[253] Fix | Delete
$this->log("removed empty duplicate folder ($drive_id)");
[254] Fix | Delete
} catch (Exception $e) {
[255] Fix | Delete
$this->log("delete empty duplicate folder ($drive_id): exception: ".$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')');
[256] Fix | Delete
continue;
[257] Fix | Delete
}
[258] Fix | Delete
}
[259] Fix | Delete
}
[260] Fix | Delete
[261] Fix | Delete
}
[262] Fix | Delete
}
[263] Fix | Delete
[264] Fix | Delete
/**
[265] Fix | Delete
* Get the Google Drive internal ID
[266] Fix | Delete
*
[267] Fix | Delete
* @param Array $opts - storage instance options
[268] Fix | Delete
* @param Boolean $one_only - whether to potentially return them all if there is more than one
[269] Fix | Delete
*
[270] Fix | Delete
* @return String|Array
[271] Fix | Delete
*/
[272] Fix | Delete
private function get_parent_id($opts, $one_only = true) {
[273] Fix | Delete
[274] Fix | Delete
$storage = $this->get_storage();
[275] Fix | Delete
[276] Fix | Delete
$filtered = apply_filters('updraftplus_googledrive_parent_id', false, $opts, $storage, $this, $one_only);
[277] Fix | Delete
if (!empty($filtered)) return $filtered;
[278] Fix | Delete
if (isset($opts['parentid'])) {
[279] Fix | Delete
if (empty($opts['parentid'])) {
[280] Fix | Delete
return $this->root_id();
[281] Fix | Delete
} else {
[282] Fix | Delete
$parent = is_array($opts['parentid']) ? $opts['parentid']['id'] : $opts['parentid'];
[283] Fix | Delete
}
[284] Fix | Delete
} else {
[285] Fix | Delete
$parent = $this->id_from_path('UpdraftPlus', $one_only);
[286] Fix | Delete
}
[287] Fix | Delete
return empty($parent) ? $this->root_id() : $parent;
[288] Fix | Delete
}
[289] Fix | Delete
[290] Fix | Delete
public function listfiles($match = 'backup_') {
[291] Fix | Delete
[292] Fix | Delete
$opts = $this->get_options();
[293] Fix | Delete
[294] Fix | Delete
$use_master = $this->use_master($opts);
[295] Fix | Delete
[296] Fix | Delete
if (!$use_master) {
[297] Fix | Delete
if (empty($opts['secret']) || empty($opts['clientid']) || empty($opts['clientid'])) return new WP_Error('no_settings', sprintf(__('No %s settings were found', 'updraftplus'), __('Google Drive', 'updraftplus')));
[298] Fix | Delete
} else {
[299] Fix | Delete
if (empty($opts['user_id']) || empty($opts['tmp_access_token'])) return new WP_Error('no_settings', sprintf(__('No %s settings were found', 'updraftplus'), __('Google Drive', 'updraftplus')));
[300] Fix | Delete
}
[301] Fix | Delete
[302] Fix | Delete
$storage = $this->bootstrap();
[303] Fix | Delete
if (is_wp_error($storage) || false == $storage) return $storage;
[304] Fix | Delete
[305] Fix | Delete
try {
[306] Fix | Delete
$parent_id = $this->get_parent_id($opts);
[307] Fix | Delete
$sub_items = $this->get_subitems($parent_id, 'file');
[308] Fix | Delete
} catch (Exception $e) {
[309] Fix | Delete
return new WP_Error(__('Google Drive list files: failed to access parent folder', 'updraftplus').": ".$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')');
[310] Fix | Delete
}
[311] Fix | Delete
[312] Fix | Delete
$results = array();
[313] Fix | Delete
[314] Fix | Delete
foreach ($sub_items as $item) {
[315] Fix | Delete
$title = "(unknown)";
[316] Fix | Delete
try {
[317] Fix | Delete
$title = $item->getTitle();
[318] Fix | Delete
if (0 === strpos($title, $match)) {
[319] Fix | Delete
$results[] = array('name' => $title, 'size' => $item->getFileSize());
[320] Fix | Delete
}
[321] Fix | Delete
} catch (Exception $e) {
[322] Fix | Delete
$this->log("list: exception: ".$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')');
[323] Fix | Delete
continue;
[324] Fix | Delete
}
[325] Fix | Delete
}
[326] Fix | Delete
[327] Fix | Delete
return $results;
[328] Fix | Delete
}
[329] Fix | Delete
[330] Fix | Delete
/**
[331] Fix | Delete
* Get a Google account access token using the refresh token
[332] Fix | Delete
*
[333] Fix | Delete
* @param String $refresh_token Specify refresh token
[334] Fix | Delete
* @param String $client_id Specify Client ID
[335] Fix | Delete
* @param String $client_secret Specify client secret
[336] Fix | Delete
* @return Boolean
[337] Fix | Delete
*/
[338] Fix | Delete
private function access_token($refresh_token, $client_id, $client_secret) {
[339] Fix | Delete
[340] Fix | Delete
$this->log("requesting access token: client_id=$client_id");
[341] Fix | Delete
[342] Fix | Delete
$query_body = array(
[343] Fix | Delete
'refresh_token' => $refresh_token,
[344] Fix | Delete
'client_id' => $client_id,
[345] Fix | Delete
'client_secret' => $client_secret,
[346] Fix | Delete
'grant_type' => 'refresh_token'
[347] Fix | Delete
);
[348] Fix | Delete
[349] Fix | Delete
$result = wp_remote_post('https://accounts.google.com/o/oauth2/token',
[350] Fix | Delete
array(
[351] Fix | Delete
'timeout' => '20',
[352] Fix | Delete
'method' => 'POST',
[353] Fix | Delete
'body' => $query_body
[354] Fix | Delete
)
[355] Fix | Delete
);
[356] Fix | Delete
[357] Fix | Delete
if (is_wp_error($result)) {
[358] Fix | Delete
$this->log("error when requesting access token");
[359] Fix | Delete
foreach ($result->get_error_messages() as $msg) $this->log("Error message: $msg");
[360] Fix | Delete
return false;
[361] Fix | Delete
} else {
[362] Fix | Delete
$json_values = json_decode(wp_remote_retrieve_body($result), true);
[363] Fix | Delete
if (isset($json_values['access_token'])) {
[364] Fix | Delete
$this->log("successfully obtained access token");
[365] Fix | Delete
return $json_values['access_token'];
[366] Fix | Delete
} else {
[367] Fix | Delete
$response = json_decode($result['body'], true);
[368] Fix | Delete
if (!empty($response['error']) && 'deleted_client' == $response['error']) {
[369] Fix | Delete
$this->log(__('The client has been deleted from the Google Drive API console. Please create a new Google Drive project and reconnect with UpdraftPlus.', 'updraftplus'), 'error');
[370] Fix | Delete
}
[371] Fix | Delete
$error_code = empty($response['error']) ? 'no error code' : $response['error'];
[372] Fix | Delete
$this->log("error ($error_code) when requesting access token: response does not contain access_token. Response: ".(is_string($result['body']) ? str_replace("\n", '', $result['body']) : json_encode($result['body'])));
[373] Fix | Delete
return false;
[374] Fix | Delete
}
[375] Fix | Delete
}
[376] Fix | Delete
}
[377] Fix | Delete
[378] Fix | Delete
/**
[379] Fix | Delete
* This method will return a redirect URL depending on the parameter passed. It will either return the redirect for the user's site or the auth server.
[380] Fix | Delete
*
[381] Fix | Delete
* @param Boolean $master - indicate whether we want the master redirect URL
[382] Fix | Delete
* @return String - a redirect URL
[383] Fix | Delete
*/
[384] Fix | Delete
private function redirect_uri($master = false) {
[385] Fix | Delete
if ($master) {
[386] Fix | Delete
return $this->callback_url;
[387] Fix | Delete
} else {
[388] Fix | Delete
return UpdraftPlus_Options::admin_page_url().'?action=updraftmethod-googledrive-auth';
[389] Fix | Delete
}
[390] Fix | Delete
}
[391] Fix | Delete
[392] Fix | Delete
/**
[393] Fix | Delete
* Acquire single-use authorization code from Google via OAuth 2.0
[394] Fix | Delete
*
[395] Fix | Delete
* @param String $instance_id - the instance id of the settings we want to authenticate
[396] Fix | Delete
*/
[397] Fix | Delete
public function do_authenticate_storage($instance_id) {
[398] Fix | Delete
$opts = $this->get_options();
[399] Fix | Delete
[400] Fix | Delete
$use_master = $this->use_master($opts);
[401] Fix | Delete
[402] Fix | Delete
// First, revoke any existing token, since Google doesn't appear to like issuing new ones
[403] Fix | Delete
if (!empty($opts['token']) && !$use_master) $this->gdrive_auth_revoke();
[404] Fix | Delete
[405] Fix | Delete
// Set a flag so we know this authentication is in progress
[406] Fix | Delete
$opts['auth_in_progress'] = true;
[407] Fix | Delete
$this->set_options($opts, true);
[408] Fix | Delete
[409] Fix | Delete
$prefixed_instance_id = ':' . $instance_id;
[410] Fix | Delete
[411] Fix | Delete
// We use 'force' here for the approval_prompt, not 'auto', as that deals better with messy situations where the user authenticated, then changed settings
[412] Fix | Delete
[413] Fix | Delete
if ($use_master) {
[414] Fix | Delete
$client_id = $this->client_id;
[415] Fix | Delete
$token = 'token'.$prefixed_instance_id.$this->redirect_uri();
[416] Fix | Delete
} else {
[417] Fix | Delete
$client_id = $opts['clientid'];
[418] Fix | Delete
$token = 'token'.$prefixed_instance_id;
[419] Fix | Delete
}
[420] Fix | Delete
// We require access to all Google Drive files (not just ones created by this app - scope https://www.googleapis.com/auth/drive.file) - because we need to be able to re-scan storage for backups uploaded by other installs, or manually by the user into their Google Drive. But, if you are happy to lose that capability, you can use the filter below to remove the drive.readonly scope.
[421] Fix | Delete
$params = array(
[422] Fix | Delete
'response_type' => 'code',
[423] Fix | Delete
'client_id' => $client_id,
[424] Fix | Delete
'redirect_uri' => $this->redirect_uri($use_master),
[425] Fix | Delete
'scope' => apply_filters('updraft_googledrive_scope', 'https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/userinfo.profile'),
[426] Fix | Delete
'state' => $token,
[427] Fix | Delete
'access_type' => 'offline',
[428] Fix | Delete
'approval_prompt' => 'force'
[429] Fix | Delete
);
[430] Fix | Delete
if (headers_sent()) {
[431] Fix | Delete
$this->log(sprintf(__('The %s authentication could not go ahead, because something else on your site is breaking it. Try disabling your other plugins and switching to a default theme. (Specifically, you are looking for the component that sends output (most likely PHP warnings/errors) before the page begins. Turning off any debugging settings may also help).', ''), 'Google Drive'), 'error');
[432] Fix | Delete
} else {
[433] Fix | Delete
header('Location: https://accounts.google.com/o/oauth2/auth?'.http_build_query($params, null, '&'));
[434] Fix | Delete
}
[435] Fix | Delete
}
[436] Fix | Delete
[437] Fix | Delete
/**
[438] Fix | Delete
* This function will complete the oAuth flow, if return_instead_of_echo is true then add the action to display the authed admin notice, otherwise echo this notice to page.
[439] Fix | Delete
*
[440] Fix | Delete
* @param string $state - the state
[441] Fix | Delete
* @param string $code - the oauth code
[442] Fix | Delete
* @param boolean $return_instead_of_echo - a boolean to indicate if we should return the result or echo it
[443] Fix | Delete
*
[444] Fix | Delete
* @return void|string - returns the authentication message if return_instead_of_echo is true
[445] Fix | Delete
*/
[446] Fix | Delete
public function do_complete_authentication($state, $code, $return_instead_of_echo = false) {
[447] Fix | Delete
[448] Fix | Delete
// If these are set then this is a request from our master app and the auth server has returned these to be saved.
[449] Fix | Delete
if (isset($code['user_id']) && isset($code['access_token'])) {
[450] Fix | Delete
$opts = $this->get_options();
[451] Fix | Delete
$opts['user_id'] = base64_decode($code['user_id']);
[452] Fix | Delete
$opts['tmp_access_token'] = base64_decode($code['access_token']);
[453] Fix | Delete
// Unset this value if it is set as this is a fresh auth we will set this value in the next step
[454] Fix | Delete
if (isset($opts['expires_in'])) unset($opts['expires_in']);
[455] Fix | Delete
// remove our flag so we know this authentication is complete
[456] Fix | Delete
if (isset($opts['auth_in_progress'])) unset($opts['auth_in_progress']);
[457] Fix | Delete
$this->set_options($opts, true);
[458] Fix | Delete
}
[459] Fix | Delete
[460] Fix | Delete
if ($return_instead_of_echo) {
[461] Fix | Delete
return $this->show_authed_admin_success($return_instead_of_echo);
[462] Fix | Delete
} else {
[463] Fix | Delete
add_action('all_admin_notices', array($this, 'show_authed_admin_success'));
[464] Fix | Delete
}
[465] Fix | Delete
}
[466] Fix | Delete
[467] Fix | Delete
/**
[468] Fix | Delete
* Revoke a Google account refresh token
[469] Fix | Delete
* Returns the parameter fed in, so can be used as a WordPress options filter
[470] Fix | Delete
* Can be called statically from UpdraftPlus::googledrive_clientid_checkchange()
[471] Fix | Delete
*
[472] Fix | Delete
* @param Boolean $unsetopt unset options is set to true unless otherwise specified
[473] Fix | Delete
*/
[474] Fix | Delete
public function gdrive_auth_revoke($unsetopt = true) {
[475] Fix | Delete
$opts = $this->get_options();
[476] Fix | Delete
$result = wp_remote_get('https://accounts.google.com/o/oauth2/revoke?token='.$opts['token']);
[477] Fix | Delete
[478] Fix | Delete
// If the call to revoke the token fails, we try again one more time
[479] Fix | Delete
if (is_wp_error($result) || 200 != wp_remote_retrieve_response_code($result)) {
[480] Fix | Delete
wp_remote_get('https://accounts.google.com/o/oauth2/revoke?token='.$opts['token']);
[481] Fix | Delete
}
[482] Fix | Delete
[483] Fix | Delete
if ($unsetopt) {
[484] Fix | Delete
$opts['token'] = '';
[485] Fix | Delete
unset($opts['ownername']);
[486] Fix | Delete
$this->set_options($opts, true);
[487] Fix | Delete
}
[488] Fix | Delete
}
[489] Fix | Delete
[490] Fix | Delete
/**
[491] Fix | Delete
* Get a Google account refresh token using the code received from do_authenticate_storage
[492] Fix | Delete
*/
[493] Fix | Delete
public function gdrive_auth_token() {
[494] Fix | Delete
$opts = $this->get_options();
[495] Fix | Delete
if (isset($_GET['code'])) {
[496] Fix | Delete
$post_vars = array(
[497] Fix | Delete
'code' => $_GET['code'],
[498] Fix | Delete
'client_id' => $opts['clientid'],
[499] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function