InfiniteWP Client - Version 1.6.4.2

Version Description

  • Jul 10th 2017 =
  • Improvement: Dropbox API V2 has been integrated with InfiniteWP.
  • Fix: While uploading the backup to Dropbox some users get Dropbox verification failed: File may be corrupted error.
  • Fix: File exceeds 150MB upload limit error while uploading the backups to Dropbox using Single call back method.
  • Fix: Path error if the Dropbox folder have trailing spaces.
Download this release

Release Info

Developer infinitewp
Plugin Icon 128x128 InfiniteWP Client
Version 1.6.4.2
Comparing to
See all releases

Code changes from version 1.6.4 to 1.6.4.2

backup.class.multicall.php CHANGED
@@ -243,6 +243,15 @@ class IWP_MMB_Backup_Multicall extends IWP_MMB_Core
243
244
245
$setMemory = $this->set_resource_limit();
246
247
if(file_exists(IWP_BACKUP_DIR) && is_dir(IWP_BACKUP_DIR)){
248
$this->statusLog($historyID, array('stage' => 'verification', 'status' => 'processing', 'statusMsg' => 'Directory Writable'));
@@ -4045,16 +4054,23 @@ function ftp_backup($historyID,$args = '')
4045
$size2 = $actual_file_size+((0.1) * $actual_file_size);
4046
if($type == "dropbox")
4047
{
4048
- $dBoxMetaData = $obj -> metadata($destFile);
4049
- $dBoxFileSize = $dBoxMetaData['bytes'];
4050
- if((($dBoxFileSize >= $size1 && $dBoxFileSize <= $actual_file_size) || ($dBoxFileSize <= $size2 && $dBoxFileSize >= $actual_file_size) || ($dBoxFileSize == $actual_file_size)) && ($dBoxFileSize != 0))
4051
- {
4052
- return true;
4053
}
4054
- else
4055
- {
4056
- return false;
4057
}
4058
}
4059
else if($type == "amazons3")
4060
{
@@ -4351,17 +4367,41 @@ function ftp_backup($historyID,$args = '')
4351
'partial' => 1, 'error_code' => 'cannot_use_dropbox_enable_curl_first'
4352
);
4353
}
4354
- if(isset($consumer_secret) && !empty($consumer_secret)){
4355
4356
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/dropbox.php';
4357
-
4358
- $dropbox = new IWP_Dropbox($consumer_key, $consumer_secret);
4359
- $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
4360
-
4361
- if (isset($dropbox_site_folder) && $dropbox_site_folder == true)
4362
- $dropbox_destination .= '/' . $this->site_name . '/' . basename($backup_file);
4363
- else
4364
- $dropbox_destination .= '/' . basename($backup_file);
4365
4366
try {
4367
//$dropbox->upload($backup_file, $dropbox_destination, true); //we are using new multiCAll function
@@ -4380,7 +4420,7 @@ function ftp_backup($historyID,$args = '')
4380
{
4381
$chunkStartTime = microtime(true);
4382
}
4383
- if(($backup_file_size - $offset) >= $upload_file_block_size) //the chunk size is set here
4384
{
4385
$readsize = $upload_file_block_size;
4386
$isCommit = false;
@@ -4393,8 +4433,11 @@ function ftp_backup($historyID,$args = '')
4393
$isCommit = true;
4394
$status = 'completed';
4395
}
4396
- $chunkResult = $dropbox->chunked_upload($backup_file, $dropbox_destination, true, $uploadid, $offset, $readsize, $isCommit);
4397
-
4398
$result_arr = array();
4399
$result_arr['response_data'] = $chunkResult;
4400
$result_arr['status'] = $status;
@@ -4416,7 +4459,11 @@ function ftp_backup($historyID,$args = '')
4416
echo " dBoxTimeLeft".$dBoxTimeLeft;
4417
//$halfOfLoopTime = (($upload_loop_break_time / 2) - 1);
4418
if(($dBoxTimeLeft <= $chunkTimeTaken)||($status == 'completed')) //if the time Left for the dropbox upload is less than the time to upload a single chunk break the loop
4419
- {
4420
$reloop = false;
4421
}
4422
else
@@ -4474,7 +4521,7 @@ function ftp_backup($historyID,$args = '')
4474
// Try the indicated offset
4475
$we_tried = $matches[1];
4476
$offset = $matches[2];
4477
- $chunkResult = $dropbox->chunked_upload($backup_file, $dropbox_destination, true, $uploadid, $offset, $readsize, $isCommit);
4478
$result_arr = array();
4479
$result_arr['response_data'] = $chunkResult;
4480
$result_arr['nextFunc'] = 'dropbox_backup';
@@ -4512,13 +4559,38 @@ function ftp_backup($historyID,$args = '')
4512
function remove_dropbox_backup($args) {
4513
extract($args);
4514
4515
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/dropbox.php';
4516
-
4517
- $dropbox = new IWP_Dropbox($consumer_key, $consumer_secret);
4518
- $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
4519
4520
- if ($dropbox_site_folder == true)
4521
- $dropbox_destination .= '/' . $this->site_name;
4522
4523
$temp_backup_file = $backup_file;
4524
if(!is_array($backup_file))
@@ -4529,7 +4601,11 @@ function ftp_backup($historyID,$args = '')
4529
foreach($backup_file as $key => $value)
4530
{
4531
try {
4532
- $dropbox->fileopsDelete($dropbox_destination . '/' . $value);
4533
} catch (Exception $e) {
4534
$this->_log($e->getMessage());
4535
/*return array(
@@ -4545,21 +4621,49 @@ function ftp_backup($historyID,$args = '')
4545
function get_dropbox_backup($args) {
4546
if ($this->iwp_mmb_function_exists('curl_init')) {
4547
extract($args);
4548
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/dropbox.php';
4549
-
4550
- $dropbox = new IWP_Dropbox($consumer_key, $consumer_secret);
4551
- $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
4552
-
4553
- if ($dropbox_site_folder == true)
4554
$dropbox_destination .= '/' . $this->site_name;
4555
4556
//$temp = ABSPATH . 'iwp_temp_backup.zip';
4557
$temp = wp_tempnam('iwp_temp_backup.zip');
4558
4559
try {
4560
-
4561
//exception should handle the errors
4562
- $dropbox->download($dropbox_destination.'/'.$backup_file, $temp);
4563
return $temp;
4564
} catch (Exception $e) {
4565
$this->_log($e->getMessage());
@@ -5780,7 +5884,9 @@ function ftp_backup($historyID,$args = '')
5780
$dropbox_file = $task_result['task_results'][$backup_data['historyID']]['dropbox'];
5781
$args = $thisRequestParams['account_info']['iwp_dropbox'];
5782
$args['backup_file'] = $dropbox_file;
5783
- $this->remove_dropbox_backup($args);
5784
}
5785
5786
if (isset($task_result['task_results'][$backup_data['historyID']]['gDrive'])) {
@@ -6420,6 +6526,15 @@ function ftp_backup($historyID,$args = '')
6420
return false;
6421
}
6422
}
6423
6424
if(!function_exists('iwp_alter_file_list_table')){
6425
function iwp_alter_file_list_table(){
@@ -6494,6 +6609,35 @@ if (!function_exists('iwp_modify_table_description')) {
6494
return $temp_table;
6495
}
6496
}
6497
/*if( function_exists('add_filter') ){
6498
add_filter( 'iwp_website_add', 'IWP_MMB_Backup::readd_tasks' );
6499
}*/
243
244
245
$setMemory = $this->set_resource_limit();
246
+
247
+ if(!empty($params['account_info']) && !empty($params['account_info']['iwp_dropbox'])){
248
+ if(empty($params['account_info']['iwp_dropbox']['dropbox_access_token']) && time() > 1506556800){
249
+ return $this->statusLog($historyID, array('stage' => 'verification', 'status' => 'error', 'statusMsg' => 'Please update your cloud backup addon to v1.2.0 or above to use Dropbox API V2', 'statusCode' => 'drop_box_update'));
250
+ }elseif(!is_new_dropbox_compatible()){
251
+ return $this->statusLog($historyID, array('stage' => 'verification', 'status' => 'error', 'statusMsg' => 'Please upgrade your PHP version to 5.3.3 or above to use Dropbox V2 API', 'statusCode' => 'drop_box_version_incompitability'));
252
+ }
253
+ upgradeOldDropBoxBackupList($params['account_info']['iwp_dropbox']);
254
+ }
255
256
if(file_exists(IWP_BACKUP_DIR) && is_dir(IWP_BACKUP_DIR)){
257
$this->statusLog($historyID, array('stage' => 'verification', 'status' => 'processing', 'statusMsg' => 'Directory Writable'));
4054
$size2 = $actual_file_size+((0.1) * $actual_file_size);
4055
if($type == "dropbox")
4056
{
4057
+ $dBoxMetaData = $obj -> metaData($destFile);
4058
+ $filename = basename($backup_file);
4059
+ $path = '/'.$destFile.$filename;
4060
+ if (empty($dBoxMetaData['body']->contents)) {
4061
+ return true;
4062
}
4063
+ foreach ($dBoxMetaData['body']->contents as $key => $value) {
4064
+ if(strtolower($path) == strtolower($value->path)){
4065
+ $dBoxFileSize = $value->bytes;
4066
+ if((($dBoxFileSize >= $size1 && $dBoxFileSize <= $actual_file_size) || ($dBoxFileSize <= $size2 && $dBoxFileSize >= $actual_file_size) || ($dBoxFileSize == $actual_file_size)) && ($dBoxFileSize != 0))
4067
+ {
4068
+ return true;
4069
+ }
4070
+ }
4071
}
4072
+
4073
+ return false;
4074
}
4075
else if($type == "amazons3")
4076
{
4367
'partial' => 1, 'error_code' => 'cannot_use_dropbox_enable_curl_first'
4368
);
4369
}
4370
+ $oldVersion = false;
4371
+ if((isset($consumer_secret) && !empty($consumer_secret)) || (isset($dropbox_access_token) && !empty($dropbox_access_token))){
4372
+ if(!isset($dropbox_access_token) && empty($dropbox_access_token)){
4373
4374
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/dropbox.php';
4375
+
4376
+ $dropbox = new IWP_Dropbox($consumer_key, $consumer_secret);
4377
+ $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
4378
+ $oldVersion = true;
4379
+ if (isset($dropbox_site_folder) && $dropbox_site_folder == true)
4380
+ $dropbox_destination .= '/' . $this->site_name . '/' . basename($backup_file);
4381
+ else
4382
+ $dropbox_destination .= '/' . basename($backup_file);
4383
+ }else{
4384
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/API.php';
4385
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/Exception.php';
4386
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/OAuth/Consumer/ConsumerAbstract.php';
4387
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/OAuth/Consumer/Curl.php';
4388
+
4389
+ $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
4390
+ $oauth->setToken($dropbox_access_token);
4391
+ $dropbox = new IWP_Dropbox_API($oauth);
4392
+ $oldRoot = 'Apps/InfiniteWP/';
4393
+ $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
4394
+ $dropbox_destination = rtrim($dropbox_destination, '/');
4395
+ if (isset($dropbox_site_folder) && $dropbox_site_folder == true){
4396
+ $dropbox_destination .= '/'.$this->site_name;
4397
+ }
4398
+ $folders = explode('/',$dropbox_destination);
4399
+ foreach ($folders as $key => $name) {
4400
+ $path.=trim($name).'/';
4401
+ }
4402
+ $dropbox_destination = $path;
4403
+
4404
+ }
4405
4406
try {
4407
//$dropbox->upload($backup_file, $dropbox_destination, true); //we are using new multiCAll function
4420
{
4421
$chunkStartTime = microtime(true);
4422
}
4423
+ if(($backup_file_size - $offset) >= 4194304) //the chunk size is set here
4424
{
4425
$readsize = $upload_file_block_size;
4426
$isCommit = false;
4433
$isCommit = true;
4434
$status = 'completed';
4435
}
4436
+ if($oldVersion){
4437
+ $chunkResult = $dropbox->chunked_upload($backup_file, $dropbox_destination, true, $uploadid, $offset, $readsize, $isCommit);
4438
+ }else{
4439
+ $chunkResult = $dropbox->chunked_upload($backup_file ,$dropbox_destination, true, $uploadid, $offset, $isCommit);
4440
+ }
4441
$result_arr = array();
4442
$result_arr['response_data'] = $chunkResult;
4443
$result_arr['status'] = $status;
4459
echo " dBoxTimeLeft".$dBoxTimeLeft;
4460
//$halfOfLoopTime = (($upload_loop_break_time / 2) - 1);
4461
if(($dBoxTimeLeft <= $chunkTimeTaken)||($status == 'completed')) //if the time Left for the dropbox upload is less than the time to upload a single chunk break the loop
4462
+ {
4463
+ if ($status == 'complete') {
4464
+ $result_arr['response_data']['offset'] = 0;
4465
+ $result_arr['response_data']['upload_id'] = null;
4466
+ }
4467
$reloop = false;
4468
}
4469
else
4521
// Try the indicated offset
4522
$we_tried = $matches[1];
4523
$offset = $matches[2];
4524
+ $chunkResult = $dropbox->chunked_upload($backup_file, $dropbox_destination, true, $uploadid, $offset, $isCommit);
4525
$result_arr = array();
4526
$result_arr['response_data'] = $chunkResult;
4527
$result_arr['nextFunc'] = 'dropbox_backup';
4559
function remove_dropbox_backup($args) {
4560
extract($args);
4561
4562
+ if(!isset($dropbox_access_token) && empty($dropbox_access_token)){
4563
+
4564
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/dropbox.php';
4565
+
4566
+ $dropbox = new IWP_Dropbox($consumer_key, $consumer_secret);
4567
+ $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
4568
+ $oldVersion = true;
4569
+ if ($dropbox_site_folder == true)
4570
+ $dropbox_destination .= '/' . $this->site_name;
4571
+ }else{
4572
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/API.php';
4573
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/Exception.php';
4574
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/OAuth/Consumer/ConsumerAbstract.php';
4575
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/OAuth/Consumer/Curl.php';
4576
+
4577
+ $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
4578
+ $oauth->setToken($dropbox_access_token);
4579
+ $dropbox = new IWP_Dropbox_API($oauth);
4580
+ $oldRoot = 'Apps/InfiniteWP/';
4581
+ $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
4582
+ $dropbox_destination = rtrim($dropbox_destination, '/');
4583
+ if (isset($dropbox_site_folder) && $dropbox_site_folder == true){
4584
+ $dropbox_destination .= '/'.$this->site_name;
4585
+ }
4586
+ $folders = explode('/',$dropbox_destination);
4587
+ foreach ($folders as $key => $name) {
4588
+ $path.=trim($name).'/';
4589
+ }
4590
+ $dropbox_destination = $path;
4591
+ $oldVersion = false;
4592
+ }
4593
4594
4595
$temp_backup_file = $backup_file;
4596
if(!is_array($backup_file))
4601
foreach($backup_file as $key => $value)
4602
{
4603
try {
4604
+ if ($oldVersion) {
4605
+ $dropbox->fileopsDelete($dropbox_destination . '/' . $value);
4606
+ }else{
4607
+ $dropbox->delete($dropbox_destination . '/' . $value);
4608
+ }
4609
} catch (Exception $e) {
4610
$this->_log($e->getMessage());
4611
/*return array(
4621
function get_dropbox_backup($args) {
4622
if ($this->iwp_mmb_function_exists('curl_init')) {
4623
extract($args);
4624
+ if(!isset($dropbox_access_token) && empty($dropbox_access_token)){
4625
+
4626
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/dropbox.php';
4627
+
4628
+ $dropbox = new IWP_Dropbox($consumer_key, $consumer_secret);
4629
+ $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
4630
+ $oldVersion = true;
4631
+ if ($dropbox_site_folder == true)
4632
$dropbox_destination .= '/' . $this->site_name;
4633
+ }else{
4634
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/API.php';
4635
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/Exception.php';
4636
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/OAuth/Consumer/ConsumerAbstract.php';
4637
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/OAuth/Consumer/Curl.php';
4638
+
4639
+ $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
4640
+ $oauth->setToken($dropbox_access_token);
4641
+ $dropbox = new IWP_Dropbox_API($oauth);
4642
+ $oldRoot = 'Apps/InfiniteWP/';
4643
+ $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
4644
+ $dropbox_destination = rtrim($dropbox_destination, '/');
4645
+ if (isset($dropbox_site_folder) && $dropbox_site_folder == true){
4646
+ $dropbox_destination .= '/'.$this->site_name;
4647
+ }
4648
+ $folders = explode('/',$dropbox_destination);
4649
+ foreach ($folders as $key => $name) {
4650
+ $path.=trim($name).'/';
4651
+ }
4652
+ $dropbox_destination = $path;
4653
+ $oldVersion = false;
4654
+ }
4655
+
4656
4657
//$temp = ABSPATH . 'iwp_temp_backup.zip';
4658
$temp = wp_tempnam('iwp_temp_backup.zip');
4659
4660
try {
4661
//exception should handle the errors
4662
+ if ($oldVersion) {
4663
+ $dropbox->download($dropbox_destination.'/'.$backup_file, $temp);
4664
+ }else{
4665
+ $dropbox->getFile($dropbox_destination.'/'.$backup_file, $temp);
4666
+ }
4667
return $temp;
4668
} catch (Exception $e) {
4669
$this->_log($e->getMessage());
5884
$dropbox_file = $task_result['task_results'][$backup_data['historyID']]['dropbox'];
5885
$args = $thisRequestParams['account_info']['iwp_dropbox'];
5886
$args['backup_file'] = $dropbox_file;
5887
+ if(!empty($args['dropbox_access_token']) || (empty($args['dropbox_access_token']) && time() < 1498608000)){
5888
+ $this->remove_dropbox_backup($args);
5889
+ }
5890
}
5891
5892
if (isset($task_result['task_results'][$backup_data['historyID']]['gDrive'])) {
6526
return false;
6527
}
6528
}
6529
+
6530
+ if( !function_exists('is_new_dropbox_compatible') ){
6531
+ function is_new_dropbox_compatible(){
6532
+ if(version_compare(phpversion() , '5.3.3', '>=')){
6533
+ return true;
6534
+ }
6535
+ return false;
6536
+ }
6537
+ }
6538
6539
if(!function_exists('iwp_alter_file_list_table')){
6540
function iwp_alter_file_list_table(){
6609
return $temp_table;
6610
}
6611
}
6612
+
6613
+ if( !function_exists('upgradeOldDropBoxBackupList')){
6614
+ function upgradeOldDropBoxBackupList($dropBoxInfo){
6615
+ if (!isset($dropBoxInfo['dropbox_access_token']) && empty($dropBoxInfo['dropbox_access_token']) ) {
6616
+ return false;
6617
+ }
6618
+ global $wpdb;
6619
+ $table_name = $wpdb->base_prefix . "iwp_backup_status";
6620
+
6621
+ $rows = $wpdb->get_results("SELECT ID, taskName, taskResults, requestParams FROM ".$table_name." ORDER BY ID DESC", ARRAY_A);
6622
+ if (empty($rows)) {
6623
+ return false;
6624
+ }
6625
+ foreach ($rows as $ID => $taskArray) {
6626
+ $requestParams = unserialize($taskArray['requestParams']);
6627
+ $accountInfo = $requestParams['account_info'];
6628
+ if (isset($accountInfo['iwp_dropbox']) && isset($accountInfo['iwp_dropbox']['oauth_token']) && !empty($accountInfo['iwp_dropbox']['oauth_token'])) {
6629
+ $requestParams['account_info']['iwp_dropbox']['consumer_key'] = '';
6630
+ $requestParams['account_info']['iwp_dropbox']['consumer_secret'] = '';
6631
+ $requestParams['account_info']['iwp_dropbox']['oauth_token'] = '';
6632
+ $requestParams['account_info']['iwp_dropbox']['oauth_token_secret'] = '';
6633
+ $requestParams['account_info']['iwp_dropbox']['dropbox_app_key'] = $dropBoxInfo['dropbox_app_key'];
6634
+ $requestParams['account_info']['iwp_dropbox']['dropbox_app_secure_key'] = $dropBoxInfo['dropbox_app_secure_key'];
6635
+ $requestParams['account_info']['iwp_dropbox']['dropbox_access_token'] = $dropBoxInfo['dropbox_access_token'];
6636
+ $update = $wpdb->update($table_name,array( 'requestParams' => serialize($requestParams)),array( 'ID' => $taskArray['ID']),array('%s'),array('%d'));
6637
+ }
6638
+ }
6639
+ }
6640
+ }
6641
/*if( function_exists('add_filter') ){
6642
add_filter( 'iwp_website_add', 'IWP_MMB_Backup::readd_tasks' );
6643
}*/
backup.class.singlecall.php CHANGED
@@ -155,6 +155,15 @@ class IWP_MMB_Backup_Singlecall extends IWP_MMB_Core
155
$this->set_resource_limit();
156
157
$this->tasks = $this->get_this_tasks('requestParams');
158
159
extract($params);
160
@@ -2002,20 +2011,48 @@ function ftp_backup($args)
2002
extract($args);
2003
2004
if ($this->iwp_mmb_function_exists('curl_init')) {
2005
- if(isset($consumer_secret) && !empty($consumer_secret)){
2006
2007
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/dropbox.php';
2008
-
2009
- $dropbox = new IWP_Dropbox($consumer_key, $consumer_secret);
2010
- $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
2011
-
2012
- if ($dropbox_site_folder == true)
2013
- $dropbox_destination .= '/' . $this->site_name . '/' . basename($backup_file);
2014
- else
2015
- $dropbox_destination .= '/' . basename($backup_file);
2016
2017
try {
2018
- $dropbox->upload($backup_file, $dropbox_destination, true);
2019
} catch (Exception $e) {
2020
$this->_log($e->getMessage());
2021
return array(
@@ -2046,13 +2083,39 @@ function ftp_backup($args)
2046
function remove_dropbox_backup($args) {
2047
extract($args);
2048
2049
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/dropbox.php';
2050
2051
- $dropbox = new IWP_Dropbox($consumer_key, $consumer_secret);
2052
- $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
2053
2054
- if ($dropbox_site_folder == true)
2055
- $dropbox_destination .= '/' . $this->site_name;
2056
2057
$temp_backup_file = $backup_file;
2058
if(!is_array($backup_file))
@@ -2063,7 +2126,11 @@ function ftp_backup($args)
2063
foreach($backup_file as $key => $value)
2064
{
2065
try {
2066
- $dropbox->fileopsDelete($dropbox_destination . '/' . $value);
2067
} catch (Exception $e) {
2068
$this->_log($e->getMessage());
2069
/*return array(
@@ -2757,7 +2824,9 @@ function ftp_backup($args)
2757
$dropbox_file = $task_result['task_results'][$backup_data['historyID']]['dropbox'];
2758
$args = $thisRequestParams['account_info']['iwp_dropbox'];
2759
$args['backup_file'] = $dropbox_file;
2760
- $this->remove_dropbox_backup($args);
2761
}
2762
2763
if (isset($task_result['task_results'][$backup_data['historyID']]['gDrive'])) {
@@ -3222,4 +3291,42 @@ if( !function_exists('is_new_s3_compatible') ){
3222
}
3223
}
3224
3225
?>
155
$this->set_resource_limit();
156
157
$this->tasks = $this->get_this_tasks('requestParams');
158
+
159
+ if(!empty($this->tasks['account_info']) && !empty($this->tasks['account_info']['iwp_dropbox'])){
160
+ if(empty($this->tasks['account_info']['iwp_dropbox']['dropbox_access_token']) && time() > 1498608000){
161
+ return array('error' => 'Please update your cloud backup addon to v1.2.0 or above to use Dropbox API V2', 'error_code' => 'drop_box_update');
162
+ }elseif(!is_new_dropbox_compatible()){
163
+ return array('error' => 'Please upgrade your PHP version to 5.3.3 or above to use Dropbox V2 API', 'error_code' => 'drop_box_version_incompitability');
164
+ }
165
+ upgradeOldDropBoxBackupList($this->tasks['account_info']['iwp_dropbox']);
166
+ }
167
168
extract($params);
169
2011
extract($args);
2012
2013
if ($this->iwp_mmb_function_exists('curl_init')) {
2014
+ if((isset($consumer_secret) && !empty($consumer_secret)) || (isset($dropbox_access_token) && !empty($dropbox_access_token))){
2015
2016
+ if(!isset($dropbox_access_token) && empty($dropbox_access_token)){
2017
+
2018
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/dropbox.php';
2019
+
2020
+ $dropbox = new IWP_Dropbox($consumer_key, $consumer_secret);
2021
+ $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
2022
+ $oldVersion = true;
2023
+ if ($dropbox_site_folder == true)
2024
+ $dropbox_destination .= '/' . $this->site_name . '/' . basename($backup_file);
2025
+ else
2026
+ $dropbox_destination .= '/' . basename($backup_file);
2027
+ }else{
2028
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/API.php';
2029
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/Exception.php';
2030
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/OAuth/Consumer/ConsumerAbstract.php';
2031
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/OAuth/Consumer/Curl.php';
2032
+
2033
+ $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
2034
+ $oauth->setToken($dropbox_access_token);
2035
+ $dropbox = new IWP_Dropbox_API($oauth);
2036
+ $oldRoot = 'Apps/InfiniteWP/';
2037
+ $oldVersion = false;
2038
+ $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
2039
+ $dropbox_destination = rtrim($dropbox_destination, '/');
2040
+ if (isset($dropbox_site_folder) && $dropbox_site_folder == true){
2041
+ $dropbox_destination .= '/'.$this->site_name;
2042
+ }
2043
+ $folders = explode('/',$dropbox_destination);
2044
+ foreach ($folders as $key => $name) {
2045
+ $path.=trim($name).'/';
2046
+ }
2047
+ $dropbox_destination = $path;
2048
+ }
2049
2050
try {
2051
+ if ($oldVersion) {
2052
+ $dropbox->upload($backup_file, $dropbox_destination, true);
2053
+ }else{
2054
+ $dropbox->putFile($backup_file, $dropbox_destination, true);
2055
+ }
2056
} catch (Exception $e) {
2057
$this->_log($e->getMessage());
2058
return array(
2083
function remove_dropbox_backup($args) {
2084
extract($args);
2085
2086
+ if(!isset($dropbox_access_token) && empty($dropbox_access_token)){
2087
+
2088
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/dropbox.php';
2089
+
2090
+ $dropbox = new IWP_Dropbox($consumer_key, $consumer_secret);
2091
+ $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
2092
+ if ($dropbox_site_folder == true)
2093
+ $dropbox_destination .= '/' . $this->site_name;
2094
+ $oldVersion = true;
2095
+ }else{
2096
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/API.php';
2097
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/Exception.php';
2098
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/OAuth/Consumer/ConsumerAbstract.php';
2099
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox2/OAuth/Consumer/Curl.php';
2100
+
2101
+ $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
2102
+ $oauth->setToken($dropbox_access_token);
2103
+ $dropbox = new IWP_Dropbox_API($oauth);
2104
+ $oldRoot = 'Apps/InfiniteWP/';
2105
+ $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
2106
+ $dropbox_destination = rtrim($dropbox_destination, '/');
2107
+ if (isset($dropbox_site_folder) && $dropbox_site_folder == true){
2108
+ $dropbox_destination .= '/'.$this->site_name;
2109
+ }
2110
+ $folders = explode('/',$dropbox_destination);
2111
+ foreach ($folders as $key => $name) {
2112
+ $path.=trim($name).'/';
2113
+ }
2114
+ $dropbox_destination = $path;
2115
+ $oldVersion = false;
2116
+ }
2117
2118
2119
2120
$temp_backup_file = $backup_file;
2121
if(!is_array($backup_file))
2126
foreach($backup_file as $key => $value)
2127
{
2128
try {
2129
+ if ($oldVersion) {
2130
+ $dropbox->fileopsDelete($dropbox_destination . '/' . $value);
2131
+ }else{
2132
+ $dropbox->delete($dropbox_destination . '/' . $value);
2133
+ }
2134
} catch (Exception $e) {
2135
$this->_log($e->getMessage());
2136
/*return array(
2824
$dropbox_file = $task_result['task_results'][$backup_data['historyID']]['dropbox'];
2825
$args = $thisRequestParams['account_info']['iwp_dropbox'];
2826
$args['backup_file'] = $dropbox_file;
2827
+ if(!empty($args['dropbox_access_token']) || (empty($args['dropbox_access_token']) && time() < 1498608000)){
2828
+ $this->remove_dropbox_backup($args);
2829
+ }
2830
}
2831
2832
if (isset($task_result['task_results'][$backup_data['historyID']]['gDrive'])) {
3291
}
3292
}
3293
3294
+ if( !function_exists('is_new_dropbox_compatible') ){
3295
+ function is_new_dropbox_compatible(){
3296
+ if(version_compare(phpversion() , '5.3.3', '>=')){
3297
+ return true;
3298
+ }
3299
+ return false;
3300
+ }
3301
+ }
3302
+
3303
+ if( !function_exists('upgradeOldDropBoxBackupList')){
3304
+ function upgradeOldDropBoxBackupList($dropBoxInfo){
3305
+ if (!isset($dropBoxInfo['dropbox_access_token']) && empty($dropBoxInfo['dropbox_access_token']) ) {
3306
+ return false;
3307
+ }
3308
+ global $wpdb;
3309
+ $table_name = $wpdb->base_prefix . "iwp_backup_status";
3310
+
3311
+ $rows = $wpdb->get_results("SELECT ID, taskName, taskResults, requestParams FROM ".$table_name." ORDER BY ID DESC", ARRAY_A);
3312
+ if (empty($rows)) {
3313
+ return false;
3314
+ }
3315
+ foreach ($rows as $ID => $taskArray) {
3316
+ $requestParams = unserialize($taskArray['requestParams']);
3317
+ $accountInfo = $requestParams['account_info'];
3318
+ if (isset($accountInfo['iwp_dropbox']) && isset($accountInfo['iwp_dropbox']['oauth_token']) && !empty($accountInfo['iwp_dropbox']['oauth_token'])) {
3319
+ $requestParams['account_info']['iwp_dropbox']['consumer_key'] = '';
3320
+ $requestParams['account_info']['iwp_dropbox']['consumer_secret'] = '';
3321
+ $requestParams['account_info']['iwp_dropbox']['oauth_token'] = '';
3322
+ $requestParams['account_info']['iwp_dropbox']['oauth_token_secret'] = '';
3323
+ $requestParams['account_info']['iwp_dropbox']['dropbox_app_key'] = $dropBoxInfo['dropbox_app_key'];
3324
+ $requestParams['account_info']['iwp_dropbox']['dropbox_app_secure_key'] = $dropBoxInfo['dropbox_app_secure_key'];
3325
+ $requestParams['account_info']['iwp_dropbox']['dropbox_access_token'] = $dropBoxInfo['dropbox_access_token'];
3326
+ $update = $wpdb->update($table_name,array( 'requestParams' => serialize($requestParams)),array( 'ID' => $taskArray['ID']),array('%s'),array('%d'));
3327
+ }
3328
+ }
3329
+ }
3330
+ }
3331
+
3332
?>
init.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: InfiniteWP - Client
4
Plugin URI: http://infinitewp.com/
5
Description: This is the client plugin of InfiniteWP that communicates with the InfiniteWP Admin panel.
6
Author: Revmakx
7
- Version: 1.6.4
8
Author URI: http://www.revmakx.com
9
*/
10
/************************************************************
@@ -28,7 +28,7 @@ if(basename($_SERVER['SCRIPT_FILENAME']) == "init.php"):
28
exit;
29
endif;
30
if(!defined('IWP_MMB_CLIENT_VERSION'))
31
- define('IWP_MMB_CLIENT_VERSION', '1.6.4');
32
33
34
4
Plugin URI: http://infinitewp.com/
5
Description: This is the client plugin of InfiniteWP that communicates with the InfiniteWP Admin panel.
6
Author: Revmakx
7
+ Version: 1.6.4.2
8
Author URI: http://www.revmakx.com
9
*/
10
/************************************************************
28
exit;
29
endif;
30
if(!defined('IWP_MMB_CLIENT_VERSION'))
31
+ define('IWP_MMB_CLIENT_VERSION', '1.6.4.2');
32
33
34
lib/Dropbox2/API.php ADDED
@@ -0,0 +1,804 @@
1
+ <?php
2
+
3
+ /**
4
+ * Dropbox API base class
5
+ * @author Ben Tadiar <ben@handcraftedbyben.co.uk>
6
+ * @link https://github.com/benthedesigner/dropbox
7
+ * @link https://www.dropbox.com/developers
8
+ * @link https://status.dropbox.com Dropbox status
9
+ * @package Dropbox
10
+ */
11
+
12
+ class IWP_Dropbox_API {
13
+ // API Endpoints
14
+ const API_URL = 'https://api.dropbox.com/1/';
15
+ const API_URL_V2 = 'https://api.dropboxapi.com/';
16
+ const CONTENT_URL = 'https://api-content.dropbox.com/1/';
17
+ const CONTENT_URL_V2 = 'https://content.dropboxapi.com/2/';
18
+
19
+ /**
20
+ * OAuth consumer object
21
+ * @var null|OAuth\Consumer
22
+ */
23
+ private $OAuth;
24
+
25
+ /**
26
+ * The root level for file paths
27
+ * Either `dropbox` or `sandbox` (preferred)
28
+ * @var null|string
29
+ */
30
+ private $root;
31
+
32
+ /**
33
+ * Chunk size used for chunked uploads
34
+ * @see \Dropbox_API::chunkedUpload()
35
+ */
36
+ private $chunkSize = 4194304;
37
+
38
+ private $responseFormat = 'php';
39
+
40
+ /**
41
+ * Object to track uploads
42
+ */
43
+ private $tracker;
44
+
45
+ private $base;
46
+
47
+ /**
48
+ * Set the OAuth consumer object
49
+ * See 'General Notes' at the link below for information on access type
50
+ * @link https://www.dropbox.com/developers/reference/api
51
+ * @param OAuth\Consumer\ConsumerAbstract $OAuth
52
+ * @param string $root Dropbox app access type
53
+ */
54
+ public function __construct($OAuth, $root = 'dropbox') {
55
+ $this->OAuth = $OAuth;
56
+ $this->setRoot($root);
57
+ }
58
+
59
+ /**
60
+ * Set the root level
61
+ * @param mixed $root
62
+ * @throws Exception
63
+ * @return void
64
+ */
65
+ public function setRoot($root) {
66
+ if ($root !== 'sandbox' && $root !== 'dropbox') {
67
+ throw new Exception("Expected a root of either 'dropbox' or 'sandbox', got '$root'");
68
+ } else {
69
+ $this->root = $root;
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Set the tracker
75
+ * @param Tracker $tracker
76
+ */
77
+ public function setTracker($tracker) {
78
+ $this->tracker = $tracker;
79
+ }
80
+
81
+ /**
82
+ * Retrieves information about the user's account
83
+ * @return object stdClass
84
+ */
85
+ public function accountInfo() {
86
+ //API V1
87
+ // return $this->fetch('POST', self::API_URL, 'account/info');
88
+
89
+ $call = '2/users/get_current_account';
90
+ $params = array('api_v2' => true);
91
+ $response = $this->fetch('POST', self::API_URL_V2, $call, $params);
92
+ return $response;
93
+ }
94
+
95
+ /**
96
+ * Retrieves information about the user's quota
97
+ * @return object stdClass
98
+ */
99
+ public function quotaInfo() {
100
+ $call = '2/users/get_space_usage';
101
+ $params = array('api_v2' => true);
102
+ $response = $this->fetch('POST', self::API_URL_V2, $call, $params);
103
+ return $response;
104
+ }
105
+
106
+ /**
107
+ * Uploads a physical file from disk
108
+ * Dropbox impose a 150MB limit to files uploaded via the API. If the file
109
+ * exceeds this limit or does not exist, an Exception will be thrown
110
+ * @param string $file Absolute path to the file to be uploaded
111
+ * @param string|bool $filename The destination filename of the uploaded file
112
+ * @param string $path Path to upload the file to, relative to root
113
+ * @param boolean $overwrite Should the file be overwritten? (Default: true)
114
+ * @return object stdClass
115
+ */
116
+ public function putFile($file, $path = '', $overwrite = true) {
117
+ if (!file_exists($file)) {
118
+ // Throw an Exception if the file does not exist
119
+ throw new Exception('Local file ' . $file . ' does not exist');
120
+ }
121
+ $filesize = iwp_mmb_get_file_size($file);
122
+ if ($filesize >= 157286400) {
123
+ $output = $this->chunked_upload_single_call_new($file, $path,$overwrite);
124
+ return $output;
125
+
126
+ }else{
127
+ $handle = @fopen($file, 'r');
128
+ //Set the file content to $this->InFile
129
+ $this->OAuth->setInFile(fread($handle, filesize($file)));
130
+ fclose($handle);
131
+
132
+ $filename = (is_string($filename)) ? $filename : basename($file);
133
+ $path = '/' . $this->encodePath($path .'/'. $filename);
134
+ $params = array(
135
+ 'path' => $path,
136
+ 'mute' => true,
137
+ 'mode' => 'overwrite',
138
+ 'api_v2' => true,
139
+ 'content_upload' => true
140
+ );
141
+ $response = $this->fetch('POST', self::CONTENT_URL_V2, 'files/upload', $params);
142
+ return $response;
143
+ }
144
+
145
+ }
146
+
147
+ public function chunked_upload_single_call_new($file, $path = '',$overwrite=true){
148
+ $file = str_replace("\\", "/",$file);
149
+ if (!is_readable($file) or !is_file($file))
150
+ throw new IWP_DropboxException("Error: File \"$file\" is not readable or doesn't exist.");
151
+ $file_handle=fopen($file,'r');
152
+ $uploadID=null;
153
+ $offset=0;
154
+ $ProgressFunction=null;
155
+ while ($data=fread($file_handle, (1024*1024*30))) { //1024*1024*30 = 30MB
156
+ $firstCommit = (0 == $offset);
157
+ iwp_mmb_auto_print('dropbox_chucked_upload');
158
+ $this->OAuth->setInFile($data);
159
+
160
+ if ($firstCommit) {
161
+ $params = array(
162
+ 'close' => false,
163
+ 'api_v2' => true,
164
+ 'content_upload' => true
165
+ );
166
+ $response = $this->fetch('POST', self::CONTENT_URL_V2, 'files/upload_session/start', $params);
167
+ $firstCommit = false;
168
+
169
+ } else {
170
+ $params = array(
171
+ 'cursor' => array(
172
+ 'session_id' => $uploadID,
173
+ // If you send it as a string, Dropbox will be unhappy
174
+ 'offset' => (int)$offset
175
+ ),
176
+ 'api_v2' => true,
177
+ 'content_upload' => true
178
+ );
179
+ $response = $this->append_upload($params, false);
180
+ }
181
+
182
+ // On subsequent chunks, use the upload ID returned by the previous request
183
+ if (isset($response['body']->session_id)) {
184
+ $uploadID = $response['body']->session_id;
185
+ }
186
+
187
+ /*
188
+ API v2 no longer returns the offset, we need to manually work this out. So check that there are no errors and update the offset as well as calling the callback method.
189
+ */
190
+ if (!isset($response['body']->error)) {
191
+ $offset = ftell($file_handle);
192
+ $output['response']= $response;
193
+ if($isCommit ==false){
194
+
195
+ $output['offset']= $offset;
196
+ $output['upload_id']= $uploadID;
197
+ }
198
+ $this->OAuth->setInFile(null);
199
+ }
200
+ fseek($file_handle, $offset);
201
+ }
202
+ fclose($file_handle);
203
+ $filename = (is_string($filename)) ? $filename : basename($file);
204
+ $params = array(
205
+ 'cursor' => array(
206
+ 'session_id' => $uploadID,
207
+ 'offset' => (int)$offset
208
+ ),
209
+ 'commit' => array(
210
+ 'path' => '/' . $this->encodePath($path .'/'. $filename),
211
+ 'mode' => 'overwrite'
212
+ ),
213
+ 'api_v2' => true,
214
+ 'content_upload' => true
215
+ );
216
+ $response = $this->append_upload($params, true);
217
+
218
+ return $response;
219
+ }
220
+
221
+ /**
222
+ * Not used
223
+ * Uploads file data from a stream
224
+ * Note: This function is experimental and requires further testing
225
+ * @todo Add filesize check
226
+ *@ param resource $stream A readable stream created using fopen()
227
+ * @param string $filename The destination filename, including path
228
+ * @param boolean $overwrite Should the file be overwritten? (Default: true)
229
+ * @return array
230
+ */
231
+ // public function putStream($stream, $filename, $overwrite = true) {
232
+ // $this->OAuth->setInFile($stream);
233
+ // $path = $this->encodePath($filename);
234
+ // $call = 'files_put/' . $this->root . '/' . $path;
235
+ // $params = array('overwrite' => (int) $overwrite);
236
+
237
+ // return $this->fetch('PUT', self::CONTENT_URL, $call, $params);
238
+ // }
239
+
240
+ /**
241
+ * Uploads large files to Dropbox in mulitple chunks
242
+ * @param string $file Absolute path to the file to be uploaded
243
+ * @param string|bool $filename The destination filename of the uploaded file
244
+ * @param string $path Path to upload the file to, relative to root
245
+ * @param boolean $overwrite Should the file be overwritten? (Default: true)
246
+ * @return stdClass
247
+ */
248
+ public function chunked_upload($file, $path = '', $overwrite = true, $uploadID = null, $offset = 0, $isCommit = false) {
249
+ $starting_backup_path_time = time();
250
+
251
+ $file = str_replace("\\", "/",$file);
252
+ if (!file_exists($file)) throw new Exception('Local file ' . $file . ' does not exist');
253
+
254
+ if (!($handle = @fopen($file, 'r'))) throw new Exception('Could not open ' . $file . ' for reading');
255
+
256
+ // Seek to the correct position on the file pointer
257
+ fseek($handle, $offset);
258
+ $to_exit = false;
259
+
260
+ //Set firstCommit to true so that the upload session start endpoint is called.
261
+ $firstCommit = (0 == $offset);
262
+
263
+ // Read from the file handle until EOF, uploading each chunk
264
+ if ($data = fread($handle, $this->chunkSize)) {
265
+
266
+ // Set the file, request parameters and send the request
267
+ $this->OAuth->setInFile($data);
268
+
269
+ if ($firstCommit) {
270
+ $params = array(
271
+ 'close' => false,
272
+ 'api_v2' => true,
273
+ 'content_upload' => true
274
+ );
275
+ $response = $this->fetch('POST', self::CONTENT_URL_V2, 'files/upload_session/start', $params);
276
+ $firstCommit = false;
277
+
278
+ } else {
279
+ $params = array(
280
+ 'cursor' => array(
281
+ 'session_id' => $uploadID,
282
+ // If you send it as a string, Dropbox will be unhappy
283
+ 'offset' => (int)$offset
284
+ ),
285
+ 'api_v2' => true,
286
+ 'content_upload' => true
287
+ );
288
+ $response = $this->append_upload($params, false);
289
+ }
290
+
291
+ // On subsequent chunks, use the upload ID returned by the previous request
292
+ if (isset($response['body']->session_id)) {
293
+ $uploadID = $response['body']->session_id;
294
+ }
295
+
296
+ /*
297
+ API v2 no longer returns the offset, we need to manually work this out. So check that there are no errors and update the offset as well as calling the callback method.
298
+ */
299
+ if (!isset($response['body']->error)) {
300
+ $offset = ftell($handle);
301
+ $output['response']= $response;
302
+ if($isCommit ==false){
303
+
304
+ $output['offset']= $offset;
305
+ $output['upload_id']= $uploadID;
306
+ }
307
+ $this->OAuth->setInFile(null);
308
+ }
309
+
310
+ }
311
+ // Complete the chunked upload
312
+ if ($isCommit) {
313
+ $filename = (is_string($filename)) ? $filename : basename($file);
314
+ $params = array(
315
+ 'cursor' => array(
316
+ 'session_id' => $uploadID,
317
+ 'offset' => (int)$offset
318
+ ),
319
+ 'commit' => array(
320
+ 'path' => '/' . $this->encodePath($path .'/'. $filename),
321
+ 'mode' => 'overwrite'
322
+ ),
323
+ 'api_v2' => true,
324
+ 'content_upload' => true
325
+ );
326
+ $response = $this->append_upload($params, true);
327
+ $offset = ftell($handle);
328
+ $output['response']= $response;
329
+ }
330
+
331
+ fclose($handle);
332
+ return $output;
333
+ }
334
+
335
+ private function append_upload($params, $last_call) {
336
+ try {
337
+ if ($last_call){
338
+ $response = $this->fetch('POST', self::CONTENT_URL_V2, 'files/upload_session/finish', $params);
339
+ } else {
340
+ $response = $this->fetch('POST', self::CONTENT_URL_V2, 'files/upload_session/append_v2', $params);
341
+ }
342
+ } catch (Exception $e) {
343
+ $responseCheck = json_decode($e->getMessage());
344
+ if (isset($responseCheck) && strpos($responseCheck[0] , 'incorrect_offset') !== false) {
345
+ $expected_offset = $responseCheck[1];
346
+ throw new Exception('Submitted input out of alignment: got ['.$params['cursor']['offset'].'] expected ['.$expected_offset.']');
347
+ //$params['cursor']['offset'] = $responseCheck[1];
348
+ //$response = $this->append_upload($params, $last_call);
349
+ } else {
350
+ throw $e;
351
+ }
352
+ }
353
+ return $response;
354
+ }
355
+
356
+ /**
357
+ * Downloads a file
358
+ * Returns the base filename, raw file data and mime type returned by Fileinfo
359
+ * @param string $file Path to file, relative to root, including path
360
+ * @param string $outFile Filename to write the downloaded file to
361
+ * @param string $revision The revision of the file to retrieve
362
+ * @return array
363
+ */
364
+ public function getFile($file, $outFile = false, $revision = null, $allow_resume = array()) {
365
+ $handle = null;
366
+ // $tempFolder = $this->getTempFolderFromOutFile(wp_normalize_path($outFile));
367
+ if ($outFile !== false) {
368
+ // Create a file handle if $outFile is specified
369
+ $this->prepareSetOutFile($outFile, 'w');
370
+ }
371
+
372
+ // $file = $this->encodePath($file);
373
+ $call = 'files/download';
374
+ $params = array('path' => '/'.$this->normalisePath($file), 'api_v2' => true, 'content_download' => true);
375
+ $response = $this->fetch('GET', self::CONTENT_URL_V2, $call, $params);
376
+ // Close the file handle if one was opened
377
+ if ($handle) fclose($handle);
378
+
379
+ return array(
380
+ 'name' => ($outFile) ? $outFile : basename($file),
381
+ 'mime' => $this->getMimeType(($outFile) ? $outFile : $response['body'], $outFile),
382
+ 'meta' => json_decode($response['headers']['dropbox-api-result']),
383
+ 'data' => $response['body'],
384
+ );
385
+ }
386
+
387
+ public function prepareSetOutFile($outFile, $mode) {
388
+ // $tempFolderFile = $this->getTempFolderFromOutFile(wp_normalize_path($outFile));
389
+ $tempFolderFile = wp_normalize_path($outFile);
390
+
391
+ //setting chmod from filesystem
392
+
393
+ if (!$handle = @fopen($tempFolderFile, $mode)) {
394
+ throw new Exception("Unable to open file handle for $tempFolderFile");
395
+ } else {
396
+ $this->OAuth->setOutFile($handle);
397
+ return $handle;
398
+ }
399
+ }
400
+
401
+ public function getTempFolderFromOutFile($outFile, $mode = '') {
402
+ //this function creates the file and its respective folders ; this function also create the exact file path from the DB values
403
+ $config = WPTC_Factory::get('config');
404
+ $is_staging_running = $config->get_option('is_staging_running');
405
+ if($is_staging_running){
406
+ $site_abspath = $config->get_option('site_abspath');
407
+ $this_absbath_length = (strlen($site_abspath) - 1);
408
+ } else{
409
+ $this_absbath_length = (strlen(ABSPATH) - 1);
410
+ }
411
+
412
+ $this_temp_file = $config->get_option('backup_db_path');
413
+ $this_temp_file = $config->wp_filesystem_safe_abspath_replace($this_temp_file);
414
+ $this_temp_file = $this_temp_file. '/tCapsule' . substr($outFile, $this_absbath_length);
415
+
416
+ //get the folder name from the full file path
417
+ $base_file_name = basename($this_temp_file);
418
+ $base_file_name_pos = strrpos($this_temp_file, $base_file_name);
419
+ $base_file_name_pos = $base_file_name_pos - 1;
420
+ $this_temp_folder = substr($this_temp_file, 0, $base_file_name_pos);
421
+
422
+ $this_temp_folder = $config->wp_filesystem_safe_abspath_replace($this_temp_folder);
423
+
424
+ $this->base->createRecursiveFileSystemFolder($this_temp_folder);
425
+ return $this_temp_file;
426
+ }
427
+
428
+ /**
429
+ * Downloads a file
430
+ * Returns the base filename, raw file data and mime type returned by Fileinfo
431
+ * @param string $file Path to file, relative to root, including path
432
+ * @param string $outFile Filename to write the downloaded file to
433
+ * @param string $revision The revision of the file to retrieve
434
+ * @return array
435
+ */
436
+ public function chunkedDownload($file, $outFile = false, $revision = null, $isChunkDownload = array(), $meta_file_download = null) {
437
+ global $start_time_tc;
438
+ $start_time_tc = time();
439
+ $handle = null;
440
+ if ($outFile !== false) {
441
+ // Create a file handle if $outFile is specified
442
+ if ($isChunkDownload['c_offset'] == 0) {
443
+ //while restoring ... first
444
+ $handle = $this->prepareSetOutFile($outFile, 'w');
445
+ } else {
446
+ $handle = $this->prepareSetOutFile($outFile, 'a');
447
+ }
448
+ }
449
+
450
+ $outFilePath = wp_normalize_path($outFile);
451
+ $call = 'files/download';
452
+ $params = array('path' =>'/'.$file, 'api_v2' => true, 'content_download' => true);
453
+ $response = $this->fetch('GET', self::CONTENT_URL_V2, $call, $params, $isChunkDownload);
454
+
455
+ // Set the data offset
456
+ if ($response) {
457
+ $offset = filesize($outFilePath);
458
+ }
459
+
460
+ if (empty($meta_file_download)) {
461
+ if ($this->tracker) {
462
+ $this->tracker->track_download($outFile, false, $offset, $isChunkDownload);
463
+ }
464
+ } else {
465
+ $this->tracker->track_meta_download($offset, $isChunkDownload);
466
+ }
467
+
468
+ // Close the file handle if one was opened
469
+ if ($handle) {
470
+ fclose($handle);
471
+ }
472
+
473
+ $data = array(
474
+ 'name' => ($outFile) ? $outFile : basename($file),
475
+ 'mime' => $this->getMimeType(($outFile) ? $outFile : $response['body'], $outFile),
476
+ 'meta' => json_decode($response['headers']['dropbox-api-result']),
477
+ 'data' => $response['body'],
478
+ 'chunked' => true,
479
+ );
480
+ return $data;
481
+ }
482
+
483
+ public function delete($path) {
484
+ $call = '2/files/delete';
485
+ $params = array('path' => '/' . $this->normalisePath($path), 'api_v2' => true);
486
+ $response = $this->fetch('POST', self::API_URL_V2, $call, $params);
487
+ return $response;
488
+ }
489
+ /**
490
+ * Not used
491
+ * Retrieves file and folder metadata
492
+ * @param string $path The path to the file/folder, relative to root
493
+ * @param string $rev Return metadata for a specific revision (Default: latest rev)
494
+ * @param int $limit Maximum number of listings to return
495
+ * @param string $hash Metadata hash to compare against
496
+ * @param bool $list Return contents field with response
497
+ * @param bool $deleted Include files/folders that have been deleted
498
+ * @return object stdClass
499
+ */
500
+ public function metaData($path = null, $rev = null, $limit = 10000, $hash = false, $list = true, $deleted = false) {
501
+ $call = 'metadata/' . $this->root . '/' . $this->encodePath($path);
502
+ $params = array(
503
+ 'file_limit' => ($limit < 1) ? 1 : (($limit > 10000) ? 10000 : (int) $limit),
504
+ 'hash' => (is_string($hash)) ? $hash : 0,
505
+ 'list' => (int) $list,
506
+ 'include_deleted' => (int) $deleted,
507
+ 'rev' => (is_string($rev)) ? $rev : null,
508
+ );
509
+
510
+ return $this->fetch('POST', self::API_URL, $call, $params);
511
+ }
512
+
513
+ /**
514
+ * Not used
515
+ * Return "delta entries", intructing you how to update
516
+ * your application state to match the server's state
517
+ * Important: This method does not make changes to the application state
518
+ * @param null|string $cursor Used to keep track of your current state
519
+ * @return array Array of delta entries
520
+ */
521
+ // public function delta($cursor = null) {
522
+ // $call = 'delta';
523
+ // $params = array('cursor' => $cursor);
524
+
525
+ // return $this->fetch('POST', self::API_URL, $call, $params);
526
+ // }
527
+
528
+ /**
529
+ * Not used
530
+ * Obtains metadata for the previous revisions of a file
531
+ * @param string Path to the file, relative to root
532
+ * @param integer Number of revisions to return (1-1000)
533
+ * @return array
534
+ */
535
+ // public function revisions($file, $limit = 10) {
536
+ // $call = 'revisions/' . $this->root . '/' . $this->encodePath($file);
537
+ // $params = array(
538
+ // 'rev_limit' => ($limit < 1) ? 1 : (($limit > 1000) ? 1000 : (int) $limit),
539
+ // );
540
+
541
+ // return $this->fetch('GET', self::API_URL, $call, $params);
542
+ // }
543
+
544
+ /**
545
+ * Not used
546
+ * Restores a file path to a previous revision
547
+ * @param string $file Path to the file, relative to root
548
+ * @param string $revision The revision of the file to restore
549
+ * @return object stdClass
550
+ */
551
+ // public function restore($file, $revision) {
552
+ // $call = 'restore/' . $this->root . '/' . $this->encodePath($file);
553
+ // $params = array('rev' => $revision);
554
+
555
+ // return $this->fetch('POST', self::API_URL, $call, $params);
556
+ // }
557
+
558
+ /**
559
+ * Returns metadata for all files and folders that match the search query
560
+ * @param mixed $query The search string. Must be at least 3 characters long
561
+ * @param string $path The path to the folder you want to search in
562
+ * @param integer $limit Maximum number of results to return (1-1000)
563
+ * @param boolean $deleted Include deleted files/folders in the search
564
+ * @return array
565
+ */
566
+ //Not used
567
+ // public function search($query, $path = '', $limit = 1000, $deleted = false) {
568
+ // $call = 'search/' . $this->root . '/' . $this->encodePath($path);
569
+ // $params = array(
570
+ // 'query' => $query,
571
+ // 'file_limit' => ($limit < 1) ? 1 : (($limit > 1000) ? 1000 : (int) $limit),
572
+ // 'include_deleted' => (int) $deleted,
573
+ // );
574
+
575
+ // return $this->fetch('GET', self::API_URL, $call, $params);
576
+ // }
577
+
578
+ /**
579
+ * Not used
580
+ * Creates and returns a shareable link to files or folders
581
+ * The link returned is for a preview page from which the user an choose to
582
+ * download the file if they wish. For direct download links, see media().
583
+ * @param string $path The path to the file/folder you want a sharable link to
584
+ * @return object stdClass
585
+ */
586
+ // public function shares($path, $shortUrl = true) {
587
+ // $call = 'shares/' . $this->root . '/' . $this->encodePath($path);
588
+ // $params = array('short_url' => ($shortUrl) ? 1 : 0);
589
+
590
+ // return $this->fetch('POST', self::API_URL, $call, $params);
591
+ // }
592
+
593
+ /**
594
+ * Not used
595
+ * Returns a link directly to a file
596
+ * @param string $path The path to the media file you want a direct link to
597
+ * @return object stdClass
598
+ */
599
+ // public function media($path) {
600
+ // $call = 'media/' . $this->root . '/' . $this->encodePath($path);
601
+
602
+ // return $this->fetch('POST', self::API_URL, $call);
603
+ // }
604
+
605
+ /**
606
+ * Not used
607
+ * Gets a thumbnail for an image
608
+ * @param string $file The path to the image you wish to thumbnail
609
+ * @param string $format The thumbnail format, either JPEG or PNG
610
+ * @param string $size The size of the thumbnail
611
+ * @return array
612
+ */
613
+ // public function thumbnails($file, $format = 'JPEG', $size = 'small') {
614
+ // $format = strtoupper($format);
615
+ // // If $format is not 'PNG', default to 'JPEG'
616
+ // if ($format != 'PNG') {
617
+ // $format = 'JPEG';
618
+ // }
619
+
620
+ // $size = strtolower($size);
621
+ // $sizes = array('s', 'm', 'l', 'xl', 'small', 'medium', 'large');
622
+ // // If $size is not valid, default to 'small'
623
+ // if (!in_array($size, $sizes)) {
624
+ // $size = 'small';
625
+ // }
626
+
627
+ // $call = 'thumbnails/' . $this->root . '/' . $this->encodePath($file);
628
+ // $params = array('format' => $format, 'size' => $size);
629
+ // $response = $this->fetch('GET', self::CONTENT_URL, $call, $params);
630
+
631
+ // return array(
632
+ // 'name' => basename($file),
633
+ // 'mime' => $this->getMimeType($response['body']),
634
+ // 'meta' => json_decode($response['headers']['x-dropbox-metadata']),
635
+ // 'data' => $response['body'],
636
+ // );
637
+ // }
638
+
639
+ /**
640
+ * Not used
641
+ * Creates and returns a copy_ref to a file
642
+ * This reference string can be used to copy that file to another user's
643
+ * Dropbox by passing it in as the from_copy_ref parameter on /fileops/copy
644
+ * @param $path File for which ref should be created, relative to root
645
+ * @return array
646
+ */
647
+ // public function copyRef($path) {
648
+ // $call = 'copy_ref/' . $this->root . '/' . $this->encodePath($path);
649
+
650
+ // return $this->fetch('GET', self::API_URL, $call);
651
+ // }
652
+
653
+ /**
654
+ * Not used
655
+ * Copies a file or folder to a new location
656
+ * @param string $from File or folder to be copied, relative to root
657
+ * @param string $to Destination path, relative to root
658
+ * @param null|string $fromCopyRef Must be used instead of the from_path
659
+ * @return object stdClass
660
+ */
661
+ // public function copy($from, $to, $fromCopyRef = null) {
662
+ // $call = 'fileops/copy';
663
+ // $params = array(
664
+ // 'root' => $this->root,
665
+ // 'from_path' => $this->normalisePath($from),
666
+ // 'to_path' => $this->normalisePath($to),
667
+ // );
668
+
669
+ // if ($fromCopyRef) {
670
+ // $params['from_path'] = null;
671
+ // $params['from_copy_ref'] = $fromCopyRef;
672
+ // }
673
+
674
+ // return $this->fetch('POST', self::API_URL, $call, $params);
675
+ // }
676
+
677
+ /**
678
+ * Not used
679
+ * Creates a folder
680
+ * @param string New folder to create relative to root
681
+ * @return object stdClass
682
+ */
683
+ // public function create($path) {
684
+ // $call = 'fileops/create_folder';
685
+ // $params = array('root' => $this->root, 'path' => $this->normalisePath($path));
686
+
687
+ // return $this->fetch('POST', self::API_URL, $call, $params);
688
+ // }
689
+
690
+ /**
691
+ * Not used
692
+ * Deletes a file or folder
693
+ * @param string $path The path to the file or folder to be deleted
694
+ * @return object stdClass
695
+ */
696
+ // public function delete($path) {
697
+ // $call = '2/files/delete';
698
+ // $params = array('path' => '/' . $this->normalisePath($path), 'api_v2' => true);
699
+ // $response = $this->fetch('POST', self::API_URL_V2, $call, $params);
700
+ // return $response;
701
+ // }
702
+
703
+ /**
704
+ * Not used
705
+ * Moves a file or folder to a new location
706
+ * @param string $from File or folder to be moved, relative to root
707
+ * @param string $to Destination path, relative to root
708
+ * @return object stdClass
709
+ */
710
+ // public function move($from, $to) {
711
+ // $call = 'fileops/move';
712
+ // $params = array(
713
+ // 'root' => $this->root,
714
+ // 'from_path' => $this->normalisePath($from),
715
+ // 'to_path' => $this->normalisePath($to),
716
+ // );
717
+
718
+ // return $this->fetch('POST', self::API_URL, $call, $params);
719
+ // }
720
+
721
+ /**
722
+ * Intermediate fetch function
723
+ * @param string $method The HTTP method
724
+ * @param string $url The API endpoint
725
+ * @param string $call The API method to call
726
+ * @param array $params Additional parameters
727
+ * @return mixed
728
+ */
729
+ private function fetch($method, $url, $call, array $params = array(), $isChunkDownload = array())
730
+ {
731
+ // Make the API call via the consumer
732
+ $response = $this->OAuth->fetch($method, $url, $call, $params, $isChunkDownload);
733
+
734
+ // Format the response and return
735
+ switch ($this->responseFormat) {
736
+ case 'json':
737
+ return json_encode($response);
738
+ case 'jsonp':
739
+ $response = json_encode($response);
740
+ return $this->callback . '(' . $response . ')';
741
+ default:
742
+ return $response;
743
+ }
744
+ }
745
+
746
+
747
+ /**
748
+ * Set the chunk size for chunked uploads
749
+ * If $chunkSize is empty, set to 4194304 bytes (4 MB)
750
+ * @see \Dropbox\API\chunkedUpload()
751
+ */
752
+ public function setChunkSize($chunkSize = 4194304) {
753
+ if (!is_int($chunkSize)) {
754
+ throw new Exception('Expecting chunk size to be an integer, got ' . gettype($chunkSize));
755
+ } elseif ($chunkSize > 157286400) {
756
+ throw new Exception('Chunk size must not exceed 157286400 bytes, got ' . $chunkSize);
757
+ } else {
758
+ $this->chunkSize = $chunkSize;
759
+ }
760
+ }
761
+
762
+ /**
763
+ * Get the mime type of downloaded file
764
+ * If the Fileinfo extension is not loaded, return false
765
+ * @param string $data File contents as a string or filename
766
+ * @param string $isFilename Is $data a filename?
767
+ * @return boolean|string Mime type and encoding of the file
768
+ */
769
+ private function getMimeType($data, $isFilename = false) {
770
+ if (extension_loaded('fileinfo')) {
771
+ $finfo = new finfo(FILEINFO_MIME);
772
+ if ($isFilename !== false) {
773
+ return @$finfo->file($data);
774
+ }
775
+
776
+ return $finfo->buffer($data);
777
+ }
778
+
779
+ return false;
780
+ }
781
+
782
+ /**
783
+ * Trim the path of forward slashes and replace
784
+ * consecutive forward slashes with a single slash
785
+ * then replace backslashes with forward slashes
786
+ * @param string $path The path to normalise
787
+ * @return string
788
+ */
789
+ private function normalisePath($path) {
790
+ $path = preg_replace('#/+#', '/', trim($path, '/'));
791
+ return $path;
792
+ }
793
+
794
+ /**
795
+ * Encode the path, then replace encoded slashes
796
+ * with literal forward slash characters
797
+ * @param string $path The path to encode
798
+ * @return string
799
+ */
800
+ private function encodePath($path) {
801
+ // in APIv1, encoding was needed because parameters were passed as part of the URL; this is no longer done in our APIv2 SDK; hence, all that we now do here is normalise.
802
+ return $this->normalisePath($path);
803
+ }
804
+ }
lib/Dropbox2/Exception.php ADDED
@@ -0,0 +1,31 @@
1
+ <?php
2
+
3
+ /**
4
+ * Dropbox Exception class
5
+ * @author Ben Tadiar <ben@handcraftedbyben.co.uk>
6
+ * @link https://github.com/benthedesigner/dropbox
7
+ * @package Dropbox
8
+ */
9
+ class IWP_Dropbox_Exception extends Exception {
10
+ }
11
+
12
+ class IWP_Dropbox_BadRequestException extends Exception {
13
+ }
14
+
15
+ class IWP_Dropbox_CurlException extends Exception {
16
+ }
17
+
18
+ class IWP_Dropbox_NotAcceptableException extends Exception {
19
+ }
20
+
21
+ class IWP_Dropbox_NotFoundException extends Exception {
22
+ }
23
+
24
+ class IWP_Dropbox_NotModifiedException extends Exception {
25
+ }
26
+
27
+ class IWP_Dropbox_UnsupportedMediaTypeException extends Exception {
28
+ }
29
+
30
+ class IWP_Dropbox_TokenExpired extends Exception {
31
+ }
lib/Dropbox2/OAuth/Consumer/ConsumerAbstract.php ADDED
@@ -0,0 +1,340 @@
1
+ <?php
2
+
3
+ /**
4
+ * Abstract OAuth consumer
5
+ * @author Ben Tadiar <ben@handcraftedbyben.co.uk>
6
+ * @link https://github.com/benthedesigner/dropbox
7
+ * @package Dropbox\OAuth
8
+ * @subpackage Consumer
9
+ */
10
+
11
+ abstract class IWP_Dropbox_OAuth_Consumer_ConsumerAbstract
12
+ {
13
+ // Dropbox web endpoint
14
+ const WEB_URL = 'https://www.dropbox.com/';
15
+
16
+ // OAuth flow methods
17
+ const REQUEST_TOKEN_METHOD = 'oauth2/REQUEST_TOKEN_METHOD';
18
+ const AUTHORISE_METHOD = 'oauth2/authorize';
19
+ const ACCESS_TOKEN_METHOD = 'oauth2/token';
20
+ const API_URL = 'https://api.dropbox.com/1/';
21
+ const OAUTH_UPGRADE = 'oauth2/token_from_oauth1';
22
+
23
+ /**
24
+ * Signature method, either PLAINTEXT or HMAC-SHA1
25
+ * @var string
26
+ */
27
+ private $sigMethod = 'PLAINTEXT';
28
+
29
+ /**
30
+ * Output file handle
31
+ * @var null|resource
32
+ */
33
+ protected $outFile = null;
34
+
35
+ /**
36
+ * Input file handle
37
+ * @var null|resource
38
+ */
39
+ protected $inFile = null;
40
+
41
+ /**
42
+ * OAuth token
43
+ * @var stdclass
44
+ */
45
+ private $token = null;
46
+
47
+ /**
48
+ * Acquire an unauthorised request token
49
+ * @link http://tools.ietf.org/html/rfc5849#section-2.1
50
+ * @return void
51
+ */
52
+ public function getRequestToken()
53
+ {
54
+ $url = WPTC_Dropbox_API::API_URL_V2 . self::REQUEST_TOKEN_METHOD;
55
+ $response = $this->fetch('POST', $url, '');
56
+
57
+ return $this->parseTokenString($response['body']);
58
+ }
59
+
60
+ /**
61
+ * Build the user authorisation URL
62
+ * @return string
63
+ */
64
+ public function getAuthoriseUrl()
65
+ {
66
+ $params = array(
67
+ 'client_id' => WPTC_DROPBOX_CLIENT_ID,
68
+ 'response_type' => 'code',
69
+ 'redirect_uri' => WPTC_DROPBOX_REDIRECT_URL,
70
+ 'state' => WPTC_DROPBOX_WP_REDIRECT_URL,
71
+ );
72
+
73
+
74
+ // Build the URL and redirect the user
75
+ $query = '?' . http_build_query($params, '', '&');
76
+ $url = self::WEB_URL . self::AUTHORISE_METHOD . $query;
77
+
78
+ return $url;
79
+ }
80
+
81
+ public function upgradeOAuth()
82
+ {
83
+ // N.B. This call only exists under API v1 - i.e. there is no APIv2 equivalent. Hence the APIv1 endpoint (API_URL) is used, and not the v2 (API_URL_V2)
84
+
85
+ $url = self::API_URL . self::OAUTH_UPGRADE;
86
+ $config = WPTC_Factory::get('config');
87
+ $this->token = new stdClass();
88
+ $this->token->oauth_token = $config->get_option('access_token');
89
+ $this->token->oauth_token_secret = $config->get_option('access_token_secret');
90
+ $response = $this->fetch('POST', $url, '');
91
+ return $response['body'];
92
+ }
93
+
94
+ /**
95
+ * Acquire an access token
96
+ * Tokens acquired at this point should be stored to
97
+ * prevent having to request new tokens for each API call
98
+ * @link http://tools.ietf.org/html/rfc5849#section-2.3
99
+ */
100
+ public function getAccessToken()
101
+ {
102
+ // Get the signed request URL
103
+ $response = $this->fetch('POST', WPTC_Dropbox_API::API_URL_V2, self::ACCESS_TOKEN_METHOD);
104
+ return $this->parseTokenString($response['body']);
105
+ }
106
+
107
+ /**
108
+ * Generate signed request URL
109
+ * See inline comments for description
110
+ * @link http://tools.ietf.org/html/rfc5849#section-3.4
111
+ * @param string $method HTTP request method
112
+ * @param string $url API endpoint to send the request to
113
+ * @param string $call API call to send
114
+ * @param array $additional Additional parameters as an associative array
115
+ * @return array
116
+ */
117
+ protected function getSignedRequest($method, $url, $call, array $additional = array())
118
+ {
119
+ // Get the request/access token
120
+ $token = $this->getToken();
121
+ // Prepare the standard request parameters differently for OAuth1 and OAuth2; we still need OAuth1 to make the request to the upgrade token endpoint
122
+ if (!empty($token)) {
123
+ $params = array(
124
+ 'access_token' => $token,
125
+ );
126
+
127
+ /*
128
+ To keep this API backwards compatible with the API v1 endpoints all v2 endpoints will also send to this method a api_v2 parameter this will then return just the access token as the signed request is not needed for any calls.
129
+ */
130
+
131
+ if (isset($additional['api_v2']) && $additional['api_v2'] == true) {
132
+ unset($additional['api_v2']);
133
+ if (isset($additional['content_download']) && $additional['content_download'] == true) {
134
+ unset($additional['content_download']);
135
+ $headers = array(
136
+ 'Authorization: Bearer '.$params['access_token'],
137
+ 'Content-Type:',
138
+ 'Dropbox-API-Arg: '.json_encode($additional),
139
+ );
140
+ $additional = '';
141
+ } else if (isset($additional['content_upload']) && $additional['content_upload'] == true) {
142
+ unset($additional['content_upload']);
143
+ $headers = array(
144
+ 'Authorization: Bearer '.$params['access_token'],
145
+ 'Content-Type: application/octet-stream',
146
+ 'Dropbox-API-Arg: '.json_encode($additional),
147
+ );
148
+ $additional = '';
149
+ } else {
150
+ $headers = array(
151
+ 'Authorization: Bearer '.$params['access_token'],
152
+ 'Content-Type: application/json',
153
+ );
154
+ }
155
+ return array(
156
+ 'url' => $url . $call,
157
+ 'postfields' => $additional,
158
+ 'headers' => $headers,
159
+ );
160
+ }
161
+ } else {
162
+
163
+ // Generate a random string for the request
164
+ $nonce = md5(microtime(true) . uniqid('', true));
165
+ $params = array(
166
+ 'oauth_consumer_key' => WPTC_DROPBOX_CLIENT_ID,
167
+ 'oauth_token' => $this->token->oauth_token,
168
+ 'oauth_signature_method' => $this->sigMethod,
169
+ 'oauth_version' => '1.0',
170
+ // Generate nonce and timestamp if signature method is HMAC-SHA1
171
+ 'oauth_timestamp' => ($this->sigMethod == 'HMAC-SHA1') ? time() : null,
172
+ 'oauth_nonce' => ($this->sigMethod == 'HMAC-SHA1') ? $nonce : null,
173
+ );
174
+ }
175
+
176
+ // Merge with the additional request parameters
177
+ $params = array_merge($params, $additional);
178
+ ksort($params);
179
+
180
+ // URL encode each parameter to RFC3986 for use in the base string
181
+ $encoded = array();
182
+ foreach($params as $param => $value) {
183
+ if ($value !== null) {
184
+ // If the value is a file upload (prefixed with @), replace it with
185
+ // the destination filename, the file path will be sent in POSTFIELDS
186
+ if (isset($value[0]) && $value[0] === '@') $value = $params['filename'];
187
+ # Prevent spurious PHP warning by only doing non-arrays
188
+ if (!is_array($value)) $encoded[] = $this->encode($param) . '=' . $this->encode($value);
189
+ } else {
190
+ unset($params[$param]);
191
+ }
192
+ }
193
+
194
+ // Build the first part of the string
195
+ $base = $method . '&' . $this->encode($url . $call) . '&';
196
+
197
+ // Re-encode the encoded parameter string and append to $base
198
+ $base .= $this->encode(implode('&', $encoded));
199
+
200
+ // Concatenate the secrets with an ampersand
201
+ $key = WPTC_DROPBOX_CLIENT_SECRET . '&' . $this->token->oauth_token_secret;
202
+
203
+ // Get the signature string based on signature method
204
+ $signature = $this->getSignature($base, $key);
205
+ $params['oauth_signature'] = $signature;
206
+
207
+ // Build the signed request URL
208
+ $query = '?' . http_build_query($params, '', '&');
209
+ return array(
210
+ 'url' => $url . $call . $query,
211
+ 'postfields' => $params,
212
+ );
213
+ }
214
+
215
+ /**
216
+ * Generate the oauth_signature for a request
217
+ * @param string $base Signature base string, used by HMAC-SHA1
218
+ * @param string $key Concatenated consumer and token secrets
219
+ */
220
+ private function getSignature($base, $key)
221
+ {
222
+ switch ($this->sigMethod) {
223
+ case 'PLAINTEXT':
224
+ $signature = $key;
225
+ break;
226
+ case 'HMAC-SHA1':
227
+ $signature = base64_encode(hash_hmac('sha1', $base, $key, true));
228
+ break;
229
+ }
230
+
231
+ return $signature;
232
+ }
233
+
234
+ /**
235
+ * Set the token to use for OAuth requests
236
+ * @param stdtclass $token A key secret pair
237
+ */
238
+ public function setToken($token)
239
+ {
240
+
241
+ $this->token = $token;
242
+
243
+ return $this;
244
+ }
245
+
246
+ public function getToken()
247
+ {
248
+ return $this->token;
249
+ }
250
+
251
+ public function resetToken()
252
+ {
253
+ $token = new stdClass;
254
+ $token->oauth_token = false;
255
+ $token->oauth_token_secret = false;
256
+
257
+ $this->setToken($token);
258
+
259
+ return $this;
260
+ }
261
+
262
+ /**
263
+ * Set the OAuth signature method
264
+ * @param string $method Either PLAINTEXT or HMAC-SHA1
265
+ * @return void
266
+ */
267
+ public function setSignatureMethod($method)
268
+ {
269
+ $method = strtoupper($method);
270
+
271
+ switch ($method) {
272
+ case 'PLAINTEXT':
273
+ case 'HMAC-SHA1':
274
+ $this->sigMethod = $method;
275
+ break;
276
+ default:
277
+ throw new Exception('Unsupported signature method ' . $method);
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Set the output file
283
+ * @param resource Resource to stream response data to
284
+ * @return void
285
+ */
286
+ public function setOutFile($handle)
287
+ {
288
+ if (!is_resource($handle) || get_resource_type($handle) != 'stream') {
289
+ throw new Exception('Outfile must be a stream resource');
290
+ }
291
+ $this->outFile = $handle;
292
+ }
293
+
294
+ /**
295
+ * Set the input file
296
+ * @param resource Resource to read data from
297
+ * @return void
298
+ */
299
+ public function setInFile($handle)
300
+ {
301
+ $this->inFile = $handle;
302
+ }
303
+
304
+ /**
305
+ * Parse response parameters for a token into an object
306
+ * Dropbox returns tokens in the response parameters, and
307
+ * not a JSON encoded object as per other API requests
308
+ * @link http://oauth.net/core/1.0/#response_parameters
309
+ * @param string $response
310
+ * @return object stdClass
311
+ */
312
+ private function parseTokenString($response)
313
+ {
314
+ if (!$response)
315
+ throw new Exception('Response cannot be null');
316
+
317
+ $parts = explode('&', $response);
318
+ $token = new stdClass();
319
+ foreach ($parts as $part) {
320
+ list($k, $v) = explode('=', $part, 2);
321
+ $k = strtolower($k);
322
+ $token->$k = $v;
323
+ }
324
+
325
+ return $token;
326
+ }
327
+
328
+ /**
329
+ * Encode a value to RFC3986
330
+ * This is a convenience method to decode ~ symbols encoded
331
+ * by rawurldecode. This will encode all characters except
332
+ * the unreserved set, ALPHA, DIGIT, '-', '.', '_', '~'
333
+ * @link http://tools.ietf.org/html/rfc5849#section-3.6
334
+ * @param mixed $value
335
+ */
336
+ private function encode($value)
337
+ {
338
+ return str_replace('%7E', '~', rawurlencode($value));
339
+ }
340
+ }
lib/Dropbox2/OAuth/Consumer/Curl.php ADDED
@@ -0,0 +1,295 @@
1
+ <?php
2
+
3
+ /**
4
+ * OAuth consumer using PHP cURL
5
+ * @author Ben Tadiar <ben@handcraftedbyben.co.uk>
6
+ * @link https://github.com/benthedesigner/dropbox
7
+ * @package Dropbox\OAuth
8
+ * @subpackage Consumer
9
+ */
10
+ error_reporting(0);
11
+ class IWP_Dropbox_OAuth_Consumer_Curl extends IWP_Dropbox_OAuth_Consumer_ConsumerAbstract {
12
+
13
+ /**
14
+ * Default cURL options
15
+ * @var array
16
+ */
17
+
18
+ protected $defaultOptions = array(
19
+ CURLOPT_SSL_VERIFYPEER => true,
20
+ CURLOPT_VERBOSE => true,
21
+ CURLOPT_HEADER => true,
22
+ CURLINFO_HEADER_OUT => false,
23
+ CURLOPT_RETURNTRANSFER => true,
24
+ CURLOPT_FOLLOWLOCATION => false,
25
+ );
26
+
27
+ /**
28
+ * Store the last response form the API
29
+ * @var mixed
30
+ */
31
+ protected $lastResponse = null;
32
+
33
+ /**
34
+ * Set properties and begin authentication
35
+ * @param string $key
36
+ * @param string $secret
37
+ */
38
+ public function __construct($key, $secret) {
39
+ // Check the cURL extension is loaded
40
+ if (!extension_loaded('curl')) {
41
+ throw new Exception('The cURL OAuth consumer requires the cURL extension');
42
+ }
43
+
44
+ $this->consumerKey = $key;
45
+ $this->consumerSecret = $secret;
46
+ }
47
+
48
+ /**
49
+ * Execute an API call
50
+ * @todo Improve error handling
51
+ * @param string $method The HTTP method
52
+ * @param string $url The API endpoint
53
+ * @param string $call The API method to call
54
+ * @param array $additional Additional parameters
55
+ * @return string|object stdClass
56
+ */
57
+
58
+
59
+ public function fetch($method, $url, $call, array $additional = array(), $isChunkDownload = array())
60
+ {
61
+ // Get the signed request URL
62
+ $request = $this->getSignedRequest($method, $url, $call, $additional);
63
+ if ($request === false) {
64
+ throw new Exception("Upgrade failed", 401);
65
+ }
66
+ // Initialise and execute a cURL request
67
+ $handle = curl_init($request['url']);
68
+
69
+ // Get the default options array
70
+ $options = $this->defaultOptions;
71
+ $options[CURLOPT_CAINFO] = dirname(__FILE__) . '/ca-bundle.pem';
72
+
73
+ //Disabling this as of now
74
+ // if (get_option('updraft_ssl_disableverify')) {
75
+ // $options[CURLOPT_SSL_VERIFYPEER] = false;
76
+ // } else {
77
+ // $options[CURLOPT_SSL_VERIFYPEER] = true;
78
+ // }
79
+ // if (!defined('WPTC_BRIDGE')) {
80
+ if (!defined('WPTC_BRIDGE')) {
81
+ if (!class_exists('WP_HTTP_Proxy')){
82
+ if (!defined('WPTC_BRIDGE')) {
83
+ require_once(ABSPATH.WPINC.'/class-http.php');
84
+ } else {
85
+ throw new Exception("WP_HTTP_Proxy Class not foound", 500);
86
+ }
87
+ }
88
+ $proxy = new WP_HTTP_Proxy();
89
+
90
+ if ($proxy->is_enabled()) {
91
+ # WP_HTTP_Proxy returns empty strings if nothing is set
92
+ $user = $proxy->username();
93
+ $pass = $proxy->password();
94
+ $host = $proxy->host();
95
+ $port = (int)$proxy->port();
96
+ if (empty($port)) $port = 8080;
97
+ if (!empty($host) && $proxy->send_through_proxy($request['url'])) {
98
+ $options[CURLOPT_PROXY] = $host;
99
+ $options[CURLOPT_PROXYTYPE] = CURLPROXY_HTTP;
100
+ $options[CURLOPT_PROXYPORT] = $port;
101
+ if (!empty($user) && !empty($pass)) {
102
+ $options[CURLOPT_PROXYAUTH] = CURLAUTH_ANY;
103
+ $options[CURLOPT_PROXYUSERPWD] = sprintf('%s:%s', $user, $pass);
104
+ }
105
+ }
106
+ }
107
+ }
108
+ if (isset($request['headers'])) $options[CURLOPT_HTTPHEADER] = $request['headers'];
109
+
110
+ /*
111
+ Add check to see if it's an API v2 call if so then json encode the contents. This is so that it is backwards compatible with API v1 endpoints.
112
+ */
113
+ if (isset($additional['api_v2']) && !empty($request['postfields'])) {
114
+ $request['postfields'] = json_encode($request['postfields']);
115
+ }
116
+
117
+ if ($method == 'GET' && $this->outFile) { // GET
118
+ $options[CURLOPT_RETURNTRANSFER] = false;
119
+ $options[CURLOPT_HEADER] = false;
120
+ $options[CURLOPT_FILE] = $this->outFile;
121
+ $options[CURLOPT_BINARYTRANSFER] = true;
122
+ $options[CURLOPT_FAILONERROR] = true;
123
+ /*
124
+ Not sure if this is used, keeping it here for backwards compatibility at the moment.
125
+ With API v2 the headers are set in the $request they are set above if they are set.
126
+ */
127
+ if (isset($additional['headers'])) $options[CURLOPT_HTTPHEADER] = $additional['headers'];
128
+ $this->outFile = null;
129
+ } elseif ($method == 'POST' && $this->outFile) { // POST request for download a file
130
+ $options[CURLOPT_POST] = true;
131
+ $options[CURLOPT_RETURNTRANSFER] = false;
132
+ $options[CURLOPT_HEADER] = false;
133
+ $options[CURLOPT_FILE] = $this->outFile;
134
+ $options[CURLOPT_BINARYTRANSFER] = true;
135
+ $options[CURLOPT_FAILONERROR] = true;
136
+ $this->outFile = null;
137
+ } elseif ($method == 'POST' && $this->inFile) { // POST request for upload a file
138
+ $options[CURLOPT_POST] = true;
139
+ $options[CURLOPT_POSTFIELDS] = $this->inFile;
140
+ } elseif ($method == 'POST') { // POST request
141
+ $options[CURLOPT_POST] = true;
142
+ $options[CURLOPT_POSTFIELDS] = $request['postfields'];
143
+ } elseif ($method == 'PUT' && $this->inFile) { // PUT request
144
+ $options[CURLOPT_PUT] = true;
145
+ $options[CURLOPT_INFILE] = $this->inFile;
146
+ // @todo Update so the data is not loaded into memory to get its size
147
+ $options[CURLOPT_INFILESIZE] = strlen(stream_get_contents($this->inFile));
148
+ fseek($this->inFile, 0);
149
+ $this->inFile = null;
150
+ }
151
+
152
+
153
+ // Set the cURL options at once
154
+ curl_setopt_array($handle, $options);
155
+
156
+ // Execute, get any error and close
157
+ $response = curl_exec($handle);
158
+ $error = curl_error($handle);
159
+ $getinfo = curl_getinfo($handle);
160
+ curl_close($handle);
161
+
162
+ //Check if a cURL error has occured
163
+ if ($response === false) {
164
+ throw new IWP_Dropbox_CurlException($error);
165
+ } else {
166
+ // Parse the response if it is a string
167
+ if (is_string($response)) {
168
+ $response = $this->parse($response);
169
+ }
170
+
171
+ // Set the last response
172
+ $this->lastResponse = $response;
173
+
174
+ $code = (!empty($response['code'])) ? $response['code'] : $getinfo['http_code'];
175
+
176
+ // The API doesn't return an error message for the 304 status code...
177
+ // 304's are only returned when the path supplied during metadata calls has not been modified
178
+ if ($code == 304) {
179
+ $response['body'] = new stdClass;
180
+ $response['body']->error = 'The folder contents have not changed';
181
+ }
182
+
183
+ // Check if an error occurred and throw an Exception
184
+ if (!empty($response['body']->error) || $code >= 400) {
185
+ // Dropbox returns error messages inconsistently...
186
+ if (!empty($response['body']->error) && $response['body']->error instanceof stdClass) {
187
+ $array = array_values((array) $response['body']->error);
188
+ //Dropbox API v2 only throws 409 errors if this error is a incorrect_offset then we need the entire error array not just the message. PHP Exception messages have to be a string so JSON encode the array.
189
+ if (strpos($array[0] , 'incorrect_offset') !== false) {
190
+ $message = json_encode($array);
191
+ } elseif (strpos($array[0] , 'lookup_failed') !== false ) {
192
+ //re-structure the array so it is correctly formatted for API
193
+ //Note: Dropbox v2 returns different errors at different stages hence this fix
194
+ $correctOffset = array(
195
+ '0' => $array[1]->{'.tag'},
196
+ '1' => $array[1]->correct_offset
197
+ );
198
+
199
+ $message = json_encode($correctOffset);
200
+ } else {
201
+ $message = $array[0];
202
+ }
203
+ } elseif (!empty($response['body']->error)) {
204
+ $message = $response['body']->error;
205
+ } elseif (is_string($response['body'])) {
206
+ // 31 Mar 2017 - This case has been found to exist; though the docs imply that there's always an 'error' property and that what is returned in JSON, we found a case of this being returned just as a simple string, but detectable via an HTTP 400: Error in call to API function "files/upload_session/append_v2": HTTP header "Dropbox-API-Arg": cursor.offset: expected integer, got string
207
+ $message = $response['body'];
208
+ } else {
209
+ $message = "HTTP bad response code: $code";
210
+ }
211
+
212
+ // Throw an Exception with the appropriate with the appropriate message and code
213
+ switch ($code) {
214
+ case 304:
215
+ throw new IWP_Dropbox_NotModifiedException($message, 304);
216
+