Version Description
- Dropbox improvements and bug fixes
Download this release
Release Info
Developer | danielhuesken |
Plugin | BackWPup – WordPress Backup Plugin |
Version | 1.6.2 |
Comparing to | |
See all releases |
Code changes from version 1.6.1 to 1.6.2
- app/backwpup_dojob.php +46 -20
- app/css/backup-icon.gif +0 -0
- app/dropbox-auth.php +2 -2
- app/js/options.js +2 -0
- app/libs/dropbox.php +0 -1096
- app/libs/dropbox/dropbox.php +200 -0
- app/libs/dropbox/oauth.php +879 -0
- app/libs/sugarsync.php +285 -0
- app/options-edit-job.php +15 -0
- app/options-save.php +15 -19
- app/php-functions.php +7 -0
- app/php5-functions.php +29 -6
- backwpup.php +2 -3
- readme.txt +88 -85
app/backwpup_dojob.php
CHANGED
@@ -173,6 +173,12 @@ class backwpup_dojob {
|
|
173 |
else
|
174 |
trigger_error(__('Curl and Json extensions needed for DropBox!','backwpup'),E_USER_ERROR);
|
175 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
if (in_array('S3',$dests) and !empty($this->job['awsAccessKey']) and !empty($this->job['awsSecretKey']) and !empty($this->job['awsBucket'])) {
|
177 |
if (function_exists('curl_exec'))
|
178 |
$this->destination_s3();
|
@@ -961,6 +967,9 @@ class backwpup_dojob {
|
|
961 |
|
962 |
|
963 |
private function destination_ftp() {
|
|
|
|
|
|
|
964 |
$ftpport=21;
|
965 |
$ftphost=$this->job['ftphost'];
|
966 |
if (false !== strpos($this->job['ftphost'],':')) //look for port
|
@@ -1143,6 +1152,8 @@ class backwpup_dojob {
|
|
1143 |
if (!class_exists('CFRuntime'))
|
1144 |
require_once(dirname(__FILE__).'/libs/aws/sdk.class.php');
|
1145 |
|
|
|
|
|
1146 |
try {
|
1147 |
$s3 = new AmazonS3($this->job['awsAccessKey'], $this->job['awsSecretKey']);
|
1148 |
|
@@ -1155,7 +1166,7 @@ class backwpup_dojob {
|
|
1155 |
else
|
1156 |
$storage=AmazonS3::STORAGE_STANDARD;
|
1157 |
|
1158 |
-
if ($s3->
|
1159 |
trigger_error(__('Backup File transferred to S3://','backwpup').$this->job['awsBucket'].'/'.$this->job['awsdir'].$this->backupfile,E_USER_NOTICE);
|
1160 |
$this->lastbackupdownloadurl='admin.php?page=BackWPup&subpage=backups&action=downloads3&file='.$this->job['awsdir'].$this->backupfile.'&jobid='.$this->jobid;
|
1161 |
} else {
|
@@ -1275,12 +1286,14 @@ class backwpup_dojob {
|
|
1275 |
}
|
1276 |
|
1277 |
private function destination_msazure() {
|
1278 |
-
|
1279 |
if (!class_exists('Microsoft_WindowsAzure_Storage_Blob')) {
|
1280 |
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).'/libs');
|
1281 |
require_once 'Microsoft/WindowsAzure/Storage/Blob.php';
|
1282 |
}
|
1283 |
-
|
|
|
|
|
1284 |
try {
|
1285 |
$storageClient = new Microsoft_WindowsAzure_Storage_Blob($this->job['msazureHost'],$this->job['msazureAccName'],$this->job['msazureKey']);
|
1286 |
|
@@ -1290,12 +1303,8 @@ class backwpup_dojob {
|
|
1290 |
} else {
|
1291 |
trigger_error(__('Connected to Microsoft Azure Container:','backwpup').' '.$this->job['msazureContainer'],E_USER_NOTICE);
|
1292 |
}
|
1293 |
-
|
1294 |
-
|
1295 |
-
$result = $storageClient->putBlob($this->job['msazureContainer'], $this->job['msazuredir'].$this->backupfile, $this->backupdir.$this->backupfile);
|
1296 |
-
} else {
|
1297 |
-
$result = $storageClient->putLargeBlob($this->job['msazureContainer'], $this->job['msazuredir'].$this->backupfile, $this->backupdir.$this->backupfile);
|
1298 |
-
}
|
1299 |
|
1300 |
if ($result->Name==$this->job['msazuredir'].$this->backupfile) {
|
1301 |
trigger_error(__('Backup File transferred to azure://','backwpup').$this->job['msazuredir'].$this->backupfile,E_USER_NOTICE);
|
@@ -1359,15 +1368,12 @@ class backwpup_dojob {
|
|
1359 |
private function destination_dropbox(){
|
1360 |
|
1361 |
if (!class_exists('Dropbox'))
|
1362 |
-
require_once (dirname(__FILE__).'/libs/dropbox.php');
|
1363 |
-
|
1364 |
-
$this->need_free_memory(filesize($this->backupdir.$this->backupfile)*1.3);
|
1365 |
|
1366 |
try {
|
1367 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
1368 |
// set the tokens
|
1369 |
-
$dropbox->
|
1370 |
-
$dropbox->setOAuthTokenSecret($this->job['dropesecret']);
|
1371 |
$info=$dropbox->accountInfo();
|
1372 |
if (!empty($info['uid'])) {
|
1373 |
trigger_error(__('Authed to DropBox from ','backwpup').$info['display_name'],E_USER_NOTICE);
|
@@ -1380,13 +1386,8 @@ class backwpup_dojob {
|
|
1380 |
} else {
|
1381 |
trigger_error(__('Free Space on DropBox: ','backwpup').backwpup_formatBytes($dropboxfreespase),E_USER_NOTICE);
|
1382 |
}
|
1383 |
-
//Check Backup File Size max 300MB allowed
|
1384 |
-
if (filesize($this->backupdir.$this->backupfile)>314572800) {
|
1385 |
-
trigger_error(__('DropBox API only allow upload files lower than 300MB!!!','backwpup'),E_USER_ERROR);
|
1386 |
-
return;
|
1387 |
-
}
|
1388 |
// put the file
|
1389 |
-
$response = $dropbox->
|
1390 |
if ($response['result']=="winner!") {
|
1391 |
$this->lastbackupdownloadurl='admin.php?page=BackWPup&subpage=backups&action=downloaddropbox&file='.$this->job['dropedir'].$this->backupfile.'&jobid='.$this->jobid;
|
1392 |
trigger_error(__('Backup File transferred to DropBox.','backwpup'),E_USER_NOTICE);
|
@@ -1419,6 +1420,31 @@ class backwpup_dojob {
|
|
1419 |
trigger_error(__('DropBox API:','backwpup').' '.$e->getMessage(),E_USER_ERROR);
|
1420 |
}
|
1421 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1422 |
|
1423 |
private function job_end($logfile ='') {
|
1424 |
if (empty($logfile)) $logfile=$this->logdir.$this->logfile;
|
173 |
else
|
174 |
trigger_error(__('Curl and Json extensions needed for DropBox!','backwpup'),E_USER_ERROR);
|
175 |
}
|
176 |
+
if (in_array('SUGARSYNC',$dests) and !empty($this->job['sugaruser']) and !empty($this->job['sugarpass'])) {
|
177 |
+
if (function_exists('curl_exec') )
|
178 |
+
$this->destination_sugarsync();
|
179 |
+
else
|
180 |
+
trigger_error(__('Curl and Json extensions needed for DropBox!','backwpup'),E_USER_ERROR);
|
181 |
+
}
|
182 |
if (in_array('S3',$dests) and !empty($this->job['awsAccessKey']) and !empty($this->job['awsSecretKey']) and !empty($this->job['awsBucket'])) {
|
183 |
if (function_exists('curl_exec'))
|
184 |
$this->destination_s3();
|
967 |
|
968 |
|
969 |
private function destination_ftp() {
|
970 |
+
|
971 |
+
$this->need_free_memory(filesize($this->backupdir.$this->backupfile)*1.5);
|
972 |
+
|
973 |
$ftpport=21;
|
974 |
$ftphost=$this->job['ftphost'];
|
975 |
if (false !== strpos($this->job['ftphost'],':')) //look for port
|
1152 |
if (!class_exists('CFRuntime'))
|
1153 |
require_once(dirname(__FILE__).'/libs/aws/sdk.class.php');
|
1154 |
|
1155 |
+
$this->need_free_memory(26214400*1.1);
|
1156 |
+
|
1157 |
try {
|
1158 |
$s3 = new AmazonS3($this->job['awsAccessKey'], $this->job['awsSecretKey']);
|
1159 |
|
1166 |
else
|
1167 |
$storage=AmazonS3::STORAGE_STANDARD;
|
1168 |
|
1169 |
+
if ($s3->create_mpu_object($this->job['awsBucket'], $this->job['awsdir'].$this->backupfile, array('fileUpload' => $this->backupdir.$this->backupfile,'acl' => AmazonS3::ACL_PRIVATE,'storage' => $storage,'partSize'=>26214400))) {//transfere file to S3
|
1170 |
trigger_error(__('Backup File transferred to S3://','backwpup').$this->job['awsBucket'].'/'.$this->job['awsdir'].$this->backupfile,E_USER_NOTICE);
|
1171 |
$this->lastbackupdownloadurl='admin.php?page=BackWPup&subpage=backups&action=downloads3&file='.$this->job['awsdir'].$this->backupfile.'&jobid='.$this->jobid;
|
1172 |
} else {
|
1286 |
}
|
1287 |
|
1288 |
private function destination_msazure() {
|
1289 |
+
|
1290 |
if (!class_exists('Microsoft_WindowsAzure_Storage_Blob')) {
|
1291 |
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).'/libs');
|
1292 |
require_once 'Microsoft/WindowsAzure/Storage/Blob.php';
|
1293 |
}
|
1294 |
+
|
1295 |
+
$this->need_free_memory(4194304*1.5);
|
1296 |
+
|
1297 |
try {
|
1298 |
$storageClient = new Microsoft_WindowsAzure_Storage_Blob($this->job['msazureHost'],$this->job['msazureAccName'],$this->job['msazureKey']);
|
1299 |
|
1303 |
} else {
|
1304 |
trigger_error(__('Connected to Microsoft Azure Container:','backwpup').' '.$this->job['msazureContainer'],E_USER_NOTICE);
|
1305 |
}
|
1306 |
+
|
1307 |
+
$result = $storageClient->putBlob($this->job['msazureContainer'], $this->job['msazuredir'].$this->backupfile, $this->backupdir.$this->backupfile);
|
|
|
|
|
|
|
|
|
1308 |
|
1309 |
if ($result->Name==$this->job['msazuredir'].$this->backupfile) {
|
1310 |
trigger_error(__('Backup File transferred to azure://','backwpup').$this->job['msazuredir'].$this->backupfile,E_USER_NOTICE);
|
1368 |
private function destination_dropbox(){
|
1369 |
|
1370 |
if (!class_exists('Dropbox'))
|
1371 |
+
require_once (dirname(__FILE__).'/libs/dropbox/dropbox.php');
|
|
|
|
|
1372 |
|
1373 |
try {
|
1374 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
1375 |
// set the tokens
|
1376 |
+
$dropbox->setOAuthTokens($this->job['dropetoken'],$this->job['dropesecret']);
|
|
|
1377 |
$info=$dropbox->accountInfo();
|
1378 |
if (!empty($info['uid'])) {
|
1379 |
trigger_error(__('Authed to DropBox from ','backwpup').$info['display_name'],E_USER_NOTICE);
|
1386 |
} else {
|
1387 |
trigger_error(__('Free Space on DropBox: ','backwpup').backwpup_formatBytes($dropboxfreespase),E_USER_NOTICE);
|
1388 |
}
|
|
|
|
|
|
|
|
|
|
|
1389 |
// put the file
|
1390 |
+
$response = $dropbox->upload($this->backupdir.$this->backupfile,$this->job['dropedir']);
|
1391 |
if ($response['result']=="winner!") {
|
1392 |
$this->lastbackupdownloadurl='admin.php?page=BackWPup&subpage=backups&action=downloaddropbox&file='.$this->job['dropedir'].$this->backupfile.'&jobid='.$this->jobid;
|
1393 |
trigger_error(__('Backup File transferred to DropBox.','backwpup'),E_USER_NOTICE);
|
1420 |
trigger_error(__('DropBox API:','backwpup').' '.$e->getMessage(),E_USER_ERROR);
|
1421 |
}
|
1422 |
}
|
1423 |
+
|
1424 |
+
private function destination_sugarsync(){
|
1425 |
+
|
1426 |
+
if (!class_exists('SugarSync'))
|
1427 |
+
require_once (dirname(__FILE__).'/libs/sugarsync.php');
|
1428 |
+
|
1429 |
+
$this->need_free_memory(filesize($this->backupdir.$this->backupfile)*1.5);
|
1430 |
+
|
1431 |
+
try {
|
1432 |
+
$sugarsync = new SugarSync($this->job['sugaruser'],base64_decode($this->job['sugarpass']),BACKWPUP_SUGARSYNC_ACCESSKEY, BACKWPUP_SUGARSYNC_PRIVATEACCESSKEY);
|
1433 |
+
// set the tokens
|
1434 |
+
$user=$sugarsync->user();
|
1435 |
+
$workspace=$sugarsync->get($user->syncfolders);
|
1436 |
+
$workspacefiles=$sugarsync->get('https://api.sugarsync.com/folder/:sc:970679:1/contents');
|
1437 |
+
//var_dump($workspacefiles);
|
1438 |
+
|
1439 |
+
$folder=$sugarsync->createfolder($user->webArchive,untrailingslashit($this->job['sugardir']));
|
1440 |
+
//$reponse=$sugarsync->createfile($user->webArchive,$this->backupdir.$this->backupfile);
|
1441 |
+
|
1442 |
+
|
1443 |
+
} catch (Exception $e) {
|
1444 |
+
trigger_error(__('SugarSync API:','backwpup').' '.$e->getMessage(),E_USER_ERROR);
|
1445 |
+
}
|
1446 |
+
}
|
1447 |
+
|
1448 |
|
1449 |
private function job_end($logfile ='') {
|
1450 |
if (empty($logfile)) $logfile=$this->logdir.$this->logfile;
|
app/css/backup-icon.gif
ADDED
Binary file
|
app/dropbox-auth.php
CHANGED
@@ -4,14 +4,14 @@ if (file_exists(trim($_GET['wpabs']).'wp-load.php')) {
|
|
4 |
} else {
|
5 |
header("HTTP/1.0 404 Not Found");
|
6 |
}
|
7 |
-
require_once (dirname(__FILE__).'/libs/dropbox.php');
|
8 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
9 |
//for Dropbox oAuth backlink
|
10 |
if ($_GET['uid']>1 and !empty($_GET['oauth_token'])) {
|
11 |
$reqtoken=get_option('backwpup_dropboxrequest');
|
12 |
if ($reqtoken['oAuthRequestToken']==$_GET['oauth_token']) {
|
13 |
//Get Access Tokens
|
14 |
-
$oAuthStuff = $dropbox->oAuthAccessToken($
|
15 |
//Save Tokens
|
16 |
$jobs=get_option('backwpup_jobs');
|
17 |
$jobs[$reqtoken['jobid']]['dropetoken']=$oAuthStuff['oauth_token'];
|
4 |
} else {
|
5 |
header("HTTP/1.0 404 Not Found");
|
6 |
}
|
7 |
+
require_once (dirname(__FILE__).'/libs/dropbox/dropbox.php');
|
8 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
9 |
//for Dropbox oAuth backlink
|
10 |
if ($_GET['uid']>1 and !empty($_GET['oauth_token'])) {
|
11 |
$reqtoken=get_option('backwpup_dropboxrequest');
|
12 |
if ($reqtoken['oAuthRequestToken']==$_GET['oauth_token']) {
|
13 |
//Get Access Tokens
|
14 |
+
$oAuthStuff = $dropbox->oAuthAccessToken($reqtoken['oAuthRequestToken'],$reqtoken['oAuthRequestTokenSecret']);
|
15 |
//Save Tokens
|
16 |
$jobs=get_option('backwpup_jobs');
|
17 |
$jobs[$reqtoken['jobid']]['dropetoken']=$oAuthStuff['oauth_token'];
|
app/js/options.js
CHANGED
@@ -8,6 +8,7 @@ jQuery(document).ready( function($) {
|
|
8 |
$('#tomsazure').show();
|
9 |
$('#torsc').show();
|
10 |
$('#todropbox').show();
|
|
|
11 |
$('#todir').show();
|
12 |
$('#tomail').show();
|
13 |
} else {
|
@@ -17,6 +18,7 @@ jQuery(document).ready( function($) {
|
|
17 |
$('#tomsazure').hide();
|
18 |
$('#torsc').hide();
|
19 |
$('#todropbox').hide();
|
|
|
20 |
$('#todir').hide();
|
21 |
$('#tomail').hide();
|
22 |
}
|
8 |
$('#tomsazure').show();
|
9 |
$('#torsc').show();
|
10 |
$('#todropbox').show();
|
11 |
+
$('#tosugarsync').show();
|
12 |
$('#todir').show();
|
13 |
$('#tomail').show();
|
14 |
} else {
|
18 |
$('#tomsazure').hide();
|
19 |
$('#torsc').hide();
|
20 |
$('#todropbox').hide();
|
21 |
+
$('#tosugarsync').hide();
|
22 |
$('#todir').hide();
|
23 |
$('#tomail').hide();
|
24 |
}
|
app/libs/dropbox.php
DELETED
@@ -1,1096 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Dropbox class
|
5 |
-
*
|
6 |
-
* This source file can be used to communicate with Dropbox (http://dropbox.com)
|
7 |
-
*
|
8 |
-
* The class is documented in the file itself. If you find any bugs help me out and report them. Reporting can be done by sending an email to php-dropbox-bugs[at]verkoyen[dot]eu.
|
9 |
-
* If you report a bug, make sure you give me enough information (include your code).
|
10 |
-
*
|
11 |
-
* Changelog since 1.0.2
|
12 |
-
* - Added methods to enable oauth-usage.
|
13 |
-
*
|
14 |
-
* Changelog since 1.0.1
|
15 |
-
* - Bugfix: when doing multiple calles where GET and POST is mixed, the postfields should be reset (thx to Daniel H�sken)
|
16 |
-
*
|
17 |
-
* Changelog since 1.0.0
|
18 |
-
* - fixed some issues with generation off the basestring
|
19 |
-
*
|
20 |
-
* License
|
21 |
-
* Copyright (c), Tijs Verkoyen. All rights reserved.
|
22 |
-
*
|
23 |
-
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
24 |
-
*
|
25 |
-
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
26 |
-
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
27 |
-
* 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
|
28 |
-
*
|
29 |
-
* This software is provided by the author "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the author be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.
|
30 |
-
*
|
31 |
-
* @author Tijs Verkoyen <php-dropbox@verkoyen.eu>
|
32 |
-
* @version 1.0.3
|
33 |
-
*
|
34 |
-
* @copyright Copyright (c), Tijs Verkoyen. All rights reserved.
|
35 |
-
* @license BSD License
|
36 |
-
*/
|
37 |
-
class Dropbox
|
38 |
-
{
|
39 |
-
// internal constant to enable/disable debugging
|
40 |
-
const DEBUG = false;
|
41 |
-
|
42 |
-
// url for the dropbox-api
|
43 |
-
const API_URL = 'https://api.dropbox.com';
|
44 |
-
const API_CONTENT_URL = 'https://api-content.dropbox.com';
|
45 |
-
|
46 |
-
// port for the dropbox-api
|
47 |
-
const API_PORT = 443;
|
48 |
-
|
49 |
-
// current version
|
50 |
-
const VERSION = '1.0.3';
|
51 |
-
|
52 |
-
|
53 |
-
/**
|
54 |
-
* A cURL instance
|
55 |
-
*
|
56 |
-
* @var resource
|
57 |
-
*/
|
58 |
-
private $curl;
|
59 |
-
|
60 |
-
|
61 |
-
/**
|
62 |
-
* The application key
|
63 |
-
*
|
64 |
-
* @var string
|
65 |
-
*/
|
66 |
-
private $applicationKey;
|
67 |
-
|
68 |
-
|
69 |
-
/**
|
70 |
-
* The application secret
|
71 |
-
*
|
72 |
-
* @var string
|
73 |
-
*/
|
74 |
-
private $applicationSecret;
|
75 |
-
|
76 |
-
|
77 |
-
/**
|
78 |
-
* The oAuth-token
|
79 |
-
*
|
80 |
-
* @var string
|
81 |
-
*/
|
82 |
-
private $oAuthToken = '';
|
83 |
-
|
84 |
-
|
85 |
-
/**
|
86 |
-
* The oAuth-token-secret
|
87 |
-
*
|
88 |
-
* @var string
|
89 |
-
*/
|
90 |
-
private $oAuthTokenSecret = '';
|
91 |
-
|
92 |
-
|
93 |
-
/**
|
94 |
-
* The timeout
|
95 |
-
*
|
96 |
-
* @var int
|
97 |
-
*/
|
98 |
-
private $timeOut = 60;
|
99 |
-
|
100 |
-
|
101 |
-
/**
|
102 |
-
* The user agent
|
103 |
-
*
|
104 |
-
* @var string
|
105 |
-
*/
|
106 |
-
private $userAgent;
|
107 |
-
|
108 |
-
|
109 |
-
// class methods
|
110 |
-
/**
|
111 |
-
* Default constructor
|
112 |
-
*
|
113 |
-
* @return void
|
114 |
-
* @param string $consumerKey The consumer key to use.
|
115 |
-
* @param string $consumerSecret The consumer secret to use.
|
116 |
-
*/
|
117 |
-
public function __construct($applicationKey, $applicationSecret)
|
118 |
-
{
|
119 |
-
$this->setApplicationKey($applicationKey);
|
120 |
-
$this->setApplicationSecret($applicationSecret);
|
121 |
-
}
|
122 |
-
|
123 |
-
|
124 |
-
/**
|
125 |
-
* Default destructor
|
126 |
-
*
|
127 |
-
* @return void
|
128 |
-
*/
|
129 |
-
public function __destruct()
|
130 |
-
{
|
131 |
-
if($this->curl != null) curl_close($this->curl);
|
132 |
-
}
|
133 |
-
|
134 |
-
|
135 |
-
/**
|
136 |
-
* Format the parameters as a querystring
|
137 |
-
*
|
138 |
-
* @return string
|
139 |
-
* @param array $parameters
|
140 |
-
*/
|
141 |
-
private function buildQuery(array $parameters)
|
142 |
-
{
|
143 |
-
// no parameters?
|
144 |
-
if(empty($parameters)) return '';
|
145 |
-
|
146 |
-
// encode the keys
|
147 |
-
$keys = self::urlencode_rfc3986(array_keys($parameters));
|
148 |
-
|
149 |
-
// encode the values
|
150 |
-
$values = self::urlencode_rfc3986(array_values($parameters));
|
151 |
-
|
152 |
-
// reset the parameters
|
153 |
-
$parameters = array_combine($keys, $values);
|
154 |
-
|
155 |
-
// sort parameters by key
|
156 |
-
uksort($parameters, 'strcmp');
|
157 |
-
|
158 |
-
// loop parameters
|
159 |
-
foreach($parameters as $key => $value)
|
160 |
-
{
|
161 |
-
// sort by value
|
162 |
-
if(is_array($value)) $parameters[$key] = natsort($value);
|
163 |
-
}
|
164 |
-
|
165 |
-
// process parameters
|
166 |
-
foreach($parameters as $key => $value) $chunks[] = $key .'='. str_replace('%25', '%', $value);
|
167 |
-
|
168 |
-
// return
|
169 |
-
return implode('&', $chunks);
|
170 |
-
}
|
171 |
-
|
172 |
-
|
173 |
-
/**
|
174 |
-
* All OAuth 1.0 requests use the same basic algorithm for creating a signature base string and a signature.
|
175 |
-
* The signature base string is composed of the HTTP method being used, followed by an ampersand ("&") and then the URL-encoded base URL being accessed,
|
176 |
-
* complete with path (but not query parameters), followed by an ampersand ("&").
|
177 |
-
* Then, you take all query parameters and POST body parameters (when the POST body is of the URL-encoded type, otherwise the POST body is ignored),
|
178 |
-
* including the OAuth parameters necessary for negotiation with the request at hand, and sort them in lexicographical order by first parameter name and
|
179 |
-
* then parameter value (for duplicate parameters), all the while ensuring that both the key and the value for each parameter are URL encoded in isolation.
|
180 |
-
* Instead of using the equals ("=") sign to mark the key/value relationship, you use the URL-encoded form of "%3D". Each parameter is then joined by the
|
181 |
-
* URL-escaped ampersand sign, "%26".
|
182 |
-
*
|
183 |
-
* @return string
|
184 |
-
* @param string $url
|
185 |
-
* @param string $method
|
186 |
-
* @param array $parameters
|
187 |
-
*/
|
188 |
-
private function calculateBaseString($url, $method, array $parameters)
|
189 |
-
{
|
190 |
-
// redefine
|
191 |
-
$url = (string) $url;
|
192 |
-
$parameters = (array) $parameters;
|
193 |
-
|
194 |
-
// init var
|
195 |
-
$pairs = array();
|
196 |
-
$chunks = array();
|
197 |
-
|
198 |
-
// sort parameters by key
|
199 |
-
uksort($parameters, 'strcmp');
|
200 |
-
|
201 |
-
// loop parameters
|
202 |
-
foreach($parameters as $key => $value)
|
203 |
-
{
|
204 |
-
// sort by value
|
205 |
-
if(is_array($value)) $parameters[$key] = natsort($value);
|
206 |
-
}
|
207 |
-
|
208 |
-
// process queries
|
209 |
-
foreach($parameters as $key => $value)
|
210 |
-
{
|
211 |
-
// only add if not already in the url
|
212 |
-
if(substr_count($url, $key .'='. $value) == 0) $chunks[] = self::urlencode_rfc3986($key) .'%3D'. self::urlencode_rfc3986($value);
|
213 |
-
}
|
214 |
-
|
215 |
-
$urlChunks = explode('/', $url);
|
216 |
-
$i = 0;
|
217 |
-
|
218 |
-
foreach($urlChunks as &$chunk)
|
219 |
-
{
|
220 |
-
if($i > 4) $chunk = self::urlencode_rfc3986($chunk);
|
221 |
-
else $chunk = urlencode($chunk);
|
222 |
-
|
223 |
-
$i++;
|
224 |
-
|
225 |
-
}
|
226 |
-
|
227 |
-
// build base
|
228 |
-
$base = $method .'&';
|
229 |
-
$base .= implode('%2F', $urlChunks);
|
230 |
-
$base .= (substr_count($url, '?')) ? '%26' : '&';
|
231 |
-
$base .= implode('%26', $chunks);
|
232 |
-
$base = str_replace(array('%3F', '%20'), array('&', '%2520'), $base);
|
233 |
-
|
234 |
-
// return
|
235 |
-
return $base;
|
236 |
-
}
|
237 |
-
|
238 |
-
|
239 |
-
/**
|
240 |
-
* Build the Authorization header
|
241 |
-
* @later: fix me
|
242 |
-
*
|
243 |
-
* @return string
|
244 |
-
* @param array $parameters
|
245 |
-
* @param string $url
|
246 |
-
*/
|
247 |
-
private function calculateHeader(array $parameters, $url)
|
248 |
-
{
|
249 |
-
// redefine
|
250 |
-
$url = (string) $url;
|
251 |
-
|
252 |
-
// divide into parts
|
253 |
-
$parts = parse_url($url);
|
254 |
-
|
255 |
-
// init var
|
256 |
-
$chunks = array();
|
257 |
-
|
258 |
-
// process queries
|
259 |
-
foreach($parameters as $key => $value) $chunks[] = str_replace('%25', '%', self::urlencode_rfc3986($key) .'="'. self::urlencode_rfc3986($value) .'"');
|
260 |
-
|
261 |
-
// build return
|
262 |
-
$return = 'Authorization: OAuth realm="' . $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '", ';
|
263 |
-
$return .= implode(',', $chunks);
|
264 |
-
|
265 |
-
// prepend name and OAuth part
|
266 |
-
return $return;
|
267 |
-
}
|
268 |
-
|
269 |
-
|
270 |
-
/**
|
271 |
-
* Make an call to the oAuth
|
272 |
-
* @todo refactor me
|
273 |
-
*
|
274 |
-
* @return array
|
275 |
-
* @param string $method
|
276 |
-
* @param array[optional] $parameters
|
277 |
-
*/
|
278 |
-
private function doOAuthCall($url, array $parameters = null, $method = 'POST', $expectJSON = true)
|
279 |
-
{
|
280 |
-
// redefine
|
281 |
-
$url = (string) $url;
|
282 |
-
|
283 |
-
// append default parameters
|
284 |
-
$parameters['oauth_consumer_key'] = $this->getApplicationKey();
|
285 |
-
$parameters['oauth_nonce'] = md5(microtime() . rand());
|
286 |
-
$parameters['oauth_timestamp'] = time();
|
287 |
-
$parameters['oauth_signature_method'] = 'HMAC-SHA1';
|
288 |
-
$parameters['oauth_version'] = '1.0';
|
289 |
-
|
290 |
-
// calculate the base string
|
291 |
-
$base = $this->calculateBaseString(self::API_URL .'/'. $url, 'POST', $parameters);
|
292 |
-
|
293 |
-
// add sign into the parameters
|
294 |
-
$parameters['oauth_signature'] = $this->hmacsha1($this->getApplicationSecret() .'&' . $this->getOAuthTokenSecret(), $base);
|
295 |
-
|
296 |
-
// calculate header
|
297 |
-
$header = $this->calculateHeader($parameters, self::API_URL .'/'. $url);
|
298 |
-
|
299 |
-
if($method == 'POST')
|
300 |
-
{
|
301 |
-
$options[CURLOPT_POST] = true;
|
302 |
-
$options[CURLOPT_POSTFIELDS] = $this->buildQuery($parameters);
|
303 |
-
}
|
304 |
-
|
305 |
-
else
|
306 |
-
{
|
307 |
-
// reset post
|
308 |
-
$options[CURLOPT_POST] = 0;
|
309 |
-
unset($options[CURLOPT_POSTFIELDS]);
|
310 |
-
|
311 |
-
// add the parameters into the querystring
|
312 |
-
if(!empty($parameters)) $url .= '?'. $this->buildQuery($parameters);
|
313 |
-
}
|
314 |
-
|
315 |
-
// set options
|
316 |
-
$options[CURLOPT_URL] = self::API_URL .'/'. $url;
|
317 |
-
$options[CURLOPT_PORT] = self::API_PORT;
|
318 |
-
$options[CURLOPT_USERAGENT] = $this->getUserAgent();
|
319 |
-
if(ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) $options[CURLOPT_FOLLOWLOCATION] = true;
|
320 |
-
$options[CURLOPT_RETURNTRANSFER] = true;
|
321 |
-
$options[CURLOPT_TIMEOUT] = (int) $this->getTimeOut();
|
322 |
-
$options[CURLOPT_SSL_VERIFYPEER] = false;
|
323 |
-
$options[CURLOPT_SSL_VERIFYHOST] = false;
|
324 |
-
$options[CURLOPT_HTTPHEADER] = array('Expect:');
|
325 |
-
|
326 |
-
// init
|
327 |
-
$this->curl = curl_init();
|
328 |
-
|
329 |
-
// set options
|
330 |
-
curl_setopt_array($this->curl, $options);
|
331 |
-
|
332 |
-
// execute
|
333 |
-
$response = curl_exec($this->curl);
|
334 |
-
$headers = curl_getinfo($this->curl);
|
335 |
-
|
336 |
-
// fetch errors
|
337 |
-
$errorNumber = curl_errno($this->curl);
|
338 |
-
$errorMessage = curl_error($this->curl);
|
339 |
-
|
340 |
-
// error?
|
341 |
-
if($errorNumber != '') throw new DropboxException($errorMessage, $errorNumber);
|
342 |
-
|
343 |
-
// return
|
344 |
-
if($expectJSON) return json_decode($response, true);
|
345 |
-
|
346 |
-
// fallback
|
347 |
-
return $response;
|
348 |
-
}
|
349 |
-
|
350 |
-
|
351 |
-
/**
|
352 |
-
* Make the call
|
353 |
-
*
|
354 |
-
* @return string
|
355 |
-
* @param string $url The url to call.
|
356 |
-
* @param array[optiona] $parameters Optional parameters.
|
357 |
-
* @param bool[optional] $method The method to use. Possible values are GET, POST.
|
358 |
-
* @param string[optional] $filePath The path to the file to upload.
|
359 |
-
* @param bool[optional] $expectJSON Do we expect JSON?
|
360 |
-
* @param bool[optional] $isContent Is this content?
|
361 |
-
*/
|
362 |
-
private function doCall($url, array $parameters = null, $method = 'GET', $filePath = null, $expectJSON = true, $isContent = false)
|
363 |
-
{
|
364 |
-
// allowed methods
|
365 |
-
$allowedMethods = array('GET', 'POST');
|
366 |
-
|
367 |
-
// redefine
|
368 |
-
$url = (string) $url;
|
369 |
-
$parameters = (array) $parameters;
|
370 |
-
$method = (string) $method;
|
371 |
-
$expectJSON = (bool) $expectJSON;
|
372 |
-
|
373 |
-
// validate method
|
374 |
-
if(!in_array($method, $allowedMethods)) throw new DropboxException('Unknown method ('. $method .'). Allowed methods are: '. implode(', ', $allowedMethods));
|
375 |
-
|
376 |
-
// append default parameters
|
377 |
-
$oauth['oauth_consumer_key'] = $this->getApplicationKey();
|
378 |
-
$oauth['oauth_nonce'] = md5(microtime() . rand());
|
379 |
-
$oauth['oauth_timestamp'] = time();
|
380 |
-
$oauth['oauth_token'] = $this->getOAuthToken();
|
381 |
-
$oauth['oauth_signature_method'] = 'HMAC-SHA1';
|
382 |
-
$oauth['oauth_version'] = '1.0';
|
383 |
-
|
384 |
-
// set data
|
385 |
-
$data = $oauth;
|
386 |
-
if(!empty($parameters))
|
387 |
-
{
|
388 |
-
// convert to UTF-8
|
389 |
-
foreach($parameters as &$value) $value = utf8_encode($value);
|
390 |
-
|
391 |
-
// merge
|
392 |
-
$data = array_merge($data, $parameters);
|
393 |
-
}
|
394 |
-
|
395 |
-
if($filePath != null)
|
396 |
-
{
|
397 |
-
// process file
|
398 |
-
$fileInfo = pathinfo($filePath);
|
399 |
-
|
400 |
-
// add to the data
|
401 |
-
$data['file'] = $fileInfo['basename'];
|
402 |
-
|
403 |
-
}
|
404 |
-
|
405 |
-
// calculate the base string
|
406 |
-
if($isContent) $base = $this->calculateBaseString(self::API_CONTENT_URL .'/'. $url, $method, $data);
|
407 |
-
else $base = $this->calculateBaseString(self::API_URL .'/'. $url, $method, $data);
|
408 |
-
|
409 |
-
// based on the method, we should handle the parameters in a different way
|
410 |
-
if($method == 'POST')
|
411 |
-
{
|
412 |
-
// file provided?
|
413 |
-
if($filePath != null)
|
414 |
-
{
|
415 |
-
// build a boundary
|
416 |
-
$boundary = md5(time());
|
417 |
-
|
418 |
-
// init var
|
419 |
-
$content = '--'. $boundary ."\r\n";
|
420 |
-
|
421 |
-
// set file
|
422 |
-
$content .= 'Content-Disposition: form-data; name=file; filename="'. $fileInfo['basename'] .'"' ."\r\n";
|
423 |
-
$content .= 'Content-Type: application/octet-stream'."\r\n";
|
424 |
-
$content .= "\r\n";
|
425 |
-
$content .= file_get_contents($filePath);
|
426 |
-
$content .="\r\n";
|
427 |
-
$content .="--". $boundary .'--';
|
428 |
-
|
429 |
-
// build headers
|
430 |
-
$headers[] = 'Content-Type: multipart/form-data; boundary='. $boundary;
|
431 |
-
$headers[] = 'Content-Length: '. strlen($content);
|
432 |
-
|
433 |
-
// set content
|
434 |
-
$options[CURLOPT_POSTFIELDS] = $content;
|
435 |
-
|
436 |
-
}
|
437 |
-
|
438 |
-
// no file
|
439 |
-
else $options[CURLOPT_POSTFIELDS] = $this->buildQuery($parameters);
|
440 |
-
|
441 |
-
// enable post
|
442 |
-
$options[CURLOPT_POST] = true;
|
443 |
-
}
|
444 |
-
|
445 |
-
else
|
446 |
-
{
|
447 |
-
// reset post
|
448 |
-
$options[CURLOPT_POST] = false;
|
449 |
-
unset($options[CURLOPT_POSTFIELDS]);
|
450 |
-
|
451 |
-
// add the parameters into the querystring
|
452 |
-
if(!empty($parameters)) $url .= '?'. $this->buildQuery($parameters);
|
453 |
-
}
|
454 |
-
|
455 |
-
// add sign into the parameters
|
456 |
-
$oauth['oauth_signature'] = $this->hmacsha1($this->getApplicationSecret() .'&' . $this->getOAuthTokenSecret(), $base);
|
457 |
-
|
458 |
-
if($isContent) $headers[] = $this->calculateHeader($oauth, self::API_CONTENT_URL .'/'. $url);
|
459 |
-
else $headers[] = $this->calculateHeader($oauth, self::API_URL .'/'. $url);
|
460 |
-
$headers[] = 'Expect:';
|
461 |
-
|
462 |
-
// set options
|
463 |
-
if($isContent) $options[CURLOPT_URL] = self::API_CONTENT_URL .'/'. $url;
|
464 |
-
else $options[CURLOPT_URL] = self::API_URL .'/'. $url;
|
465 |
-
$options[CURLOPT_PORT] = self::API_PORT;
|
466 |
-
$options[CURLOPT_USERAGENT] = $this->getUserAgent();
|
467 |
-
if(ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) $options[CURLOPT_FOLLOWLOCATION] = true;
|
468 |
-
$options[CURLOPT_RETURNTRANSFER] = true;
|
469 |
-
$options[CURLOPT_TIMEOUT] = (int) $this->getTimeOut();
|
470 |
-
$options[CURLOPT_SSL_VERIFYPEER] = false;
|
471 |
-
$options[CURLOPT_SSL_VERIFYHOST] = false;
|
472 |
-
$options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
|
473 |
-
$options[CURLOPT_HTTPHEADER] = $headers;
|
474 |
-
|
475 |
-
// init
|
476 |
-
if($this->curl == null) $this->curl = curl_init();
|
477 |
-
|
478 |
-
// set options
|
479 |
-
curl_setopt_array($this->curl, $options);
|
480 |
-
|
481 |
-
// execute
|
482 |
-
$response = curl_exec($this->curl);
|
483 |
-
$headers = curl_getinfo($this->curl);
|
484 |
-
|
485 |
-
// fetch errors
|
486 |
-
$errorNumber = curl_errno($this->curl);
|
487 |
-
$errorMessage = curl_error($this->curl);
|
488 |
-
|
489 |
-
if(!$expectJSON && $isContent)
|
490 |
-
{
|
491 |
-
// is it JSON?
|
492 |
-
$json = @json_decode($response, true);
|
493 |
-
if($json !== false && isset($json['error'])) throw new DropboxException($json['error']);
|
494 |
-
|
495 |
-
// set return
|
496 |
-
$return['content_type'] = $headers['content_type'];
|
497 |
-
$return['data'] = base64_encode($response);
|
498 |
-
|
499 |
-
// return
|
500 |
-
return $return;
|
501 |
-
}
|
502 |
-
|
503 |
-
// we don't expect JSON, return the response
|
504 |
-
if(!$expectJSON) return $response;
|
505 |
-
|
506 |
-
// replace ids with their string values, added because of some PHP-version can't handle these large values
|
507 |
-
$response = preg_replace('/id":(\d+)/', 'id":"\1"', $response);
|
508 |
-
|
509 |
-
// we expect JSON, so decode it
|
510 |
-
$json = @json_decode($response, true);
|
511 |
-
|
512 |
-
// validate JSON
|
513 |
-
if($json === null)
|
514 |
-
{
|
515 |
-
// should we provide debug information
|
516 |
-
if(self::DEBUG)
|
517 |
-
{
|
518 |
-
// make it output proper
|
519 |
-
echo '<pre>';
|
520 |
-
|
521 |
-
// dump the header-information
|
522 |
-
var_dump($headers);
|
523 |
-
|
524 |
-
// dump the error
|
525 |
-
var_dump($errorMessage);
|
526 |
-
|
527 |
-
// dump the raw response
|
528 |
-
var_dump($response);
|
529 |
-
|
530 |
-
// end proper format
|
531 |
-
echo '</pre>';
|
532 |
-
}
|
533 |
-
|
534 |
-
// throw exception
|
535 |
-
throw new DropboxException('Invalid response.');
|
536 |
-
}
|
537 |
-
|
538 |
-
// any error
|
539 |
-
if(isset($json['error']))
|
540 |
-
{
|
541 |
-
// should we provide debug information
|
542 |
-
if(self::DEBUG)
|
543 |
-
{
|
544 |
-
// make it output proper
|
545 |
-
echo '<pre>';
|
546 |
-
|
547 |
-
// dump the header-information
|
548 |
-
var_dump($headers);
|
549 |
-
|
550 |
-
// dump the raw response
|
551 |
-
var_dump($response);
|
552 |
-
|
553 |
-
// end proper format
|
554 |
-
echo '</pre>';
|
555 |
-
}
|
556 |
-
|
557 |
-
if(isset($json['error']) && is_string($json['error'])) $message = $json['error'];
|
558 |
-
elseif(isset($json['error']['hash']) && $json['error']['hash'] != '') $message = (string) $json['error']['hash'];
|
559 |
-
else $message = 'Invalid response.';
|
560 |
-
|
561 |
-
// throw exception
|
562 |
-
throw new DropboxException($message);
|
563 |
-
}
|
564 |
-
|
565 |
-
// return
|
566 |
-
return $json;
|
567 |
-
}
|
568 |
-
|
569 |
-
|
570 |
-
/**
|
571 |
-
* Get the application key
|
572 |
-
*
|
573 |
-
* @return string
|
574 |
-
*/
|
575 |
-
private function getApplicationKey()
|
576 |
-
{
|
577 |
-
return $this->applicationKey;
|
578 |
-
}
|
579 |
-
|
580 |
-
|
581 |
-
/**
|
582 |
-
* Get the application secret
|
583 |
-
*
|
584 |
-
* @return string
|
585 |
-
*/
|
586 |
-
private function getApplicationSecret()
|
587 |
-
{
|
588 |
-
return $this->applicationSecret;
|
589 |
-
}
|
590 |
-
|
591 |
-
|
592 |
-
/**
|
593 |
-
* Get the oAuth-token
|
594 |
-
*
|
595 |
-
* @return string
|
596 |
-
*/
|
597 |
-
private function getOAuthToken()
|
598 |
-
{
|
599 |
-
return $this->oAuthToken;
|
600 |
-
}
|
601 |
-
|
602 |
-
|
603 |
-
/**
|
604 |
-
* Get the oAuth-token-secret
|
605 |
-
*
|
606 |
-
* @return string
|
607 |
-
*/
|
608 |
-
private function getOAuthTokenSecret()
|
609 |
-
{
|
610 |
-
return $this->oAuthTokenSecret;
|
611 |
-
}
|
612 |
-
|
613 |
-
|
614 |
-
/**
|
615 |
-
* Get the timeout
|
616 |
-
*
|
617 |
-
* @return int
|
618 |
-
*/
|
619 |
-
public function getTimeOut()
|
620 |
-
{
|
621 |
-
return (int) $this->timeOut;
|
622 |
-
}
|
623 |
-
|
624 |
-
|
625 |
-
/**
|
626 |
-
* Get the useragent that will be used. Our version will be prepended to yours.
|
627 |
-
* It will look like: "PHP Dropbox/<version> <your-user-agent>"
|
628 |
-
*
|
629 |
-
* @return string
|
630 |
-
*/
|
631 |
-
public function getUserAgent()
|
632 |
-
{
|
633 |
-
return (string) 'PHP Dropbox/'. self::VERSION .' '. $this->userAgent;
|
634 |
-
}
|
635 |
-
|
636 |
-
|
637 |
-
/**
|
638 |
-
* Set the application key
|
639 |
-
*
|
640 |
-
* @return void
|
641 |
-
* @param string $key The application key to use.
|
642 |
-
*/
|
643 |
-
private function setApplicationKey($key)
|
644 |
-
{
|
645 |
-
$this->applicationKey = (string) $key;
|
646 |
-
}
|
647 |
-
|
648 |
-
|
649 |
-
/**
|
650 |
-
* Set the application secret
|
651 |
-
*
|
652 |
-
* @return void
|
653 |
-
* @param string $secret The application secret to use.
|
654 |
-
*/
|
655 |
-
private function setApplicationSecret($secret)
|
656 |
-
{
|
657 |
-
$this->applicationSecret = (string) $secret;
|
658 |
-
}
|
659 |
-
|
660 |
-
|
661 |
-
/**
|
662 |
-
* Set the oAuth-token
|
663 |
-
*
|
664 |
-
* @return void
|
665 |
-
* @param string $token The token to use.
|
666 |
-
*/
|
667 |
-
public function setOAuthToken($token)
|
668 |
-
{
|
669 |
-
$this->oAuthToken = (string) $token;
|
670 |
-
}
|
671 |
-
|
672 |
-
|
673 |
-
/**
|
674 |
-
* Set the oAuth-secret
|
675 |
-
*
|
676 |
-
* @return void
|
677 |
-
* @param string $secret The secret to use.
|
678 |
-
*/
|
679 |
-
public function setOAuthTokenSecret($secret)
|
680 |
-
{
|
681 |
-
$this->oAuthTokenSecret = (string) $secret;
|
682 |
-
}
|
683 |
-
|
684 |
-
|
685 |
-
/**
|
686 |
-
* Set the timeout
|
687 |
-
*
|
688 |
-
* @return void
|
689 |
-
* @param int $seconds The timeout in seconds
|
690 |
-
*/
|
691 |
-
public function setTimeOut($seconds)
|
692 |
-
{
|
693 |
-
$this->timeOut = (int) $seconds;
|
694 |
-
}
|
695 |
-
|
696 |
-
|
697 |
-
/**
|
698 |
-
* Get the useragent that will be used. Our version will be prepended to yours.
|
699 |
-
* It will look like: "PHP Dropbox/<version> <your-user-agent>"
|
700 |
-
*
|
701 |
-
* @return void
|
702 |
-
* @param string $userAgent Your user-agent, it should look like <app-name>/<app-version>
|
703 |
-
*/
|
704 |
-
public function setUserAgent($userAgent)
|
705 |
-
{
|
706 |
-
$this->userAgent = (string) $userAgent;
|
707 |
-
}
|
708 |
-
|
709 |
-
|
710 |
-
/**
|
711 |
-
* Build the signature for the data
|
712 |
-
*
|
713 |
-
* @return string
|
714 |
-
* @param string $key The key to use for signing.
|
715 |
-
* @param string $data The data that has to be signed.
|
716 |
-
*/
|
717 |
-
private function hmacsha1($key, $data)
|
718 |
-
{
|
719 |
-
return base64_encode(hash_hmac('SHA1', $data, $key, true));
|
720 |
-
}
|
721 |
-
|
722 |
-
|
723 |
-
/**
|
724 |
-
* URL-encode method for internatl use
|
725 |
-
*
|
726 |
-
* @return string
|
727 |
-
* @param mixed $value The value to encode.
|
728 |
-
*/
|
729 |
-
private static function urlencode_rfc3986($value)
|
730 |
-
{
|
731 |
-
if(is_array($value)) return array_map(array('Dropbox', 'urlencode_rfc3986'), $value);
|
732 |
-
else
|
733 |
-
{
|
734 |
-
$search = array('+', ' ', '%7E', '%');
|
735 |
-
$replace = array('%20', '%20', '~', '%25');
|
736 |
-
|
737 |
-
return str_replace($search, $replace, rawurlencode($value));
|
738 |
-
}
|
739 |
-
}
|
740 |
-
|
741 |
-
|
742 |
-
// oauth resources
|
743 |
-
/**
|
744 |
-
* Call for obtaining an OAuth request token.
|
745 |
-
* Returns a request token and the corresponding request token secret. This token and secret cannot be used to sign requests for the /metadata and /file content API calls.
|
746 |
-
* Their only purpose is for signing a request to oauth/access_token once the user has gone through the application authorization steps provided by oauth/authorize.
|
747 |
-
*
|
748 |
-
* @return array
|
749 |
-
*/
|
750 |
-
public function oAuthRequestToken()
|
751 |
-
{
|
752 |
-
// make the call
|
753 |
-
$response = $this->doOAuthCall('0/oauth/request_token', null, 'POST', false);
|
754 |
-
|
755 |
-
// process response
|
756 |
-
$response = (array) explode('&', $response);
|
757 |
-
$return = array();
|
758 |
-
|
759 |
-
// loop chunks
|
760 |
-
foreach($response as $chunk)
|
761 |
-
{
|
762 |
-
// split again
|
763 |
-
$chunks = explode('=', $chunk, 2);
|
764 |
-
|
765 |
-
// store return
|
766 |
-
if(count($chunks) == 2) $return[$chunks[0]] = $chunks[1];
|
767 |
-
}
|
768 |
-
|
769 |
-
// return
|
770 |
-
return $return;
|
771 |
-
}
|
772 |
-
|
773 |
-
|
774 |
-
/**
|
775 |
-
* Redirect the user to the oauth/authorize location so that Dropbox can authenticate the user and ask whether or not the user wants to authorize the application to access
|
776 |
-
* file metadata and content on its behalf. oauth/authorize is not an API call per se, because it does not have a return value, but rather directs the user to a page on
|
777 |
-
* api.dropbox.com where they are provided means to log in to Dropbox and grant authority to the application requesting it.
|
778 |
-
* The page served by oauth/authorize should be presented to the user through their web browser.
|
779 |
-
* Please note, without directing the user to a Dropbox-provided page via oauth/authorize, it is impossible for your application to use the request token it received
|
780 |
-
* via oauth/request_token to obtain an access token from oauth/access_token.
|
781 |
-
*
|
782 |
-
* @return void
|
783 |
-
* @param string $oauthToken The request token of the application requesting authority from a user.
|
784 |
-
* @param string[optional] $oauthCallback After the user authorizes an application, the user is redirected to the application-served URL provided by this parameter.
|
785 |
-
*/
|
786 |
-
public function oAuthAuthorize($oauthToken, $oauthCallback = null)
|
787 |
-
{
|
788 |
-
// build parameters
|
789 |
-
$parameters = array();
|
790 |
-
$parameters['oauth_token'] = (string) $oauthToken;
|
791 |
-
if($oauthCallback !== null) $parameters['oauth_callback'] = (string) $oauthCallback;
|
792 |
-
|
793 |
-
// build url
|
794 |
-
$url = self::API_URL .'/0/oauth/authorize?'. http_build_query($parameters);
|
795 |
-
|
796 |
-
// redirect
|
797 |
-
header('Location: '. $url);
|
798 |
-
exit;
|
799 |
-
}
|
800 |
-
|
801 |
-
|
802 |
-
/**
|
803 |
-
* This call returns a access token and the corresponding access token secret.
|
804 |
-
* Upon return, the authorization process is now complete and the access token and corresponding secret are used to sign requests for the metadata and file content API calls.
|
805 |
-
*
|
806 |
-
* @return array
|
807 |
-
* @param string $oauthToken The token returned after authorizing
|
808 |
-
*/
|
809 |
-
public function oAuthAccessToken($oauthToken)
|
810 |
-
{
|
811 |
-
// build parameters
|
812 |
-
$parameters = array();
|
813 |
-
$parameters['oauth_token'] = (string) $oauthToken;
|
814 |
-
|
815 |
-
// make the call
|
816 |
-
$response = $this->doOAuthCall('0/oauth/access_token', $parameters, 'POST', false);
|
817 |
-
|
818 |
-
// process response
|
819 |
-
$response = (array) explode('&', $response);
|
820 |
-
$return = array();
|
821 |
-
|
822 |
-
// loop chunks
|
823 |
-
foreach($response as $chunk)
|
824 |
-
{
|
825 |
-
// split again
|
826 |
-
$chunks = explode('=', $chunk, 2);
|
827 |
-
|
828 |
-
// store return
|
829 |
-
if(count($chunks) == 2) $return[$chunks[0]] = $chunks[1];
|
830 |
-
}
|
831 |
-
|
832 |
-
// return
|
833 |
-
return $return;
|
834 |
-
}
|
835 |
-
|
836 |
-
|
837 |
-
// token resources
|
838 |
-
/**
|
839 |
-
* The token call provides a consumer/secret key pair you can use to consistently access the user's account.
|
840 |
-
* This is the preferred method of authentication over storing the username and password.
|
841 |
-
* Use the key pair as a signature with every subsequent call.
|
842 |
-
* The request must be signed using the application's developer and secret key token. Request or access tokens are necessary.
|
843 |
-
*
|
844 |
-
* Warning: DO NOT STORE THE USER'S PASSWORD! The way this call works is you call it once with the user's email and password and then
|
845 |
-
* keep the token around for later. You do NOT (I repeat NOT) call this before everything you do or on each program startup.
|
846 |
-
* We watch for this and will shut down your application with little notice if we catch you.
|
847 |
-
* In fact, the Objective-C code does this for you so you can't get it wrong.
|
848 |
-
*
|
849 |
-
* @return array Upon successful verification of the user's credentials, returns an array representation of the access token and secret.
|
850 |
-
* @param string $email The email account of the user.
|
851 |
-
* @param string $password The password of the user.
|
852 |
-
*/
|
853 |
-
public function token($email, $password)
|
854 |
-
{
|
855 |
-
// build parameters
|
856 |
-
$parameters = array();
|
857 |
-
$parameters['email'] = (string) $email;
|
858 |
-
$parameters['password'] = (string) $password;
|
859 |
-
|
860 |
-
// make the call
|
861 |
-
$response = (array) $this->doOAuthCall('0/token', $parameters);
|
862 |
-
|
863 |
-
// validate and set
|
864 |
-
if(isset($response['token'])) $this->setOAuthToken($response['token']);
|
865 |
-
if(isset($response['secret'])) $this->setOAuthTokenSecret($response['secret']);
|
866 |
-
|
867 |
-
// return
|
868 |
-
return $response;
|
869 |
-
}
|
870 |
-
|
871 |
-
|
872 |
-
// account resources
|
873 |
-
/**
|
874 |
-
* Given a set of account information, the account call allows an application to create a new Dropbox user account.
|
875 |
-
* This is useful for situations where the trusted third party application is possibly the user's first interaction with Dropbox.
|
876 |
-
*
|
877 |
-
* @return bool
|
878 |
-
* @param string $email The email account of the user.
|
879 |
-
* @param string $password The password for the user.
|
880 |
-
* @param string $firstName The user's first name.
|
881 |
-
* @param string $lastName The user's last name.
|
882 |
-
*/
|
883 |
-
public function account($email, $password, $firstName, $lastName)
|
884 |
-
{
|
885 |
-
// build parameters
|
886 |
-
$parameters['email'] = (string) $email;
|
887 |
-
$parameters['first_name'] = (string) $firstName;
|
888 |
-
$parameters['last_name'] = (string) $lastName;
|
889 |
-
$parameters['password'] = (string) $password;
|
890 |
-
|
891 |
-
return (bool) ($this->doCall('0/account', $parameters, 'POST', null, false) == 'OK');
|
892 |
-
}
|
893 |
-
|
894 |
-
|
895 |
-
/**
|
896 |
-
* Get the user account information.
|
897 |
-
*
|
898 |
-
* @return array
|
899 |
-
*/
|
900 |
-
public function accountInfo()
|
901 |
-
{
|
902 |
-
// make the call
|
903 |
-
return (array) $this->doCall('0/account/info');
|
904 |
-
}
|
905 |
-
|
906 |
-
|
907 |
-
// files & metadata
|
908 |
-
/**
|
909 |
-
* Retrieves file contents relative to the user's Dropbox root or the application's directory within the user's Dropbox.
|
910 |
-
*
|
911 |
-
* @return string
|
912 |
-
* @param string $path Path of the directory wherin the file is located.
|
913 |
-
* @param bool[optional] $sandbox Sandbox mode?
|
914 |
-
*/
|
915 |
-
public function filesGet($path, $sandbox = false)
|
916 |
-
{
|
917 |
-
// build url
|
918 |
-
$url = '0/files/';
|
919 |
-
$url .= ($sandbox) ? 'sandbox/' : 'dropbox/';
|
920 |
-
$url .= trim((string) $path, '/');
|
921 |
-
|
922 |
-
// make the call
|
923 |
-
return $this->doCall($url, null, 'GET', null, false, true);
|
924 |
-
}
|
925 |
-
|
926 |
-
|
927 |
-
/**
|
928 |
-
* Uploads file contents relative to the user's Dropbox root or the application's directory within the user's Dropbox.
|
929 |
-
*
|
930 |
-
* @return bool
|
931 |
-
* @param string $path Path of the directory wherin the file should be uploaded.
|
932 |
-
* @param string $file Path to the local file.
|
933 |
-
* @param bool[optional] $sandbox Sandbox mode?
|
934 |
-
*/
|
935 |
-
public function filesPost($path, $localFile, $sandbox = false)
|
936 |
-
{
|
937 |
-
// build url
|
938 |
-
$url = '0/files/';
|
939 |
-
$url .= ($sandbox) ? 'sandbox/' : 'dropbox/';
|
940 |
-
$url .= trim((string) $path, '/');
|
941 |
-
|
942 |
-
// make the call
|
943 |
-
return $this->doCall($url, null, 'POST', $localFile, true, true);
|
944 |
-
}
|
945 |
-
|
946 |
-
|
947 |
-
/**
|
948 |
-
* Returns metadata for the file or directory at the given <path> location relative to the user's Dropbox or
|
949 |
-
* the user's application sandbox. If <path> represents a directory and the list parameter is true, the metadata will
|
950 |
-
* also include a listing of metadata for the directory's contents.
|
951 |
-
*
|
952 |
-
* @return array
|
953 |
-
* @param int[optional] $fileLimit When listing a directory, the service will not report listings containing more than $fileLimit files.
|
954 |
-
* @param bool[optional] $hash Listing return values include a hash representing the state of the directory's contents.
|
955 |
-
* @param bool[optional] $list If true, this call returns a list of metadata representations for the contents of the directory. If false, this call returns the metadata for the directory itself.
|
956 |
-
* @param bool[optional] $sandbox Sandbox mode?
|
957 |
-
*/
|
958 |
-
public function metadata($path = '', $fileLimit = 10000, $hash = false, $list = true, $sandbox = false)
|
959 |
-
{
|
960 |
-
// build url
|
961 |
-
$url = '0/metadata/';
|
962 |
-
$url .= ($sandbox) ? 'sandbox/' : 'dropbox/';
|
963 |
-
$url .= trim((string) $path, '/');
|
964 |
-
|
965 |
-
// build parameters
|
966 |
-
$parameters = null;
|
967 |
-
$parameters['file_limit'] = (int) $fileLimit;
|
968 |
-
if((bool) $hash) $parameters['hash'] = '';
|
969 |
-
$parameters['list'] = ($list) ? 'true': 'false';
|
970 |
-
|
971 |
-
// make the call
|
972 |
-
return (array) $this->doCall($url, $parameters);
|
973 |
-
}
|
974 |
-
|
975 |
-
|
976 |
-
/**
|
977 |
-
* Get a minimized thumbnail for a photo.
|
978 |
-
*
|
979 |
-
* @return string Will return a base64_encode string with the JPEG-data
|
980 |
-
* @param string $path The path to the photo.
|
981 |
-
* @param string[optional] $size The size, possible values are: 'small' (32x32), 'medium' (64x64), 'large' (128x128)
|
982 |
-
*/
|
983 |
-
public function thumbnails($path, $size = 'small')
|
984 |
-
{
|
985 |
-
// build url
|
986 |
-
$url = '0/thumbnails/dropbox/';
|
987 |
-
$url .= trim((string) $path, '/');
|
988 |
-
|
989 |
-
// build parameters
|
990 |
-
$parameters['size'] = (string) $size;
|
991 |
-
|
992 |
-
// make the call
|
993 |
-
return $this->doCall($url, $parameters, 'GET', null, false, true);
|
994 |
-
}
|
995 |
-
|
996 |
-
|
997 |
-
// file operations
|
998 |
-
/**
|
999 |
-
* Copy a file or folder to a new location.
|
1000 |
-
*
|
1001 |
-
* @return array
|
1002 |
-
* @param string $fromPath fromPath specifies either a file or folder to be copied to the location specified by toPath. This path is interpreted relative to the location specified by root.
|
1003 |
-
* @param string $toPath toPath specifies the destination path including the new name for file or folder. This path is interpreted relative to the location specified by root.
|
1004 |
-
* @param bool[optional] $sandbox Sandbox mode?
|
1005 |
-
*/
|
1006 |
-
public function fileopsCopy($fromPath, $toPath, $sandbox = false)
|
1007 |
-
{
|
1008 |
-
// build url
|
1009 |
-
$url = '0/fileops/copy';
|
1010 |
-
|
1011 |
-
// build parameters
|
1012 |
-
$parameters['from_path'] = (string) $fromPath;
|
1013 |
-
$parameters['to_path'] = (string) $toPath;
|
1014 |
-
$parameters['root'] = ($sandbox) ? 'sandbox' : 'dropbox';
|
1015 |
-
|
1016 |
-
// make the call
|
1017 |
-
return $this->doCall($url, $parameters, 'POST');
|
1018 |
-
}
|
1019 |
-
|
1020 |
-
|
1021 |
-
/**
|
1022 |
-
* Create a folder relative to the user's Dropbox root or the user's application sandbox folder.
|
1023 |
-
*
|
1024 |
-
* @return array
|
1025 |
-
* @param string $path The path to the new folder to create, relative to root.
|
1026 |
-
* @param bool[optional] $sandbox Sandbox mode?
|
1027 |
-
*/
|
1028 |
-
public function fileopsCreateFolder($path, $sandbox = false)
|
1029 |
-
{
|
1030 |
-
// build url
|
1031 |
-
$url = '0/fileops/create_folder';
|
1032 |
-
|
1033 |
-
// build parameters
|
1034 |
-
$parameters['path'] = trim((string) $path, '/');
|
1035 |
-
$parameters['root'] = ($sandbox) ? 'sandbox' : 'dropbox';
|
1036 |
-
|
1037 |
-
// make the call
|
1038 |
-
return $this->doCall($url, $parameters, 'POST');
|
1039 |
-
}
|
1040 |
-
|
1041 |
-
|
1042 |
-
/**
|
1043 |
-
* Deletes a file or folder.
|
1044 |
-
*
|
1045 |
-
* @return array
|
1046 |
-
* @param string $path path specifies either a file or folder to be deleted. This path is interpreted relative to the location specified by root.
|
1047 |
-
* @param bool[optional] $sandbox Sandbox mode?
|
1048 |
-
*/
|
1049 |
-
public function fileopsDelete($path, $sandbox = false)
|
1050 |
-
{
|
1051 |
-
// build url
|
1052 |
-
$url = '0/fileops/delete';
|
1053 |
-
|
1054 |
-
// build parameters
|
1055 |
-
$parameters['path'] = trim((string) $path, '/');
|
1056 |
-
$parameters['root'] = ($sandbox) ? 'sandbox' : 'dropbox';
|
1057 |
-
|
1058 |
-
// make the call
|
1059 |
-
return $this->doCall($url, $parameters, 'POST');
|
1060 |
-
}
|
1061 |
-
|
1062 |
-
|
1063 |
-
/**
|
1064 |
-
* Move a file or folder to a new location.
|
1065 |
-
*
|
1066 |
-
* @return array
|
1067 |
-
* @param string $fromPath fromPath specifies either a file or folder to be copied to the location specified by toPath. This path is interpreted relative to the location specified by root.
|
1068 |
-
* @param string $toPath toPath specifies the destination path including the new name for file or folder. This path is interpreted relative to the location specified by root.
|
1069 |
-
* @param bool[optional] $sandbox Sandbox mode?
|
1070 |
-
*/
|
1071 |
-
public function fileopsMove($fromPath, $toPath, $sandbox = false)
|
1072 |
-
{
|
1073 |
-
// build url
|
1074 |
-
$url = '0/fileops/move';
|
1075 |
-
|
1076 |
-
// build parameters
|
1077 |
-
$parameters['from_path'] = (string) $fromPath;
|
1078 |
-
$parameters['to_path'] = (string) $toPath;
|
1079 |
-
$parameters['root'] = ($sandbox) ? 'sandbox' : 'dropbox';
|
1080 |
-
|
1081 |
-
// make the call
|
1082 |
-
return $this->doCall($url, $parameters, 'POST');
|
1083 |
-
}
|
1084 |
-
}
|
1085 |
-
|
1086 |
-
|
1087 |
-
/**
|
1088 |
-
* Dropbox Exception class
|
1089 |
-
*
|
1090 |
-
* @author Tijs Verkoyen <php-dropbox@verkoyen.eu>
|
1091 |
-
*/
|
1092 |
-
class DropboxException extends Exception
|
1093 |
-
{
|
1094 |
-
}
|
1095 |
-
|
1096 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/libs/dropbox/dropbox.php
ADDED
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?PHP
|
2 |
+
require_once(dirname(__FILE__).'/oauth.php');
|
3 |
+
|
4 |
+
class Dropbox {
|
5 |
+
const API_URL = 'https://api.dropbox.com/';
|
6 |
+
const API_CONTENT_URL = 'https://api-content.dropbox.com/';
|
7 |
+
const API_VERSION_URL = '0/';
|
8 |
+
|
9 |
+
protected $root = 'dropbox';
|
10 |
+
protected $OAuthToken;
|
11 |
+
protected $OAuthConsumer;
|
12 |
+
protected $OAuthSignatureMethod;
|
13 |
+
|
14 |
+
public function __construct($applicationKey, $applicationSecret) {
|
15 |
+
$this->OAuthConsumer = new OAuthConsumer($applicationKey, $applicationSecret);
|
16 |
+
$this->OAuthSignatureMethod = new OAuthSignatureMethod_HMAC_SHA1;
|
17 |
+
}
|
18 |
+
|
19 |
+
public function setOAuthTokens($token,$secret) {
|
20 |
+
$this->oAuthToken = $token;
|
21 |
+
$this->oAuthTokenSecret = $secret;
|
22 |
+
$this->OAuthToken = new OAuthToken($this->oAuthToken, $this->oAuthTokenSecret);
|
23 |
+
}
|
24 |
+
|
25 |
+
public function setDropbox() {
|
26 |
+
$this->root = 'dropbox';
|
27 |
+
}
|
28 |
+
|
29 |
+
public function setSandbox() {
|
30 |
+
$this->root = 'sandbox';
|
31 |
+
}
|
32 |
+
|
33 |
+
public function accountInfo(){
|
34 |
+
$url = self::API_URL.self::API_VERSION_URL.'account/info';
|
35 |
+
return $this->request($url);
|
36 |
+
}
|
37 |
+
|
38 |
+
public function upload($file, $path = ''){
|
39 |
+
$file = preg_replace("/\\\\/", "/",$file);
|
40 |
+
if (!is_readable($file)){
|
41 |
+
throw new DropboxException("Error: File \"$file\" is not readable or doesn't exist.");
|
42 |
+
}
|
43 |
+
if (!filesize($file)>314572800){
|
44 |
+
throw new DropboxException("Error: File \"$file\" is to big max. 300 MB.");
|
45 |
+
}
|
46 |
+
$url = self::API_CONTENT_URL.self::API_VERSION_URL. 'files/' . $this->root . '/' . trim($path, '/');
|
47 |
+
return $this->request($url, array('file' => $file), 'POST', $file);
|
48 |
+
}
|
49 |
+
|
50 |
+
public function download($path){
|
51 |
+
$url = self::API_CONTENT_URL.self::API_VERSION_URL. 'files/' . $this->root . '/' . trim($path, '/');
|
52 |
+
return $this->request($url);
|
53 |
+
}
|
54 |
+
|
55 |
+
public function metadata($path = '', $listContents = true, $fileLimit = 10000){
|
56 |
+
$url = self::API_URL.self::API_VERSION_URL. 'metadata/' . $this->root . '/' . ltrim($path, '/');
|
57 |
+
return $this->request($url, array('list' => ($listContents)? 'true' : 'false', 'file_limit' => $fileLimit));
|
58 |
+
}
|
59 |
+
|
60 |
+
public function createAccount($firstName, $lastName, $email, $password){
|
61 |
+
$url = self::API_URL.self::API_VERSION_URL.'account';
|
62 |
+
return $this->request($url, array('first_name' => $firstName, 'last_name' => $lastName, 'email' => $email, 'password' => $password), 'GET', true);
|
63 |
+
}
|
64 |
+
|
65 |
+
public function fileopsDelete($path){
|
66 |
+
$url = self::API_URL.self::API_VERSION_URL.'fileops/delete';
|
67 |
+
return $this->request($url, array('path' => $path, 'root' => $this->root));
|
68 |
+
}
|
69 |
+
|
70 |
+
public function fileopsMove($from, $to){
|
71 |
+
$url = self::API_URL.self::API_VERSION_URL.'fileops/move';
|
72 |
+
return $this->request($url, array('from_path' => $from, 'to_path' => $to, 'root' => $this->root));
|
73 |
+
}
|
74 |
+
|
75 |
+
public function fileopsCreateFolder($path){
|
76 |
+
$url = self::API_URL.self::API_VERSION_URL.'fileops/create_folder';
|
77 |
+
return $this->request($url, array('path' => $path, 'root' => $this->root));
|
78 |
+
}
|
79 |
+
|
80 |
+
public function fileopsCopy($from, $to){
|
81 |
+
$url = self::API_URL.self::API_VERSION_URL.'fileops/copy';
|
82 |
+
return $this->request($url, array('from_path' => $from, 'to_path' => $to, 'root' => $this->root));
|
83 |
+
}
|
84 |
+
|
85 |
+
public function thumbnail($path, $size = 'small', $format = 'JPEG', $raw = false){
|
86 |
+
$url = self::API_CONTENT_URL.self::API_VERSION_URL. 'dropbox/' . ltrim($path, '/');
|
87 |
+
$result = $this->request($url, array('size' => $size, 'format' => $format));
|
88 |
+
if ($raw){
|
89 |
+
return $result;
|
90 |
+
}
|
91 |
+
else{
|
92 |
+
return 'data:image/' . $format . ';base64,' . base64_encode( (isset($result['body'])) ? $result['body'] : (!is_array($result)) ? $result : '' );
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
public function oAuthRequestToken() {
|
97 |
+
$req_req = OAuthRequest::from_consumer_and_token($this->OAuthConsumer, NULL, "GET", self::API_URL.self::API_VERSION_URL.'oauth/request_token');
|
98 |
+
$req_req->sign_request($this->OAuthSignatureMethod, $this->OAuthConsumer, NULL);
|
99 |
+
$ch = curl_init();
|
100 |
+
curl_setopt($ch, CURLOPT_URL, $req_req);
|
101 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
102 |
+
$content = curl_exec($ch);
|
103 |
+
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
104 |
+
if ($status>=200 and $status<300) {
|
105 |
+
$content = (array) explode('&', $content);
|
106 |
+
foreach($content as $chunk) {
|
107 |
+
$chunks = explode('=', $chunk, 2);
|
108 |
+
if(count($chunks) == 2) $return[$chunks[0]] = $chunks[1];
|
109 |
+
}
|
110 |
+
return $return;
|
111 |
+
} else {
|
112 |
+
$output = json_decode($content, true);
|
113 |
+
if(isset($output['error']) && is_string($output['error'])) $message = $output['error'];
|
114 |
+
elseif(isset($output['error']['hash']) && $output['error']['hash'] != '') $message = (string) $output['error']['hash'];
|
115 |
+
else $message = '('.$status.') Invalid response.';
|
116 |
+
throw new DropboxException($message);
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
public function oAuthAuthorize($oAuthToken,$callback_url) {
|
121 |
+
$auth_url = self::API_URL.self::API_VERSION_URL."oauth/authorize?oauth_token=".$oAuthToken."&oauth_callback=".urlencode($callback_url);
|
122 |
+
header('Location: '. $auth_url);
|
123 |
+
exit;
|
124 |
+
}
|
125 |
+
|
126 |
+
public function oAuthAccessToken($oauth_token, $oauth_token_secret) {
|
127 |
+
$oAuthToken = new OAuthConsumer($oauth_token, $oauth_token_secret);
|
128 |
+
$acc_req = OAuthRequest::from_consumer_and_token($this->OAuthConsumer, $oAuthToken, "GET", self::API_URL.self::API_VERSION_URL.'oauth/access_token');
|
129 |
+
$acc_req->sign_request($this->OAuthSignatureMethod, $this->OAuthConsumer, $oAuthToken);
|
130 |
+
$ch = curl_init();
|
131 |
+
curl_setopt($ch, CURLOPT_URL, $acc_req);
|
132 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
133 |
+
$content = curl_exec($ch);
|
134 |
+
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
135 |
+
if ($status>=200 and $status<300) {
|
136 |
+
$content = (array) explode('&', $content);
|
137 |
+
$return = array();
|
138 |
+
foreach($content as $chunk) {
|
139 |
+
$chunks = explode('=', $chunk, 2);
|
140 |
+
if(count($chunks) == 2) $return[$chunks[0]] = $chunks[1];
|
141 |
+
}
|
142 |
+
$this->setOAuthTokens($return['oauth_token'],$return['oauth_token_secret']);
|
143 |
+
return $return;
|
144 |
+
} else {
|
145 |
+
$output = json_decode($content, true);
|
146 |
+
if(isset($output['error']) && is_string($output['error'])) $message = $output['error'];
|
147 |
+
elseif(isset($output['error']['hash']) && $output['error']['hash'] != '') $message = (string) $output['error']['hash'];
|
148 |
+
else $message = '('.$status.') Invalid response.';
|
149 |
+
throw new DropboxException($message);
|
150 |
+
}
|
151 |
+
}
|
152 |
+
|
153 |
+
protected function request($url, $args = null, $method = 'GET', $file = null){
|
154 |
+
$args = (is_array($args)) ? $args : array();
|
155 |
+
|
156 |
+
/* Sign Request*/
|
157 |
+
$Request = OAuthRequest::from_consumer_and_token($this->OAuthConsumer, $this->OAuthToken, $method, $url, $args);
|
158 |
+
$Request->sign_request($this->OAuthSignatureMethod, $this->OAuthConsumer, $this->OAuthToken);
|
159 |
+
|
160 |
+
/* Build cURL Request */
|
161 |
+
$ch = curl_init();
|
162 |
+
curl_setopt($ch, CURLOPT_URL, $Request->to_url());
|
163 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
164 |
+
if ($this->noSSLCheck){
|
165 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
166 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
167 |
+
}
|
168 |
+
|
169 |
+
/* file upload */
|
170 |
+
if ($file !== null){
|
171 |
+
$data = array('file' => "@$file");
|
172 |
+
curl_setopt($ch, CURLOPT_POST, true);
|
173 |
+
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
174 |
+
}
|
175 |
+
|
176 |
+
$content = curl_exec($ch);
|
177 |
+
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
178 |
+
|
179 |
+
curl_close($ch);
|
180 |
+
$output = json_decode($content, true);
|
181 |
+
|
182 |
+
|
183 |
+
if (isset($output['error']) or $status>=300 or $status<200) {
|
184 |
+
if(isset($output['error']) && is_string($output['error'])) $message = $output['error'];
|
185 |
+
elseif(isset($output['error']['hash']) && $output['error']['hash'] != '') $message = (string) $output['error']['hash'];
|
186 |
+
else $message = '('.$status.') Invalid response.';
|
187 |
+
throw new DropboxException($message);
|
188 |
+
} else {
|
189 |
+
if (!is_array($output))
|
190 |
+
return $content;
|
191 |
+
else
|
192 |
+
return $output;
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
}
|
197 |
+
|
198 |
+
class DropboxException extends Exception {
|
199 |
+
}
|
200 |
+
?>
|
app/libs/dropbox/oauth.php
ADDED
@@ -0,0 +1,879 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// vim: foldmethod=marker
|
3 |
+
|
4 |
+
/* Generic exception class
|
5 |
+
*/
|
6 |
+
class OAuthException extends Exception {
|
7 |
+
// pass
|
8 |
+
}
|
9 |
+
|
10 |
+
class OAuthConsumer {
|
11 |
+
public $key;
|
12 |
+
public $secret;
|
13 |
+
|
14 |
+
function __construct($key, $secret, $callback_url=NULL) {
|
15 |
+
$this->key = $key;
|
16 |
+
$this->secret = $secret;
|
17 |
+
$this->callback_url = $callback_url;
|
18 |
+
}
|
19 |
+
|
20 |
+
function __toString() {
|
21 |
+
return "OAuthConsumer[key=$this->key,secret=$this->secret]";
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
class OAuthToken {
|
26 |
+
// access tokens and request tokens
|
27 |
+
public $key;
|
28 |
+
public $secret;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* key = the token
|
32 |
+
* secret = the token secret
|
33 |
+
*/
|
34 |
+
function __construct($key, $secret) {
|
35 |
+
$this->key = $key;
|
36 |
+
$this->secret = $secret;
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* generates the basic string serialization of a token that a server
|
41 |
+
* would respond to request_token and access_token calls with
|
42 |
+
*/
|
43 |
+
function to_string() {
|
44 |
+
return "oauth_token=" .
|
45 |
+
OAuthUtil::urlencode_rfc3986($this->key) .
|
46 |
+
"&oauth_token_secret=" .
|
47 |
+
OAuthUtil::urlencode_rfc3986($this->secret);
|
48 |
+
}
|
49 |
+
|
50 |
+
function __toString() {
|
51 |
+
return $this->to_string();
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* A class for implementing a Signature Method
|
57 |
+
* See section 9 ("Signing Requests") in the spec
|
58 |
+
*/
|
59 |
+
abstract class OAuthSignatureMethod {
|
60 |
+
/**
|
61 |
+
* Needs to return the name of the Signature Method (ie HMAC-SHA1)
|
62 |
+
* @return string
|
63 |
+
*/
|
64 |
+
abstract public function get_name();
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Build up the signature
|
68 |
+
* NOTE: The output of this function MUST NOT be urlencoded.
|
69 |
+
* the encoding is handled in OAuthRequest when the final
|
70 |
+
* request is serialized
|
71 |
+
* @param OAuthRequest $request
|
72 |
+
* @param OAuthConsumer $consumer
|
73 |
+
* @param OAuthToken $token
|
74 |
+
* @return string
|
75 |
+
*/
|
76 |
+
abstract public function build_signature($request, $consumer, $token);
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Verifies that a given signature is correct
|
80 |
+
* @param OAuthRequest $request
|
81 |
+
* @param OAuthConsumer $consumer
|
82 |
+
* @param OAuthToken $token
|
83 |
+
* @param string $signature
|
84 |
+
* @return bool
|
85 |
+
*/
|
86 |
+
public function check_signature($request, $consumer, $token, $signature) {
|
87 |
+
$built = $this->build_signature($request, $consumer, $token);
|
88 |
+
return $built == $signature;
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
|
94 |
+
* where the Signature Base String is the text and the key is the concatenated values (each first
|
95 |
+
* encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
|
96 |
+
* character (ASCII code 38) even if empty.
|
97 |
+
* - Chapter 9.2 ("HMAC-SHA1")
|
98 |
+
*/
|
99 |
+
class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
|
100 |
+
function get_name() {
|
101 |
+
return "HMAC-SHA1";
|
102 |
+
}
|
103 |
+
|
104 |
+
public function build_signature($request, $consumer, $token) {
|
105 |
+
$base_string = $request->get_signature_base_string();
|
106 |
+
$request->base_string = $base_string;
|
107 |
+
|
108 |
+
$key_parts = array(
|
109 |
+
$consumer->secret,
|
110 |
+
($token) ? $token->secret : ""
|
111 |
+
);
|
112 |
+
|
113 |
+
$key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
|
114 |
+
$key = implode('&', $key_parts);
|
115 |
+
|
116 |
+
return base64_encode(hash_hmac('sha1', $base_string, $key, true));
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* The PLAINTEXT method does not provide any security protection and SHOULD only be used
|
122 |
+
* over a secure channel such as HTTPS. It does not use the Signature Base String.
|
123 |
+
* - Chapter 9.4 ("PLAINTEXT")
|
124 |
+
*/
|
125 |
+
class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
|
126 |
+
public function get_name() {
|
127 |
+
return "PLAINTEXT";
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* oauth_signature is set to the concatenated encoded values of the Consumer Secret and
|
132 |
+
* Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
|
133 |
+
* empty. The result MUST be encoded again.
|
134 |
+
* - Chapter 9.4.1 ("Generating Signatures")
|
135 |
+
*
|
136 |
+
* Please note that the second encoding MUST NOT happen in the SignatureMethod, as
|
137 |
+
* OAuthRequest handles this!
|
138 |
+
*/
|
139 |
+
public function build_signature($request, $consumer, $token) {
|
140 |
+
$key_parts = array(
|
141 |
+
$consumer->secret,
|
142 |
+
($token) ? $token->secret : ""
|
143 |
+
);
|
144 |
+
|
145 |
+
$key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
|
146 |
+
$key = implode('&', $key_parts);
|
147 |
+
$request->base_string = $key;
|
148 |
+
|
149 |
+
return $key;
|
150 |
+
}
|
151 |
+
}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
|
155 |
+
* [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
|
156 |
+
* EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
|
157 |
+
* verified way to the Service Provider, in a manner which is beyond the scope of this
|
158 |
+
* specification.
|
159 |
+
* - Chapter 9.3 ("RSA-SHA1")
|
160 |
+
*/
|
161 |
+
abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
|
162 |
+
public function get_name() {
|
163 |
+
return "RSA-SHA1";
|
164 |
+
}
|
165 |
+
|
166 |
+
// Up to the SP to implement this lookup of keys. Possible ideas are:
|
167 |
+
// (1) do a lookup in a table of trusted certs keyed off of consumer
|
168 |
+
// (2) fetch via http using a url provided by the requester
|
169 |
+
// (3) some sort of specific discovery code based on request
|
170 |
+
//
|
171 |
+
// Either way should return a string representation of the certificate
|
172 |
+
protected abstract function fetch_public_cert(&$request);
|
173 |
+
|
174 |
+
// Up to the SP to implement this lookup of keys. Possible ideas are:
|
175 |
+
// (1) do a lookup in a table of trusted certs keyed off of consumer
|
176 |
+
//
|
177 |
+
// Either way should return a string representation of the certificate
|
178 |
+
protected abstract function fetch_private_cert(&$request);
|
179 |
+
|
180 |
+
public function build_signature($request, $consumer, $token) {
|
181 |
+
$base_string = $request->get_signature_base_string();
|
182 |
+
$request->base_string = $base_string;
|
183 |
+
|
184 |
+
// Fetch the private key cert based on the request
|
185 |
+
$cert = $this->fetch_private_cert($request);
|
186 |
+
|
187 |
+
// Pull the private key ID from the certificate
|
188 |
+
$privatekeyid = openssl_get_privatekey($cert);
|
189 |
+
|
190 |
+
// Sign using the key
|
191 |
+
$ok = openssl_sign($base_string, $signature, $privatekeyid);
|
192 |
+
|
193 |
+
// Release the key resource
|
194 |
+
openssl_free_key($privatekeyid);
|
195 |
+
|
196 |
+
return base64_encode($signature);
|
197 |
+
}
|
198 |
+
|
199 |
+
public function check_signature($request, $consumer, $token, $signature) {
|
200 |
+
$decoded_sig = base64_decode($signature);
|
201 |
+
|
202 |
+
$base_string = $request->get_signature_base_string();
|
203 |
+
|
204 |
+
// Fetch the public key cert based on the request
|
205 |
+
$cert = $this->fetch_public_cert($request);
|
206 |
+
|
207 |
+
// Pull the public key ID from the certificate
|
208 |
+
$publickeyid = openssl_get_publickey($cert);
|
209 |
+
|
210 |
+
// Check the computed signature against the one passed in the query
|
211 |
+
$ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
|
212 |
+
|
213 |
+
// Release the key resource
|
214 |
+
openssl_free_key($publickeyid);
|
215 |
+
|
216 |
+
return $ok == 1;
|
217 |
+
}
|
218 |
+
}
|
219 |
+
|
220 |
+
class OAuthRequest {
|
221 |
+
protected $parameters;
|
222 |
+
protected $http_method;
|
223 |
+
protected $http_url;
|
224 |
+
// for debug purposes
|
225 |
+
public $base_string;
|
226 |
+
public static $version = '1.0';
|
227 |
+
public static $POST_INPUT = 'php://input';
|
228 |
+
|
229 |
+
function __construct($http_method, $http_url, $parameters=NULL) {
|
230 |
+
$parameters = ($parameters) ? $parameters : array();
|
231 |
+
$parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
|
232 |
+
$this->parameters = $parameters;
|
233 |
+
$this->http_method = $http_method;
|
234 |
+
$this->http_url = $http_url;
|
235 |
+
}
|
236 |
+
|
237 |
+
|
238 |
+
/**
|
239 |
+
* attempt to build up a request from what was passed to the server
|
240 |
+
*/
|
241 |
+
public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
|
242 |
+
$scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
|
243 |
+
? 'http'
|
244 |
+
: 'https';
|
245 |
+
$http_url = ($http_url) ? $http_url : $scheme .
|
246 |
+
'://' . $_SERVER['HTTP_HOST'] .
|
247 |
+
':' .
|
248 |
+
$_SERVER['SERVER_PORT'] .
|
249 |
+
$_SERVER['REQUEST_URI'];
|
250 |
+
$http_method = ($http_method) ? $http_method : $_SERVER['REQUEST_METHOD'];
|
251 |
+
|
252 |
+
// We weren't handed any parameters, so let's find the ones relevant to
|
253 |
+
// this request.
|
254 |
+
// If you run XML-RPC or similar you should use this to provide your own
|
255 |
+
// parsed parameter-list
|
256 |
+
if (!$parameters) {
|
257 |
+
// Find request headers
|
258 |
+
$request_headers = OAuthUtil::get_headers();
|
259 |
+
|
260 |
+
// Parse the query-string to find GET parameters
|
261 |
+
$parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
|
262 |
+
|
263 |
+
// It's a POST request of the proper content-type, so parse POST
|
264 |
+
// parameters and add those overriding any duplicates from GET
|
265 |
+
if ($http_method == "POST"
|
266 |
+
&& isset($request_headers['Content-Type'])
|
267 |
+
&& strstr($request_headers['Content-Type'],
|
268 |
+
'application/x-www-form-urlencoded')
|
269 |
+
) {
|
270 |
+
$post_data = OAuthUtil::parse_parameters(
|
271 |
+
file_get_contents(self::$POST_INPUT)
|
272 |
+
);
|
273 |
+
$parameters = array_merge($parameters, $post_data);
|
274 |
+
}
|
275 |
+
|
276 |
+
// We have a Authorization-header with OAuth data. Parse the header
|
277 |
+
// and add those overriding any duplicates from GET or POST
|
278 |
+
if (isset($request_headers['Authorization']) && substr($request_headers['Authorization'], 0, 6) == 'OAuth ') {
|
279 |
+
$header_parameters = OAuthUtil::split_header(
|
280 |
+
$request_headers['Authorization']
|
281 |
+
);
|
282 |
+
$parameters = array_merge($parameters, $header_parameters);
|
283 |
+
}
|
284 |
+
|
285 |
+
}
|
286 |
+
|
287 |
+
return new OAuthRequest($http_method, $http_url, $parameters);
|
288 |
+
}
|
289 |
+
|
290 |
+
/**
|
291 |
+
* pretty much a helper function to set up the request
|
292 |
+
*/
|
293 |
+
public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
|
294 |
+
$parameters = ($parameters) ? $parameters : array();
|
295 |
+
$defaults = array("oauth_version" => OAuthRequest::$version,
|
296 |
+
"oauth_nonce" => OAuthRequest::generate_nonce(),
|
297 |
+
"oauth_timestamp" => OAuthRequest::generate_timestamp(),
|
298 |
+
"oauth_consumer_key" => $consumer->key);
|
299 |
+
if ($token)
|
300 |
+
$defaults['oauth_token'] = $token->key;
|
301 |
+
|
302 |
+
$parameters = array_merge($defaults, $parameters);
|
303 |
+
|
304 |
+
return new OAuthRequest($http_method, $http_url, $parameters);
|
305 |
+
}
|
306 |
+
|
307 |
+
public function set_parameter($name, $value, $allow_duplicates = true) {
|
308 |
+
if ($allow_duplicates && isset($this->parameters[$name])) {
|
309 |
+
// We have already added parameter(s) with this name, so add to the list
|
310 |
+
if (is_scalar($this->parameters[$name])) {
|
311 |
+
// This is the first duplicate, so transform scalar (string)
|
312 |
+
// into an array so we can add the duplicates
|
313 |
+
$this->parameters[$name] = array($this->parameters[$name]);
|
314 |
+
}
|
315 |
+
|
316 |
+
$this->parameters[$name][] = $value;
|
317 |
+
} else {
|
318 |
+
$this->parameters[$name] = $value;
|
319 |
+
}
|
320 |
+
}
|
321 |
+
|
322 |
+
public function get_parameter($name) {
|
323 |
+
return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
|
324 |
+
}
|
325 |
+
|
326 |
+
public function get_parameters() {
|
327 |
+
return $this->parameters;
|
328 |
+
}
|
329 |
+
|
330 |
+
public function unset_parameter($name) {
|
331 |
+
unset($this->parameters[$name]);
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* The request parameters, sorted and concatenated into a normalized string.
|
336 |
+
* @return string
|
337 |
+
*/
|
338 |
+
public function get_signable_parameters() {
|
339 |
+
// Grab all parameters
|
340 |
+
$params = $this->parameters;
|
341 |
+
|
342 |
+
// Remove oauth_signature if present
|
343 |
+
// Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
|
344 |
+
if (isset($params['oauth_signature'])) {
|
345 |
+
unset($params['oauth_signature']);
|
346 |
+
}
|
347 |
+
|
348 |
+
return OAuthUtil::build_http_query($params);
|
349 |
+
}
|
350 |
+
|
351 |
+
/**
|
352 |
+
* Returns the base string of this request
|
353 |
+
*
|
354 |
+
* The base string defined as the method, the url
|
355 |
+
* and the parameters (normalized), each urlencoded
|
356 |
+
* and the concated with &.
|
357 |
+
*/
|
358 |
+
public function get_signature_base_string() {
|
359 |
+
$parts = array(
|
360 |
+
$this->get_normalized_http_method(),
|
361 |
+
$this->get_normalized_http_url(),
|
362 |
+
$this->get_signable_parameters()
|
363 |
+
);
|
364 |
+
|
365 |
+
$parts = OAuthUtil::urlencode_rfc3986($parts);
|
366 |
+
|
367 |
+
return implode('&', $parts);
|
368 |
+
}
|
369 |
+
|
370 |
+
/**
|
371 |
+
* just uppercases the http method
|
372 |
+
*/
|
373 |
+
public function get_normalized_http_method() {
|
374 |
+
return strtoupper($this->http_method);
|
375 |
+
}
|
376 |
+
|
377 |
+
/**
|
378 |
+
* parses the url and rebuilds it to be
|
379 |
+
* scheme://host/path
|
380 |
+
*/
|
381 |
+
public function get_normalized_http_url() {
|
382 |
+
$parts = parse_url($this->http_url);
|
383 |
+
|
384 |
+
$scheme = (isset($parts['scheme'])) ? $parts['scheme'] : 'http';
|
385 |
+
$port = (isset($parts['port'])) ? $parts['port'] : (($scheme == 'https') ? '443' : '80');
|
386 |
+
$host = (isset($parts['host'])) ? $parts['host'] : '';
|
387 |
+
$path = (isset($parts['path'])) ? $parts['path'] : '';
|
388 |
+
|
389 |
+
if (($scheme == 'https' && $port != '443')
|
390 |
+
|| ($scheme == 'http' && $port != '80')) {
|
391 |
+
$host = "$host:$port";
|
392 |
+
}
|
393 |
+
return "$scheme://$host$path";
|
394 |
+
}
|
395 |
+
|
396 |
+
/**
|
397 |
+
* builds a url usable for a GET request
|
398 |
+
*/
|
399 |
+
public function to_url() {
|
400 |
+
$post_data = $this->to_postdata();
|
401 |
+
$out = $this->get_normalized_http_url();
|
402 |
+
if ($post_data) {
|
403 |
+
$out .= '?'.$post_data;
|
404 |
+
}
|
405 |
+
return $out;
|
406 |
+
}
|
407 |
+
|
408 |
+
/**
|
409 |
+
* builds the data one would send in a POST request
|
410 |
+
*/
|
411 |
+
public function to_postdata() {
|
412 |
+
return OAuthUtil::build_http_query($this->parameters);
|
413 |
+
}
|
414 |
+
|
415 |
+
/**
|
416 |
+
* builds the Authorization: header
|
417 |
+
*/
|
418 |
+
public function to_header($realm=null) {
|
419 |
+
$first = true;
|
420 |
+
if($realm) {
|
421 |
+
$out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
|
422 |
+
$first = false;
|
423 |
+
} else
|
424 |
+
$out = 'Authorization: OAuth';
|
425 |
+
|
426 |
+
$total = array();
|
427 |
+
foreach ($this->parameters as $k => $v) {
|
428 |
+
if (substr($k, 0, 5) != "oauth") continue;
|
429 |
+
if (is_array($v)) {
|
430 |
+
throw new OAuthException('Arrays not supported in headers');
|
431 |
+
}
|
432 |
+
$out .= ($first) ? ' ' : ',';
|
433 |
+
$out .= OAuthUtil::urlencode_rfc3986($k) .
|
434 |
+
'="' .
|
435 |
+
OAuthUtil::urlencode_rfc3986($v) .
|
436 |
+
'"';
|
437 |
+
$first = false;
|
438 |
+
}
|
439 |
+
return $out;
|
440 |
+
}
|
441 |
+
|
442 |
+
public function __toString() {
|
443 |
+
return $this->to_url();
|
444 |
+
}
|
445 |
+
|
446 |
+
|
447 |
+
public function sign_request($signature_method, $consumer, $token) {
|
448 |
+
$this->set_parameter(
|
449 |
+
"oauth_signature_method",
|
450 |
+
$signature_method->get_name(),
|
451 |
+
false
|
452 |
+
);
|
453 |
+
$signature = $this->build_signature($signature_method, $consumer, $token);
|
454 |
+
$this->set_parameter("oauth_signature", $signature, false);
|
455 |
+
}
|
456 |
+
|
457 |
+
public function build_signature($signature_method, $consumer, $token) {
|
458 |
+
$signature = $signature_method->build_signature($this, $consumer, $token);
|
459 |
+
return $signature;
|
460 |
+
}
|
461 |
+
|
462 |
+
/**
|
463 |
+
* util function: current timestamp
|
464 |
+
*/
|
465 |
+
private static function generate_timestamp() {
|
466 |
+
return time();
|
467 |
+
}
|
468 |
+
|
469 |
+
/**
|
470 |
+
* util function: current nonce
|
471 |
+
*/
|
472 |
+
private static function generate_nonce() {
|
473 |
+
$mt = microtime();
|
474 |
+
$rand = mt_rand();
|
475 |
+
|
476 |
+
return md5($mt . $rand); // md5s look nicer than numbers
|
477 |
+
}
|
478 |
+
}
|
479 |
+
|
480 |
+
class OAuthServer {
|
481 |
+
protected $timestamp_threshold = 300; // in seconds, five minutes
|
482 |
+
protected $version = '1.0'; // hi blaine
|
483 |
+
protected $signature_methods = array();
|
484 |
+
|
485 |
+
protected $data_store;
|
486 |
+
|
487 |
+
function __construct($data_store) {
|
488 |
+
$this->data_store = $data_store;
|
489 |
+
}
|
490 |
+
|
491 |
+
public function add_signature_method($signature_method) {
|
492 |
+
$this->signature_methods[$signature_method->get_name()] =
|
493 |
+
$signature_method;
|
494 |
+
}
|
495 |
+
|
496 |
+
// high level functions
|
497 |
+
|
498 |
+
/**
|
499 |
+
* process a request_token request
|
500 |
+
* returns the request token on success
|
501 |
+
*/
|
502 |
+
public function fetch_request_token(&$request) {
|
503 |
+
$this->get_version($request);
|
504 |
+
|
505 |
+
$consumer = $this->get_consumer($request);
|
506 |
+
|
507 |
+
// no token required for the initial token request
|
508 |
+
$token = NULL;
|
509 |
+
|
510 |
+
$this->check_signature($request, $consumer, $token);
|
511 |
+
|
512 |
+
// Rev A change
|
513 |
+
$callback = $request->get_parameter('oauth_callback');
|
514 |
+
$new_token = $this->data_store->new_request_token($consumer, $callback);
|
515 |
+
|
516 |
+
return $new_token;
|
517 |
+
}
|
518 |
+
|
519 |
+
/**
|
520 |
+
* process an access_token request
|
521 |
+
* returns the access token on success
|
522 |
+
*/
|
523 |
+
public function fetch_access_token(&$request) {
|
524 |
+
$this->get_version($request);
|
525 |
+
|
526 |
+
$consumer = $this->get_consumer($request);
|
527 |
+
|
528 |
+
// requires authorized request token
|
529 |
+
$token = $this->get_token($request, $consumer, "request");
|
530 |
+
|
531 |
+
$this->check_signature($request, $consumer, $token);
|
532 |
+
|
533 |
+
// Rev A change
|
534 |
+
$verifier = $request->get_parameter('oauth_verifier');
|
535 |
+
$new_token = $this->data_store->new_access_token($token, $consumer, $verifier);
|
536 |
+
|
537 |
+
return $new_token;
|
538 |
+
}
|
539 |
+
|
540 |
+
/**
|
541 |
+
* verify an api call, checks all the parameters
|
542 |
+
*/
|
543 |
+
public function verify_request(&$request) {
|
544 |
+
$this->get_version($request);
|
545 |
+
$consumer = $this->get_consumer($request);
|
546 |
+
$token = $this->get_token($request, $consumer, "access");
|
547 |
+
$this->check_signature($request, $consumer, $token);
|
548 |
+
return array($consumer, $token);
|
549 |
+
}
|
550 |
+
|
551 |
+
// Internals from here
|
552 |
+
/**
|
553 |
+
* version 1
|
554 |
+
*/
|
555 |
+
private function get_version(&$request) {
|
556 |
+
$version = $request->get_parameter("oauth_version");
|
557 |
+
if (!$version) {
|
558 |
+
// Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
|
559 |
+
// Chapter 7.0 ("Accessing Protected Ressources")
|
560 |
+
$version = '1.0';
|
561 |
+
}
|
562 |
+
if ($version !== $this->version) {
|
563 |
+
throw new OAuthException("OAuth version '$version' not supported");
|
564 |
+
}
|
565 |
+
return $version;
|
566 |
+
}
|
567 |
+
|
568 |
+
/**
|
569 |
+
* figure out the signature with some defaults
|
570 |
+
*/
|
571 |
+
private function get_signature_method($request) {
|
572 |
+
$signature_method = $request instanceof OAuthRequest
|
573 |
+
? $request->get_parameter("oauth_signature_method")
|
574 |
+
: NULL;
|
575 |
+
|
576 |
+
if (!$signature_method) {
|
577 |
+
// According to chapter 7 ("Accessing Protected Ressources") the signature-method
|
578 |
+
// parameter is required, and we can't just fallback to PLAINTEXT
|
579 |
+
throw new OAuthException('No signature method parameter. This parameter is required');
|
580 |
+
}
|
581 |
+
|
582 |
+
if (!in_array($signature_method,
|
583 |
+
array_keys($this->signature_methods))) {
|
584 |
+
throw new OAuthException(
|
585 |
+
"Signature method '$signature_method' not supported " .
|
586 |
+
"try one of the following: " .
|
587 |
+
implode(", ", array_keys($this->signature_methods))
|
588 |
+
);
|
589 |
+
}
|
590 |
+
return $this->signature_methods[$signature_method];
|
591 |
+
}
|
592 |
+
|
593 |
+
/**
|
594 |
+
* try to find the consumer for the provided request's consumer key
|
595 |
+
*/
|
596 |
+
private function get_consumer($request) {
|
597 |
+
$consumer_key = $request instanceof OAuthRequest
|
598 |
+
? $request->get_parameter("oauth_consumer_key")
|
599 |
+
: NULL;
|
600 |
+
|
601 |
+
if (!$consumer_key) {
|
602 |
+
throw new OAuthException("Invalid consumer key");
|
603 |
+
}
|
604 |
+
|
605 |
+
$consumer = $this->data_store->lookup_consumer($consumer_key);
|
606 |
+
if (!$consumer) {
|
607 |
+
throw new OAuthException("Invalid consumer");
|
608 |
+
}
|
609 |
+
|
610 |
+
return $consumer;
|
611 |
+
}
|
612 |
+
|
613 |
+
/**
|
614 |
+
* try to find the token for the provided request's token key
|
615 |
+
*/
|
616 |
+
private function get_token($request, $consumer, $token_type="access") {
|
617 |
+
$token_field = $request instanceof OAuthRequest
|
618 |
+
? $request->get_parameter('oauth_token')
|
619 |
+
: NULL;
|
620 |
+
|
621 |
+
$token = $this->data_store->lookup_token(
|
622 |
+
$consumer, $token_type, $token_field
|
623 |
+
);
|
624 |
+
if (!$token) {
|
625 |
+
throw new OAuthException("Invalid $token_type token: $token_field");
|
626 |
+
}
|
627 |
+
return $token;
|
628 |
+
}
|
629 |
+
|
630 |
+
/**
|
631 |
+
* all-in-one function to check the signature on a request
|
632 |
+
* should guess the signature method appropriately
|
633 |
+
*/
|
634 |
+
private function check_signature($request, $consumer, $token) {
|
635 |
+
// this should probably be in a different method
|
636 |
+
$timestamp = $request instanceof OAuthRequest
|
637 |
+
? $request->get_parameter('oauth_timestamp')
|
638 |
+
: NULL;
|
639 |
+
$nonce = $request instanceof OAuthRequest
|
640 |
+
? $request->get_parameter('oauth_nonce')
|
641 |
+
: NULL;
|
642 |
+
|
643 |
+
$this->check_timestamp($timestamp);
|
644 |
+
$this->check_nonce($consumer, $token, $nonce, $timestamp);
|
645 |
+
|
646 |
+
$signature_method = $this->get_signature_method($request);
|
647 |
+
|
648 |
+
$signature = $request->get_parameter('oauth_signature');
|
649 |
+
$valid_sig = $signature_method->check_signature(
|
650 |
+
$request,
|
651 |
+
$consumer,
|
652 |
+
$token,
|
653 |
+
$signature
|
654 |
+
);
|
655 |
+
|
656 |
+
if (!$valid_sig) {
|
657 |
+
throw new OAuthException("Invalid signature");
|
658 |
+
}
|
659 |
+
}
|
660 |
+
|
661 |
+
/**
|
662 |
+
* check that the timestamp is new enough
|
663 |
+
*/
|
664 |
+
private function check_timestamp($timestamp) {
|
665 |
+
if( ! $timestamp )
|
666 |
+
throw new OAuthException(
|
667 |
+
'Missing timestamp parameter. The parameter is required'
|
668 |
+
);
|
669 |
+
|
670 |
+
// verify that timestamp is recentish
|
671 |
+
$now = time();
|
672 |
+
if (abs($now - $timestamp) > $this->timestamp_threshold) {
|
673 |
+
throw new OAuthException(
|
674 |
+
"Expired timestamp, yours $timestamp, ours $now"
|
675 |
+
);
|
676 |
+
}
|
677 |
+
}
|
678 |
+
|
679 |
+
/**
|
680 |
+
* check that the nonce is not repeated
|
681 |
+
*/
|
682 |
+
private function check_nonce($consumer, $token, $nonce, $timestamp) {
|
683 |
+
if( ! $nonce )
|
684 |
+
throw new OAuthException(
|
685 |
+
'Missing nonce parameter. The parameter is required'
|
686 |
+
);
|
687 |
+
|
688 |
+
// verify that the nonce is uniqueish
|
689 |
+
$found = $this->data_store->lookup_nonce(
|
690 |
+
$consumer,
|
691 |
+
$token,
|
692 |
+
$nonce,
|
693 |
+
$timestamp
|
694 |
+
);
|
695 |
+
if ($found) {
|
696 |
+
throw new OAuthException("Nonce already used: $nonce");
|
697 |
+
}
|
698 |
+
}
|
699 |
+
|
700 |
+
}
|
701 |
+
|
702 |
+
class OAuthDataStore {
|
703 |
+
function lookup_consumer($consumer_key) {
|
704 |
+
// implement me
|
705 |
+
}
|
706 |
+
|
707 |
+
function lookup_token($consumer, $token_type, $token) {
|
708 |
+
// implement me
|
709 |
+
}
|
710 |
+
|
711 |
+
function lookup_nonce($consumer, $token, $nonce, $timestamp) {
|
712 |
+
// implement me
|
713 |
+
}
|
714 |
+
|
715 |
+
function new_request_token($consumer, $callback = null) {
|
716 |
+
// return a new token attached to this consumer
|
717 |
+
}
|
718 |
+
|
719 |
+
function new_access_token($token, $consumer, $verifier = null) {
|
720 |
+
// return a new access token attached to this consumer
|
721 |
+
// for the user associated with this token if the request token
|
722 |
+
// is authorized
|
723 |
+
// should also invalidate the request token
|
724 |
+
}
|
725 |
+
|
726 |
+
}
|
727 |
+
|
728 |
+
class OAuthUtil {
|
729 |
+
public static function urlencode_rfc3986($input) {
|
730 |
+
if (is_array($input)) {
|
731 |
+
return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
|
732 |
+
} else if (is_scalar($input)) {
|
733 |
+
return str_replace(
|
734 |
+
'+',
|
735 |
+
' ',
|
736 |
+
str_replace('%7E', '~', rawurlencode($input))
|
737 |
+
);
|
738 |
+
} else {
|
739 |
+
return '';
|
740 |
+
}
|
741 |
+
}
|
742 |
+
|
743 |
+
|
744 |
+
// This decode function isn't taking into consideration the above
|
745 |
+
// modifications to the encoding process. However, this method doesn't
|
746 |
+
// seem to be used anywhere so leaving it as is.
|
747 |
+
public static function urldecode_rfc3986($string) {
|
748 |
+
return urldecode($string);
|
749 |
+
}
|
750 |
+
|
751 |
+
// Utility function for turning the Authorization: header into
|
752 |
+
// parameters, has to do some unescaping
|
753 |
+
// Can filter out any non-oauth parameters if needed (default behaviour)
|
754 |
+
// May 28th, 2010 - method updated to tjerk.meesters for a speed improvement.
|
755 |
+
// see http://code.google.com/p/oauth/issues/detail?id=163
|
756 |
+
public static function split_header($header, $only_allow_oauth_parameters = true) {
|
757 |
+
$params = array();
|
758 |
+
if (preg_match_all('/('.($only_allow_oauth_parameters ? 'oauth_' : '').'[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', $header, $matches)) {
|
759 |
+
foreach ($matches[1] as $i => $h) {
|
760 |
+
$params[$h] = OAuthUtil::urldecode_rfc3986(empty($matches[3][$i]) ? $matches[4][$i] : $matches[3][$i]);
|
761 |
+
}
|
762 |
+
if (isset($params['realm'])) {
|
763 |
+
unset($params['realm']);
|
764 |
+
}
|
765 |
+
}
|
766 |
+
return $params;
|
767 |
+
}
|
768 |
+
|
769 |
+
// helper to try to sort out headers for people who aren't running apache
|
770 |
+
public static function get_headers() {
|
771 |
+
if (function_exists('apache_request_headers')) {
|
772 |
+
// we need this to get the actual Authorization: header
|
773 |
+
// because apache tends to tell us it doesn't exist
|
774 |
+
$headers = apache_request_headers();
|
775 |
+
|
776 |
+
// sanitize the output of apache_request_headers because
|
777 |
+
// we always want the keys to be Cased-Like-This and arh()
|
778 |
+
// returns the headers in the same case as they are in the
|
779 |
+
// request
|
780 |
+
$out = array();
|
781 |
+
foreach ($headers AS $key => $value) {
|
782 |
+
$key = str_replace(
|
783 |
+
" ",
|
784 |
+
"-",
|
785 |
+
ucwords(strtolower(str_replace("-", " ", $key)))
|
786 |
+
);
|
787 |
+
$out[$key] = $value;
|
788 |
+
}
|
789 |
+
} else {
|
790 |
+
// otherwise we don't have apache and are just going to have to hope
|
791 |
+
// that $_SERVER actually contains what we need
|
792 |
+
$out = array();
|
793 |
+
if( isset($_SERVER['CONTENT_TYPE']) )
|
794 |
+
$out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
|
795 |
+
if( isset($_ENV['CONTENT_TYPE']) )
|
796 |
+
$out['Content-Type'] = $_ENV['CONTENT_TYPE'];
|
797 |
+
|
798 |
+
foreach ($_SERVER as $key => $value) {
|
799 |
+
if (substr($key, 0, 5) == "HTTP_") {
|
800 |
+
// this is chaos, basically it is just there to capitalize the first
|
801 |
+
// letter of every word that is not an initial HTTP and strip HTTP
|
802 |
+
// code from przemek
|
803 |
+
$key = str_replace(
|
804 |
+
" ",
|
805 |
+
"-",
|
806 |
+
ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
|
807 |
+
);
|
808 |
+
$out[$key] = $value;
|
809 |
+
}
|
810 |
+
}
|
811 |
+
}
|
812 |
+
return $out;
|
813 |
+
}
|
814 |
+
|
815 |
+
// This function takes a input like a=b&a=c&d=e and returns the parsed
|
816 |
+
// parameters like this
|
817 |
+
// array('a' => array('b','c'), 'd' => 'e')
|
818 |
+
public static function parse_parameters( $input ) {
|
819 |
+
if (!isset($input) || !$input) return array();
|
820 |
+
|
821 |
+
$pairs = explode('&', $input);
|
822 |
+
|
823 |
+
$parsed_parameters = array();
|
824 |
+
foreach ($pairs as $pair) {
|
825 |
+
$split = explode('=', $pair, 2);
|
826 |
+
$parameter = OAuthUtil::urldecode_rfc3986($split[0]);
|
827 |
+
$value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';
|
828 |
+
|
829 |
+
if (isset($parsed_parameters[$parameter])) {
|
830 |
+
// We have already recieved parameter(s) with this name, so add to the list
|
831 |
+
// of parameters with this name
|
832 |
+
|
833 |
+
if (is_scalar($parsed_parameters[$parameter])) {
|
834 |
+
// This is the first duplicate, so transform scalar (string) into an array
|
835 |
+
// so we can add the duplicates
|
836 |
+
$parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
|
837 |
+
}
|
838 |
+
|
839 |
+
$parsed_parameters[$parameter][] = $value;
|
840 |
+
} else {
|
841 |
+
$parsed_parameters[$parameter] = $value;
|
842 |
+
}
|
843 |
+
}
|
844 |
+
return $parsed_parameters;
|
845 |
+
}
|
846 |
+
|
847 |
+
public static function build_http_query($params) {
|
848 |
+
if (!$params) return '';
|
849 |
+
|
850 |
+
// Urlencode both keys and values
|
851 |
+
$keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
|
852 |
+
$values = OAuthUtil::urlencode_rfc3986(array_values($params));
|
853 |
+
$params = array_combine($keys, $values);
|
854 |
+
|
855 |
+
// Parameters are sorted by name, using lexicographical byte value ordering.
|
856 |
+
// Ref: Spec: 9.1.1 (1)
|
857 |
+
uksort($params, 'strcmp');
|
858 |
+
|
859 |
+
$pairs = array();
|
860 |
+
foreach ($params as $parameter => $value) {
|
861 |
+
if (is_array($value)) {
|
862 |
+
// If two or more parameters share the same name, they are sorted by their value
|
863 |
+
// Ref: Spec: 9.1.1 (1)
|
864 |
+
// June 12th, 2010 - changed to sort because of issue 164 by hidetaka
|
865 |
+
sort($value, SORT_STRING);
|
866 |
+
foreach ($value as $duplicate_value) {
|
867 |
+
$pairs[] = $parameter . '=' . $duplicate_value;
|
868 |
+
}
|
869 |
+
} else {
|
870 |
+
$pairs[] = $parameter . '=' . $value;
|
871 |
+
}
|
872 |
+
}
|
873 |
+
// For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
|
874 |
+
// Each name-value pair is separated by an '&' character (ASCII code 38)
|
875 |
+
return implode('&', $pairs);
|
876 |
+
}
|
877 |
+
}
|
878 |
+
|
879 |
+
?>
|
app/libs/sugarsync.php
ADDED
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* SugarSync class
|
5 |
+
*
|
6 |
+
* This source file can be used to communicate with SugarSync (http://sugarsync.com)
|
7 |
+
*
|
8 |
+
* The class is documented in the file itself. If you find any bugs help me out and report them. Reporting can be done by sending an email to php-dropbox-bugs[at]verkoyen[dot]eu.
|
9 |
+
* If you report a bug, make sure you give me enough information (include your code).
|
10 |
+
*
|
11 |
+
*
|
12 |
+
* Changelog since 1.0.0
|
13 |
+
* - fixed some issues with generation off the basestring
|
14 |
+
*
|
15 |
+
* License
|
16 |
+
* Copyright (c), Daniel Huesken. All rights reserved.
|
17 |
+
*
|
18 |
+
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
19 |
+
*
|
20 |
+
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
21 |
+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
22 |
+
* 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
|
23 |
+
*
|
24 |
+
* This software is provided by the author "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the author be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.
|
25 |
+
*
|
26 |
+
* @author Daniel Huesken <daniel@huesken-net.de>
|
27 |
+
* @version 1.0.0
|
28 |
+
*
|
29 |
+
* @copyright Copyright (c), Daniel Huesken. All rights reserved.
|
30 |
+
* @license BSD License
|
31 |
+
*/
|
32 |
+
|
33 |
+
class SugarSync {
|
34 |
+
|
35 |
+
// debug
|
36 |
+
const DEBUG = true;
|
37 |
+
|
38 |
+
// url for the sugarsync-api
|
39 |
+
const API_URL = 'https://api.sugarsync.com';
|
40 |
+
|
41 |
+
// current version
|
42 |
+
const VERSION = '1.0.0';
|
43 |
+
|
44 |
+
|
45 |
+
/**
|
46 |
+
* The Auth-token
|
47 |
+
*
|
48 |
+
* @var string
|
49 |
+
*/
|
50 |
+
private $AuthToken = '';
|
51 |
+
|
52 |
+
|
53 |
+
// class methods
|
54 |
+
/**
|
55 |
+
* Default constructor/Auth
|
56 |
+
*
|
57 |
+
* @return void
|
58 |
+
* @param string $email The consumer E-Mail.
|
59 |
+
* @param string $password The consumer password.
|
60 |
+
* @param string $accessKeyId The developer access key.
|
61 |
+
* @param string $privateAccessKey The developer access scret.
|
62 |
+
*/
|
63 |
+
public function __construct($email, $password, $accessKeyId, $privateAccessKey)
|
64 |
+
{
|
65 |
+
if(!is_string($email) or empty($email))
|
66 |
+
throw new SugarSyncException('You must set Account E-Mail!');
|
67 |
+
if(!is_string($password) or empty($password))
|
68 |
+
throw new SugarSyncException('You must set Account Password!');
|
69 |
+
if(!is_string($accessKeyId) or empty($accessKeyId))
|
70 |
+
throw new SugarSyncException('You must Developer access Key!');
|
71 |
+
if(!is_string($privateAccessKey) or empty($privateAccessKey))
|
72 |
+
throw new SugarSyncException('You must Developer access Secret!');
|
73 |
+
|
74 |
+
//auth xml
|
75 |
+
$auth ='<?xml version="1.0" encoding="UTF-8" ?>';
|
76 |
+
$auth.='<authRequest>';
|
77 |
+
$auth.='<username>'.utf8_encode($email).'</username>';
|
78 |
+
$auth.='<password>'.utf8_encode($password).'</password>';
|
79 |
+
$auth.='<accessKeyId>'.utf8_encode($accessKeyId).'</accessKeyId>';
|
80 |
+
$auth.='<privateAccessKey>'.utf8_encode($privateAccessKey).'</privateAccessKey>';
|
81 |
+
$auth.='</authRequest>';
|
82 |
+
// init
|
83 |
+
$curl = curl_init();
|
84 |
+
//set otions
|
85 |
+
curl_setopt($curl,CURLOPT_URL,self::API_URL .'/authorization');
|
86 |
+
//curl_setopt($curl,CURLOPT_USERAGENT,'PHP SugarSync/'. self::VERSION);
|
87 |
+
if(ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) curl_setopt($curl,CURLOPT_FOLLOWLOCATION,true);
|
88 |
+
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
|
89 |
+
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
|
90 |
+
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,false);
|
91 |
+
curl_setopt($curl,CURLOPT_HEADER,true);
|
92 |
+
curl_setopt($curl,CURLOPT_HTTPHEADER,array('Content-Type: application/xml; charset=UTF-8'));
|
93 |
+
curl_setopt($curl,CURLOPT_POSTFIELDS,$auth);
|
94 |
+
curl_setopt($curl,CURLOPT_POST,true);
|
95 |
+
// execute
|
96 |
+
$response = curl_exec($curl);
|
97 |
+
$curlgetinfo = curl_getinfo($curl);
|
98 |
+
// fetch curl errors
|
99 |
+
if (curl_errno($curl) != 0)
|
100 |
+
throw new SugarSyncException('cUrl Error: '. curl_error($curl));
|
101 |
+
|
102 |
+
curl_close($curl);
|
103 |
+
|
104 |
+
if ($curlgetinfo['http_code']>=200 and $curlgetinfo['http_code']<=204) {
|
105 |
+
if (preg_match('/Location:(.*?)\n/', $response, $matches))
|
106 |
+
$this->AuthToken=$matches[1];
|
107 |
+
} else {
|
108 |
+
if ($curlgetinfo['http_code']==401)
|
109 |
+
throw new SugarSyncException('Http Error: '. $curlgetinfo['http_code'].' Authorization required or worng.');
|
110 |
+
elseif ($curlgetinfo['http_code']==403)
|
111 |
+
throw new SugarSyncException('Http Error: '. $curlgetinfo['http_code'].' (Forbidden) Authentication failed.');
|
112 |
+
elseif ($curlgetinfo['http_code']==404)
|
113 |
+
throw new SugarSyncException('Http Error: '. $curlgetinfo['http_code'].' Not found');
|
114 |
+
else
|
115 |
+
throw new SugarSyncException('Http Error: '. $curlgetinfo['http_code']);
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Make the call
|
121 |
+
*
|
122 |
+
* @return string
|
123 |
+
* @param string $url The url to call.
|
124 |
+
* @param string[optiona] $data File on put, xml on post.
|
125 |
+
* @param string[optional] $method The method to use. Possible values are GET, POST, PUT, DELETE.
|
126 |
+
*/
|
127 |
+
private function doCall($url, $data = '', $method = 'GET') {
|
128 |
+
// allowed methods
|
129 |
+
$allowedMethods = array('GET','POST','PUT','DELETE');
|
130 |
+
|
131 |
+
// redefine
|
132 |
+
$url = (string) $url;
|
133 |
+
$data = (string) $data;
|
134 |
+
$method = (string) $method;
|
135 |
+
|
136 |
+
// validate method
|
137 |
+
if(!in_array($method, $allowedMethods))
|
138 |
+
throw new SugarSyncException('Unknown method ('. $method .'). Allowed methods are: '. implode(', ', $allowedMethods));
|
139 |
+
|
140 |
+
// check auth token
|
141 |
+
if(!is_string($this->AuthToken) or empty($this->AuthToken) or !strripos($this->AuthToken,self::API_URL))
|
142 |
+
throw new SugarSyncException('Auth Token not set correctly!!');
|
143 |
+
else
|
144 |
+
$headers[] = 'Authorization: '.$this->AuthToken;
|
145 |
+
|
146 |
+
// init
|
147 |
+
$curl = curl_init();
|
148 |
+
//set otions
|
149 |
+
curl_setopt($curl,CURLOPT_USERAGENT,'PHP SugarSync/'. self::VERSION);
|
150 |
+
if(ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) curl_setopt($curl,CURLOPT_FOLLOWLOCATION,true);
|
151 |
+
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
|
152 |
+
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
|
153 |
+
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,false);
|
154 |
+
|
155 |
+
|
156 |
+
if ($method == 'POST') {
|
157 |
+
$headers[] = 'Content-Type: application/xml; charset=UTF-8';
|
158 |
+
//$url=str_replace(':','/',$url);
|
159 |
+
curl_setopt($curl,CURLOPT_POSTFIELDS,$data);
|
160 |
+
echo $data;
|
161 |
+
curl_setopt($curl,CURLOPT_POST,true);
|
162 |
+
} elseif ($method == 'PUT') {
|
163 |
+
if (is_file($data) and is_readable($data)) {
|
164 |
+
$datafilefd=fopen($data,'r');
|
165 |
+
curl_setopt($curl,CURLOPT_PUT,true);
|
166 |
+
curl_setopt($curl,CURLOPT_INFILE,$datafilefd);
|
167 |
+
curl_setopt($curl,CURLOPT_INFILESIZE,filesize($data));
|
168 |
+
} elseif (is_sting($data) and !is_file($data)) {
|
169 |
+
curl_setopt($curl,CURLOPT_PUT,true);
|
170 |
+
curl_setopt($curl,CURLOPT_INFILE,$data);
|
171 |
+
curl_setopt($curl,CURLOPT_INFILESIZE,strnlen($data));
|
172 |
+
} else {
|
173 |
+
throw new SugarSyncException('Is not a readable file or string:'. $data);
|
174 |
+
}
|
175 |
+
} elseif ($method == 'DELETE') {
|
176 |
+
curl_setopt($curl,CURLOPT_CUSTOMREQUEST,'DELETE');
|
177 |
+
} else {
|
178 |
+
curl_setopt($curl,CURLOPT_POST,false);
|
179 |
+
}
|
180 |
+
|
181 |
+
// set headers
|
182 |
+
curl_setopt($curl,CURLOPT_URL, $url);
|
183 |
+
curl_setopt($curl,CURLOPT_HTTPHEADER,$headers);
|
184 |
+
curl_setopt($curl,CURLINFO_HEADER_OUT,self::DEBUG);
|
185 |
+
|
186 |
+
// execute
|
187 |
+
$response = curl_exec($curl);
|
188 |
+
$curlgetinfo = curl_getinfo($curl);
|
189 |
+
|
190 |
+
if (self::DEBUG) {
|
191 |
+
echo "<pre>";
|
192 |
+
var_dump($response);
|
193 |
+
var_dump($curlgetinfo);
|
194 |
+
echo "</pre>";
|
195 |
+
}
|
196 |
+
|
197 |
+
// fetch curl errors
|
198 |
+
if (curl_errno($curl) != 0)
|
199 |
+
throw new SugarSyncException('cUrl Error: '. curl_error($curl));
|
200 |
+
|
201 |
+
curl_close($curl);
|
202 |
+
|
203 |
+
if ($curlgetinfo['http_code']>=200 and $curlgetinfo['http_code']<300) {
|
204 |
+
if (!empty($response))
|
205 |
+
return simplexml_load_string($response);
|
206 |
+
} else {
|
207 |
+
if ($curlgetinfo['http_code']==401)
|
208 |
+
throw new SugarSyncException('Http Error: '. $curlgetinfo['http_code'].' Authorization required.');
|
209 |
+
elseif ($curlgetinfo['http_code']==403)
|
210 |
+
throw new SugarSyncException('Http Error: '. $curlgetinfo['http_code'].' (Forbidden) Authentication failed.');
|
211 |
+
elseif ($curlgetinfo['http_code']==404)
|
212 |
+
throw new SugarSyncException('Http Error: '. $curlgetinfo['http_code'].' Not found');
|
213 |
+
else
|
214 |
+
throw new SugarSyncException('Http Error: '. $curlgetinfo['http_code']);
|
215 |
+
}
|
216 |
+
}
|
217 |
+
|
218 |
+
public function user() {
|
219 |
+
$request=$this->doCall(self::API_URL .'/user');
|
220 |
+
return $request;
|
221 |
+
}
|
222 |
+
|
223 |
+
|
224 |
+
public function get($url) {
|
225 |
+
$request=$this->doCall($url,'','GET');
|
226 |
+
return $request;
|
227 |
+
}
|
228 |
+
|
229 |
+
public function delete($url) {
|
230 |
+
$request=$this->doCall($url,'DELTE');
|
231 |
+
}
|
232 |
+
|
233 |
+
|
234 |
+
public function getcontents($url,$start=0,$max=500) {
|
235 |
+
if (strtolower($type)=='folder' or strtolower($type)=='file')
|
236 |
+
$parameters.='type='.strtolower($type);
|
237 |
+
if (!empty($start) and is_integer($start)) {
|
238 |
+
if (!empty($parameters))
|
239 |
+
$parameters.='&';
|
240 |
+
$parameters.='start='.$start;
|
241 |
+
|
242 |
+
}
|
243 |
+
if (!empty($max) and is_integer($max)) {
|
244 |
+
if (!empty($parameters))
|
245 |
+
$parameters.='&';
|
246 |
+
$parameters.='max='.$max;
|
247 |
+
}
|
248 |
+
|
249 |
+
$request=$this->doCall($url.'?'.$parameters);
|
250 |
+
return $request;
|
251 |
+
}
|
252 |
+
|
253 |
+
public function createfile($url,$file,$name='') {
|
254 |
+
if (empty($name))
|
255 |
+
$name=basename($file);
|
256 |
+
$name=utf8_encode($name);
|
257 |
+
$xmlrequest ='<?xml version="1.0" encoding="UTF-8"?>';
|
258 |
+
$xmlrequest.='<file>';
|
259 |
+
$xmlrequest.='<displayName>'.$name.'</displayName>';
|
260 |
+
if (!is_file($file))
|
261 |
+
$xmlrequest.='<mediaType>'.mime_content_type($file).'</mediaType>';
|
262 |
+
$xmlrequest.='</file>';
|
263 |
+
$request=$this->doCall($url,$xmlrequest,'POST');
|
264 |
+
|
265 |
+
//$request=$this->doCall($url,$file,'PUT');
|
266 |
+
}
|
267 |
+
|
268 |
+
public function createfolder($url,$folder) {
|
269 |
+
$xmlrequest ='<?xml version="1.0" encoding="UTF-8"?>';
|
270 |
+
$xmlrequest.='<folder>';
|
271 |
+
$xmlrequest.='<displayName>'.utf8_encode($folder).'</displayName>';
|
272 |
+
$xmlrequest.='</folder>';
|
273 |
+
$request=$this->doCall($url,$xmlrequest,'POST');
|
274 |
+
}
|
275 |
+
|
276 |
+
}
|
277 |
+
|
278 |
+
|
279 |
+
/**
|
280 |
+
* SugarSync Exception class
|
281 |
+
*
|
282 |
+
* @author Daniel Huesken <daniel@huersken-net.de>
|
283 |
+
*/
|
284 |
+
class SugarSyncException extends Exception {
|
285 |
+
}
|
app/options-edit-job.php
CHANGED
@@ -431,6 +431,21 @@ $dests=explode(',',strtoupper(BACKWPUP_DESTS));
|
|
431 |
</div>
|
432 |
<?PHP } ?>
|
433 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
434 |
<div id="tomail" class="postbox" <?PHP if (!in_array("FILE",$todo) and !in_array("DB",$todo) and !in_array("WPEXP",$todo)) echo 'style="display:none;"';?>>
|
435 |
<h3 class="hndle"><span><?PHP _e('Backup to E-Mail','backwpup'); ?></span></h3>
|
436 |
<div class="inside">
|
431 |
</div>
|
432 |
<?PHP } ?>
|
433 |
|
434 |
+
<?PHP if (in_array('SUGARSYNC',$dests) and function_exists('curl_exec')) { ?>
|
435 |
+
<div id="tosugarsync" class="postbox" <?PHP if (!in_array("FILE",$todo) and !in_array("DB",$todo) and !in_array("WPEXP",$todo)) echo 'style="display:none;"';?>>
|
436 |
+
<h3 class="hndle"><span><?PHP _e('Backup to SugarSync','backwpup'); ?></span> <a href="https://www.sugarsync.com/referral?rf=cajw0b09tbw6k" target="_blank"><?PHP _e('Create Account','backwpup'); ?></a></h3>
|
437 |
+
<div class="inside">
|
438 |
+
<b><?PHP _e('E-mail address:','backwpup'); ?></b><br />
|
439 |
+
<input id="sugaruser" name="sugaruser" type="text" value="<?PHP echo $jobvalue['sugaruser'];?>" class="large-text" /><br />
|
440 |
+
<b><?PHP _e('Password:','backwpup'); ?></b><br />
|
441 |
+
<input id="sugarpass" name="sugarpass" type="password" value="<?PHP echo base64_decode($jobvalue['sugarpass']);?>" class="large-text" /><br />
|
442 |
+
<b><?PHP _e('Directory:','backwpup'); ?></b><br />
|
443 |
+
<input name="sugardir" type="text" value="<?PHP echo $jobvalue['sugardir'];?>" class="large-text" /><br />
|
444 |
+
<?PHP _e('Max. Backup Files in Folder:','backwpup'); ?><input name="sugarmaxbackups" type="text" size="3" value="<?PHP echo $jobvalue['sugarmaxbackups'];?>" class="small-text" /><span class="description"><?PHP _e('(Oldest files will be deleted first.)','backwpup');?></span><br />
|
445 |
+
</div>
|
446 |
+
</div>
|
447 |
+
<?PHP } ?>
|
448 |
+
|
449 |
<div id="tomail" class="postbox" <?PHP if (!in_array("FILE",$todo) and !in_array("DB",$todo) and !in_array("WPEXP",$todo)) echo 'style="display:none;"';?>>
|
450 |
<h3 class="hndle"><span><?PHP _e('Backup to E-Mail','backwpup'); ?></span></h3>
|
451 |
<div class="inside">
|
app/options-save.php
CHANGED
@@ -164,7 +164,7 @@ function backwpup_backups_operations($action) {
|
|
164 |
if (!class_exists('CF_Authentication'))
|
165 |
require_once(plugin_dir_path(__FILE__).'libs/rackspace/cloudfiles.php');
|
166 |
if (!class_exists('Dropbox'))
|
167 |
-
require_once(dirname(__FILE__).'/libs/dropbox.php');
|
168 |
}
|
169 |
|
170 |
$num=0;
|
@@ -191,8 +191,7 @@ function backwpup_backups_operations($action) {
|
|
191 |
if (class_exists('Dropbox')) {
|
192 |
if (!empty($jobvalue['dropetoken']) and !empty($jobvalue['dropesecret'])) {
|
193 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
194 |
-
$dropbox->
|
195 |
-
$dropbox->setOAuthTokenSecret($jobvalue['dropesecret']);
|
196 |
$dropbox->fileopsDelete($backups['file']);
|
197 |
}
|
198 |
}
|
@@ -293,34 +292,27 @@ function backwpup_backups_operations($action) {
|
|
293 |
break;
|
294 |
case 'downloaddropbox': //Download Dropbox Backup
|
295 |
check_admin_referer('download-backup');
|
296 |
-
require_once(dirname(__FILE__).'/libs/dropbox.php');
|
297 |
$jobs=get_option('backwpup_jobs');
|
298 |
$jobid=$_GET['jobid'];
|
299 |
try {
|
300 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
301 |
-
$dropbox->
|
302 |
-
$dropbox->setOAuthTokenSecret($jobs[$jobid]['dropesecret']);
|
303 |
-
$dropfile = $dropbox->filesGet($_GET['file']);
|
304 |
-
} catch (Exception $e) {
|
305 |
-
die($e->getMessage());
|
306 |
-
}
|
307 |
-
if (!empty($dropfile['content_type'])) {
|
308 |
header("Pragma: public");
|
309 |
header("Expires: 0");
|
310 |
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
|
311 |
-
header("Content-Type: ".$dropfile['content_type']);
|
312 |
header("Content-Type: application/force-download");
|
313 |
header("Content-Type: application/octet-stream");
|
314 |
header("Content-Type: application/download");
|
315 |
header("Content-Disposition: attachment; filename=".basename($_GET['file']).";");
|
316 |
header("Content-Transfer-Encoding: binary");
|
317 |
-
header("Content-Length: ".$dropfile['bytes']);
|
318 |
-
echo
|
319 |
-
die();
|
320 |
-
} else {
|
321 |
-
header('HTTP/1.0 404 Not Found');
|
322 |
die();
|
323 |
-
}
|
|
|
|
|
324 |
break;
|
325 |
case 'downloadmsazure': //Download Microsoft Azure Backup
|
326 |
check_admin_referer('download-backup');
|
@@ -515,6 +507,10 @@ function backwpup_save_job() { //Save Job settings
|
|
515 |
$jobs[$jobid]['msazureContainer']=$_POST['msazureContainer'];
|
516 |
$jobs[$jobid]['msazuredir']=stripslashes($_POST['msazuredir']);
|
517 |
$jobs[$jobid]['msazuremaxbackups']=(int)$_POST['msazuremaxbackups'];
|
|
|
|
|
|
|
|
|
518 |
$jobs[$jobid]['rscUsername']=$_POST['rscUsername'];
|
519 |
$jobs[$jobid]['rscAPIKey']=$_POST['rscAPIKey'];
|
520 |
$jobs[$jobid]['rscContainer']=$_POST['rscContainer'];
|
@@ -573,7 +569,7 @@ function backwpup_save_job() { //Save Job settings
|
|
573 |
|
574 |
if ($_POST['dropboxauth']==__('Authenticate!', 'backwpup')) {
|
575 |
if (!class_exists('Dropbox'))
|
576 |
-
require_once (dirname(__FILE__).'/libs/dropbox.php');
|
577 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
578 |
// request request tokens
|
579 |
$response = $dropbox->oAuthRequestToken();
|
164 |
if (!class_exists('CF_Authentication'))
|
165 |
require_once(plugin_dir_path(__FILE__).'libs/rackspace/cloudfiles.php');
|
166 |
if (!class_exists('Dropbox'))
|
167 |
+
require_once(dirname(__FILE__).'/libs/dropbox/dropbox.php');
|
168 |
}
|
169 |
|
170 |
$num=0;
|
191 |
if (class_exists('Dropbox')) {
|
192 |
if (!empty($jobvalue['dropetoken']) and !empty($jobvalue['dropesecret'])) {
|
193 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
194 |
+
$dropbox->setOAuthTokens($jobvalue['dropetoken'],$jobvalue['dropesecret']);
|
|
|
195 |
$dropbox->fileopsDelete($backups['file']);
|
196 |
}
|
197 |
}
|
292 |
break;
|
293 |
case 'downloaddropbox': //Download Dropbox Backup
|
294 |
check_admin_referer('download-backup');
|
295 |
+
require_once(dirname(__FILE__).'/libs/dropbox/dropbox.php');
|
296 |
$jobs=get_option('backwpup_jobs');
|
297 |
$jobid=$_GET['jobid'];
|
298 |
try {
|
299 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
300 |
+
$dropbox->setOAuthTokens($jobs[$jobid]['dropetoken'],$jobs[$jobid]['dropesecret']);
|
|
|
|
|
|
|
|
|
|
|
|
|
301 |
header("Pragma: public");
|
302 |
header("Expires: 0");
|
303 |
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
|
304 |
+
//header("Content-Type: ".$dropfile['content_type']);
|
305 |
header("Content-Type: application/force-download");
|
306 |
header("Content-Type: application/octet-stream");
|
307 |
header("Content-Type: application/download");
|
308 |
header("Content-Disposition: attachment; filename=".basename($_GET['file']).";");
|
309 |
header("Content-Transfer-Encoding: binary");
|
310 |
+
//header("Content-Length: ".$dropfile['bytes']);
|
311 |
+
echo $dropbox->download($_GET['file']);
|
|
|
|
|
|
|
312 |
die();
|
313 |
+
} catch (Exception $e) {
|
314 |
+
die($e->getMessage());
|
315 |
+
}
|
316 |
break;
|
317 |
case 'downloadmsazure': //Download Microsoft Azure Backup
|
318 |
check_admin_referer('download-backup');
|
507 |
$jobs[$jobid]['msazureContainer']=$_POST['msazureContainer'];
|
508 |
$jobs[$jobid]['msazuredir']=stripslashes($_POST['msazuredir']);
|
509 |
$jobs[$jobid]['msazuremaxbackups']=(int)$_POST['msazuremaxbackups'];
|
510 |
+
$jobs[$jobid]['sugaruser']=$_POST['sugaruser'];
|
511 |
+
$jobs[$jobid]['sugarpass']=base64_encode($_POST['sugarpass']);
|
512 |
+
$jobs[$jobid]['sugardir']=stripslashes($_POST['sugardir']);
|
513 |
+
$jobs[$jobid]['sugarmaxbackups']=(int)$_POST['sugarmaxbackups'];
|
514 |
$jobs[$jobid]['rscUsername']=$_POST['rscUsername'];
|
515 |
$jobs[$jobid]['rscAPIKey']=$_POST['rscAPIKey'];
|
516 |
$jobs[$jobid]['rscContainer']=$_POST['rscContainer'];
|
569 |
|
570 |
if ($_POST['dropboxauth']==__('Authenticate!', 'backwpup')) {
|
571 |
if (!class_exists('Dropbox'))
|
572 |
+
require_once (dirname(__FILE__).'/libs/dropbox/dropbox.php');
|
573 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
574 |
// request request tokens
|
575 |
$response = $dropbox->oAuthRequestToken();
|
app/php-functions.php
CHANGED
@@ -5,6 +5,13 @@ if ( !defined('ABSPATH') )
|
|
5 |
|
6 |
//Thems Option menu entry
|
7 |
function backwpup_admin_menu() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
$hook = add_management_page(__('BackWPup','backwpup'), __('BackWPup','backwpup'), BACKWPUP_USER_CAPABILITY, 'BackWPup','backwpup_options_page') ;
|
9 |
add_action('load-'.$hook, 'backwpup_options_load');
|
10 |
}
|
5 |
|
6 |
//Thems Option menu entry
|
7 |
function backwpup_admin_menu() {
|
8 |
+
//add_menu_page( __('BackWPup','backwpup'), __('BackWPup','backwpup'), BACKWPUP_USER_CAPABILITY, 'BackWPup', 'backwpup_jobs_page', plugins_url('css/backup-icon.gif',__FILE__) );
|
9 |
+
//add_submenu_page( 'BackWPup', __('Jobs','backwpup'), __('Jobs','backwpup'), BACKWPUP_USER_CAPABILITY, 'BackWPup', 'backwpup_jobs_page' );
|
10 |
+
//add_submenu_page( 'BackWPup', __('Logs','backwpup'), __('Logs','backwpup'), BACKWPUP_USER_CAPABILITY, 'BackWPupLogs', 'backwpup_logs_page' );
|
11 |
+
//add_submenu_page( 'BackWPup', __('Backups','backwpup'), __('Backups','backwpup'), BACKWPUP_USER_CAPABILITY, 'BackWPupBackups', 'backwpup_backups_page' );
|
12 |
+
//add_submenu_page( 'BackWPup', __('Tools','backwpup'), __('Tools','backwpup'), BACKWPUP_USER_CAPABILITY, 'BackWPupTools', 'backwpup_tools_page' );
|
13 |
+
//add_submenu_page( 'BackWPup', __('Settings','backwpup'), __('Settings','backwpup'), BACKWPUP_USER_CAPABILITY, 'BackWPupSettings', 'backwpup_settings_page' );
|
14 |
+
|
15 |
$hook = add_management_page(__('BackWPup','backwpup'), __('BackWPup','backwpup'), BACKWPUP_USER_CAPABILITY, 'BackWPup','backwpup_options_page') ;
|
16 |
add_action('load-'.$hook, 'backwpup_options_load');
|
17 |
}
|
app/php5-functions.php
CHANGED
@@ -278,6 +278,23 @@ function backwpup_check_job_vars($jobsettings,$jobid='') {
|
|
278 |
if (!isset($jobsettings['dropemaxbackups']) or !is_int($jobsettings['dropemaxbackups']))
|
279 |
$jobsettings['dropemaxbackups']=0;
|
280 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
281 |
if (!is_string($jobsettings['mailaddress']) or false === $pos=strpos($jobsettings['mailaddress'],'@') or false === strpos($jobsettings['mailaddress'],'.',$pos))
|
282 |
$jobsettings['mailaddress']='';
|
283 |
|
@@ -301,7 +318,7 @@ function backwpup_get_backup_files($onlyjobid='') {
|
|
301 |
if (!class_exists('CF_Authentication'))
|
302 |
require_once(dirname(__FILE__).'/libs/rackspace/cloudfiles.php');
|
303 |
if (!class_exists('Dropbox') and function_exists('json_decode'))
|
304 |
-
require_once(dirname(__FILE__).'/libs/dropbox.php');
|
305 |
}
|
306 |
|
307 |
foreach ($jobs as $jobid => $jobvalue) { //go job by job
|
@@ -338,8 +355,7 @@ function backwpup_get_backup_files($onlyjobid='') {
|
|
338 |
if (!empty($jobvalue['dropetoken']) and !empty($jobvalue['dropesecret'])) {
|
339 |
try {
|
340 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
341 |
-
$dropbox->
|
342 |
-
$dropbox->setOAuthTokenSecret($jobvalue['dropesecret']);
|
343 |
$contents = $dropbox->metadata($jobvalue['dropedir']);
|
344 |
if (is_array($contents)) {
|
345 |
foreach ($contents['contents'] as $object) {
|
@@ -472,7 +488,7 @@ function backwpup_get_backup_files($onlyjobid='') {
|
|
472 |
$files[$filecounter]['jobid']=$jobid;
|
473 |
$files[$filecounter]['file']=$ftpfiles;
|
474 |
$files[$filecounter]['filename']=basename($ftpfiles);
|
475 |
-
$files[$filecounter]['downloadurl']="ftp://"
|
476 |
$files[$filecounter]['filesize']=ftp_size($ftp_conn_id,$ftpfiles);
|
477 |
$files[$filecounter]['time']=ftp_mdtm($ftp_conn_id,$ftpfiles);
|
478 |
$filecounter++;
|
@@ -527,13 +543,20 @@ function backwpup_get_aws_buckets($args='') {
|
|
527 |
else
|
528 |
return;
|
529 |
}
|
530 |
-
if ($buckets->status
|
531 |
-
echo '<span id="awsBucket" style="color:red;">'.__('
|
532 |
if ($ajax)
|
533 |
die();
|
534 |
else
|
535 |
return;
|
536 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
537 |
echo '<select name="awsBucket" id="awsBucket">';
|
538 |
foreach ($buckets->body->Buckets->Bucket as $bucket) {
|
539 |
echo "<option ".selected(strtolower($awsselected),strtolower($bucket->Name),false).">".$bucket->Name."</option>";
|
278 |
if (!isset($jobsettings['dropemaxbackups']) or !is_int($jobsettings['dropemaxbackups']))
|
279 |
$jobsettings['dropemaxbackups']=0;
|
280 |
|
281 |
+
if (!isset($jobsettings['sugaruser']) or !is_string($jobsettings['sugaruser']))
|
282 |
+
$jobsettings['sugaruser']='';
|
283 |
+
|
284 |
+
if (!isset($jobsettings['sugarpass']) or !is_string($jobsettings['sugarpass']))
|
285 |
+
$jobsettings['sugarpass']='';
|
286 |
+
|
287 |
+
if (!isset($jobsettings['sugardir']) or !is_string($jobsettings['sugardir']) or $jobsettings['sugardir']=='/')
|
288 |
+
$jobsettings['sugardir']='';
|
289 |
+
$jobsettings['sugardir']=trailingslashit(str_replace('//','/',str_replace('\\','/',trim($jobsettings['sugardir']))));
|
290 |
+
if (substr($jobsettings['sugardir'],0,1)=='/')
|
291 |
+
$jobsettings['sugardir']=substr($jobsettings['sugardir'],1);
|
292 |
+
|
293 |
+
if (!isset($jobsettings['sugarmaxbackups']) or !is_int($jobsettings['sugarmaxbackups']))
|
294 |
+
$jobsettings['sugarmaxbackups']=0;
|
295 |
+
|
296 |
+
|
297 |
+
|
298 |
if (!is_string($jobsettings['mailaddress']) or false === $pos=strpos($jobsettings['mailaddress'],'@') or false === strpos($jobsettings['mailaddress'],'.',$pos))
|
299 |
$jobsettings['mailaddress']='';
|
300 |
|
318 |
if (!class_exists('CF_Authentication'))
|
319 |
require_once(dirname(__FILE__).'/libs/rackspace/cloudfiles.php');
|
320 |
if (!class_exists('Dropbox') and function_exists('json_decode'))
|
321 |
+
require_once(dirname(__FILE__).'/libs/dropbox/dropbox.php');
|
322 |
}
|
323 |
|
324 |
foreach ($jobs as $jobid => $jobvalue) { //go job by job
|
355 |
if (!empty($jobvalue['dropetoken']) and !empty($jobvalue['dropesecret'])) {
|
356 |
try {
|
357 |
$dropbox = new Dropbox(BACKWPUP_DROPBOX_APP_KEY, BACKWPUP_DROPBOX_APP_SECRET);
|
358 |
+
$dropbox->setOAuthTokens($jobvalue['dropetoken'],$jobvalue['dropesecret']);
|
|
|
359 |
$contents = $dropbox->metadata($jobvalue['dropedir']);
|
360 |
if (is_array($contents)) {
|
361 |
foreach ($contents['contents'] as $object) {
|
488 |
$files[$filecounter]['jobid']=$jobid;
|
489 |
$files[$filecounter]['file']=$ftpfiles;
|
490 |
$files[$filecounter]['filename']=basename($ftpfiles);
|
491 |
+
$files[$filecounter]['downloadurl']="ftp://".rawurlencode($jobvalue['ftpuser']).":".rawurlencode(base64_decode($jobvalue['ftppass']))."@".$jobvalue['ftphost'].rawurlencode($ftpfiles);
|
492 |
$files[$filecounter]['filesize']=ftp_size($ftp_conn_id,$ftpfiles);
|
493 |
$files[$filecounter]['time']=ftp_mdtm($ftp_conn_id,$ftpfiles);
|
494 |
$filecounter++;
|
543 |
else
|
544 |
return;
|
545 |
}
|
546 |
+
if ($buckets->status>=200 and $buckets->status<300) {
|
547 |
+
echo '<span id="awsBucket" style="color:red;">'.__('S3 Message:','backwpup').' '.$buckets->status.': '.$buckets->body->Message.'</span>';
|
548 |
if ($ajax)
|
549 |
die();
|
550 |
else
|
551 |
return;
|
552 |
}
|
553 |
+
if (empty($buckets->body->Buckets->Bucket)) {
|
554 |
+
echo '<span id="awsBucket" style="color:red;">'.__('No Buckets found!','backwpup').'</span>';
|
555 |
+
if ($ajax)
|
556 |
+
die();
|
557 |
+
else
|
558 |
+
return;
|
559 |
+
}
|
560 |
echo '<select name="awsBucket" id="awsBucket">';
|
561 |
foreach ($buckets->body->Buckets->Bucket as $bucket) {
|
562 |
echo "<option ".selected(strtolower($awsselected),strtolower($bucket->Name),false).">".$bucket->Name."</option>";
|
backwpup.php
CHANGED
@@ -4,7 +4,7 @@ Plugin Name: BackWPup
|
|
4 |
Plugin URI: http://danielhuesken.de/portfolio/backwpup/
|
5 |
Description: Backup and more of your WordPress Blog Database and Files.
|
6 |
Author: Daniel Hüsken
|
7 |
-
Version: 1.6.
|
8 |
Author URI: http://danielhuesken.de
|
9 |
Text Domain: backwpup
|
10 |
Domain Path: /lang/
|
@@ -34,7 +34,7 @@ if ( !defined('ABSPATH') )
|
|
34 |
//Set plugin dirname
|
35 |
define('BACKWPUP_PLUGIN_BASEDIR', dirname(plugin_basename(__FILE__)));
|
36 |
//Set Plugin Version
|
37 |
-
define('BACKWPUP_VERSION', '1.6.
|
38 |
//Set User Capability
|
39 |
define('BACKWPUP_USER_CAPABILITY', '10');
|
40 |
//Set useable destinations
|
@@ -42,7 +42,6 @@ if (!defined('BACKWPUP_DESTS'))
|
|
42 |
define('BACKWPUP_DESTS', 'S3,RSC,FTP,DROPBOX,MSAZURE');
|
43 |
//Set Dropbox Aplication Keys
|
44 |
define('BACKWPUP_DROPBOX_APP_KEY', 'q2jbt0unkkc54u2');
|
45 |
-
//Set Dropbox Aplication Keys
|
46 |
define('BACKWPUP_DROPBOX_APP_SECRET', 't5hlbxtz473hchy');
|
47 |
//load Text Domain
|
48 |
load_plugin_textdomain('backwpup', false, BACKWPUP_PLUGIN_BASEDIR.'/lang');
|
4 |
Plugin URI: http://danielhuesken.de/portfolio/backwpup/
|
5 |
Description: Backup and more of your WordPress Blog Database and Files.
|
6 |
Author: Daniel Hüsken
|
7 |
+
Version: 1.6.2
|
8 |
Author URI: http://danielhuesken.de
|
9 |
Text Domain: backwpup
|
10 |
Domain Path: /lang/
|
34 |
//Set plugin dirname
|
35 |
define('BACKWPUP_PLUGIN_BASEDIR', dirname(plugin_basename(__FILE__)));
|
36 |
//Set Plugin Version
|
37 |
+
define('BACKWPUP_VERSION', '1.6.2');
|
38 |
//Set User Capability
|
39 |
define('BACKWPUP_USER_CAPABILITY', '10');
|
40 |
//Set useable destinations
|
42 |
define('BACKWPUP_DESTS', 'S3,RSC,FTP,DROPBOX,MSAZURE');
|
43 |
//Set Dropbox Aplication Keys
|
44 |
define('BACKWPUP_DROPBOX_APP_KEY', 'q2jbt0unkkc54u2');
|
|
|
45 |
define('BACKWPUP_DROPBOX_APP_SECRET', 't5hlbxtz473hchy');
|
46 |
//load Text Domain
|
47 |
load_plugin_textdomain('backwpup', false, BACKWPUP_PLUGIN_BASEDIR.'/lang');
|
readme.txt
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
=== BackWPup ===
|
2 |
Contributors: danielhuesken
|
3 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=daniel%40huesken-net%2ede&item_name=Daniel%20Huesken%20Plugin%20Donation&item_number=BackWPup&no_shipping=0&no_note=1&tax=0&bn=PP%2dDonationsBF&charset=UTF%2d8
|
4 |
-
Tags: backup, admin, file, Database, mysql,
|
5 |
Requires at least: 2.8
|
6 |
Tested up to: 3.1.0
|
7 |
-
Stable tag: 1.6.
|
8 |
|
9 |
-
Backup
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
-
|
14 |
|
15 |
* Database Backup
|
16 |
* WordPress XML Export
|
17 |
* Optimize Database
|
18 |
* Check\Repair Database
|
19 |
* File Backup
|
20 |
-
* Backups in zip,tar,tar.gz,tar.bz2 format
|
21 |
* Store backup to Folder
|
22 |
* Store backup to FTP Server
|
23 |
* Store backup to Amazon S3
|
24 |
* Store backup to Microsoft Azure (Blob)
|
25 |
* Store backup to RackSpaceCloud
|
26 |
* Store backup to DropBox
|
27 |
-
* Send Log/Backup by
|
28 |
|
29 |
|
30 |
-
|
31 |
|
32 |
|
33 |
== Installation ==
|
@@ -39,19 +39,19 @@ I can give no WARRANTY to any backups...
|
|
39 |
== Frequently Asked Questions ==
|
40 |
= Requires =
|
41 |
* PHP 5.2.0
|
42 |
-
* WordPress 2.8
|
43 |
-
* curl (for Amazon S3, MS Azur, RackSpace,Dropbox Support)
|
44 |
* gzip (for PCLZIP and gzip archives)
|
45 |
* bzip2 (for bzip2 archives)
|
46 |
|
47 |
-
= Where is the Database dump File =
|
48 |
-
in the root folder of the
|
49 |
|
50 |
-
= Where is the WordPress Export File =
|
51 |
-
in the root folder of the
|
52 |
|
53 |
= Zip File Support =
|
54 |
-
Plugin
|
55 |
|
56 |
= Maintenance Mode =
|
57 |
Supported Plugins
|
@@ -59,40 +59,40 @@ Supported Plugins
|
|
59 |
* wp-maintenance-mode
|
60 |
* WordPress .maintenance file
|
61 |
|
62 |
-
|
63 |
|
64 |
= Restore a Blog Database =
|
65 |
-
Copy the <i>DBName</i>.sql in the root folder of the
|
66 |
-
You can use PHPMyAdmin
|
67 |
|
68 |
-
= Abnormal Script
|
69 |
-
Webserver normally
|
70 |
-
PHP normally
|
71 |
|
72 |
= Memory usage =
|
73 |
-
* The
|
74 |
-
* The
|
75 |
-
* PCLZIP lib
|
76 |
-
*
|
77 |
|
78 |
-
=
|
79 |
-
I have
|
80 |
-
|
81 |
|
82 |
= FTP Warnings =
|
83 |
-
Please deactivate
|
84 |
|
85 |
-
=
|
86 |
-
You can set in wp-config.php
|
87 |
-
<i>define('BACKWPUP_DESTS',
|
88 |
-
all listed destinations are
|
89 |
Destinations are:
|
90 |
-
* MAIL = mail (can't
|
91 |
-
* DIR = Directory (can't
|
92 |
* S3 = Amazon S3
|
93 |
* RSC = RackSpaceCloud
|
94 |
* FTP = FTP Server
|
95 |
-
* DROPBOX =
|
96 |
* MSAZURE = Microsoft Azure (Blob)
|
97 |
|
98 |
== Screenshots ==
|
@@ -100,68 +100,71 @@ Destinations are:
|
|
100 |
1. Job Page
|
101 |
|
102 |
== Changelog ==
|
|
|
|
|
|
|
103 |
= 1.6.1 =
|
104 |
-
* Now use web OAuth login for
|
105 |
-
* Only
|
106 |
-
* Check
|
107 |
-
* fixed bug in tar with file/folder names longer than 100 chars
|
108 |
-
* changed user capability back to '10'
|
109 |
-
* bug fixes for old
|
110 |
-
* English
|
111 |
-
* improvements
|
112 |
* bug fixes
|
113 |
|
114 |
= 1.6.0 =
|
115 |
-
* new
|
116 |
-
* added
|
117 |
-
* renamed functions.php to resolve problems
|
118 |
-
* improvements
|
119 |
|
120 |
= 1.5.5 =
|
121 |
-
*
|
122 |
-
* Added AWS
|
123 |
* Added Microsoft Azure (Blob) as backup destination
|
124 |
* bug fixes
|
125 |
|
126 |
= 1.5.2 =
|
127 |
* changes for user checking
|
128 |
-
* removed
|
129 |
|
130 |
= 1.5.1 =
|
131 |
* changed user capability from '10' to 'export'
|
132 |
-
*
|
133 |
|
134 |
= 1.5.0 =
|
135 |
* use AWS SDK ver.1.2.4 now for Amazon S3
|
136 |
-
* Update
|
137 |
-
* Added
|
138 |
-
* Download link for last backup in
|
139 |
-
* Link for last
|
140 |
-
* Logs can now compressed
|
141 |
* Backup destinations can now be disabled (see help)
|
142 |
* Bug fixes and improvements
|
143 |
|
144 |
= 1.4.1 =
|
145 |
-
*
|
146 |
-
* fixed problem on send log with
|
147 |
* Security fix (thanks Massa Danilo)
|
148 |
|
149 |
= 1.4.0 =
|
150 |
* make SSL-FTP as option
|
151 |
-
* added
|
152 |
|
153 |
= 1.3.6 =
|
154 |
-
* long file list
|
155 |
* Added option to see detailed file list
|
156 |
* removed FTP Alloc command
|
157 |
-
* set FTP normal mode if
|
158 |
-
* remove FTP
|
159 |
* spend file list 2MB free memory
|
160 |
|
161 |
= 1.3.5 =
|
162 |
* fixed problem with folder include
|
163 |
* added option to deactivate FTP passive mode
|
164 |
-
* fixed bug for
|
165 |
|
166 |
= 1.3.4 =
|
167 |
* fixed warning in send mail
|
@@ -169,28 +172,28 @@ Destinations are:
|
|
169 |
|
170 |
= 1.3.3 =
|
171 |
* fixed bug with clear only displayed
|
172 |
-
*
|
173 |
|
174 |
= 1.3.2 =
|
175 |
-
* added
|
176 |
* bug fixes
|
177 |
|
178 |
= 1.3.1 =
|
179 |
-
* added
|
180 |
* removed "LOCK TABLE" in sql dumps
|
181 |
* fixed bug in automatic job abortion
|
182 |
* fixed bug in ABSPATH if it '/'
|
183 |
-
*
|
184 |
-
*
|
185 |
* added link to clear running jobs
|
186 |
|
187 |
= 1.3.0 =
|
188 |
* added S3 new region codes for bucket creation
|
189 |
-
* added S3 REDUCED REDUNDANCY support on
|
190 |
-
* jobs will aborted after 10 min. and can't run twice
|
191 |
* use curl for xml dump and copy if curl not works
|
192 |
-
*
|
193 |
-
* use linux cron based
|
194 |
* added rackspacecloud.com support
|
195 |
* use WP 3.1 table creation
|
196 |
* added plugin checks for folder and new scheduling
|
@@ -208,7 +211,7 @@ Destinations are:
|
|
208 |
* Bug fixes
|
209 |
|
210 |
= 1.1.1 =
|
211 |
-
* fixed S3 lib not found bug again.
|
212 |
* improved reschedule on activation problem.
|
213 |
|
214 |
= 1.1.0 =
|
@@ -237,8 +240,8 @@ Destinations are:
|
|
237 |
* removed some not used code
|
238 |
|
239 |
= 1.0.7 =
|
240 |
-
* added
|
241 |
-
* Fixed bug on S3
|
242 |
* get files form S3 now faster for file deletion
|
243 |
|
244 |
= 1.0.6 =
|
@@ -264,8 +267,8 @@ Destinations are:
|
|
264 |
= 1.0.0 =
|
265 |
* now WordPress Exports to XML can made
|
266 |
* new backup files formats tar, tar.gz, tar.bz2
|
267 |
-
* all job types can
|
268 |
-
* added PHP zip extension support (use
|
269 |
* removed PclZip trace code
|
270 |
* fixed time display and schedule bugs
|
271 |
* added some security
|
@@ -278,15 +281,15 @@ Destinations are:
|
|
278 |
|
279 |
= 0.8.0 =
|
280 |
* Fixed not working default settings on settings page
|
281 |
-
*
|
282 |
* fixed global for $wp_version
|
283 |
* set max execution time to 0 for unlimited
|
284 |
* use WP function to generate options tables
|
285 |
* Backup file list and zip creation changes
|
286 |
* Added support for Amazon S3
|
287 |
* Only works with PHP 5 now
|
288 |
-
* Complete rewrite of job
|
289 |
-
* PHP errors now in
|
290 |
* Log now in files
|
291 |
|
292 |
= 0.7.2 =
|
@@ -307,7 +310,7 @@ Destinations are:
|
|
307 |
|
308 |
= 0.6.5 =
|
309 |
* Prevent direct file loading
|
310 |
-
* job working in
|
311 |
* colored logs
|
312 |
* HTML fixes
|
313 |
* spell check
|
@@ -323,7 +326,7 @@ Destinations are:
|
|
323 |
* use ftp_row for login and other commands
|
324 |
* Add option to send only email on errors
|
325 |
* Internal structure changes
|
326 |
-
* Add option to disable WP-Cron and use
|
327 |
* bug fixes
|
328 |
|
329 |
= 0.6.2 =
|
@@ -333,9 +336,9 @@ Destinations are:
|
|
333 |
* bug fixes and little improvements
|
334 |
|
335 |
= 0.6.1 =
|
336 |
-
* Added setting for
|
337 |
-
* Optimize
|
338 |
-
* Fixed Bug that cron
|
339 |
|
340 |
= 0.6.0 =
|
341 |
* Add Dashboard Widget
|
1 |
=== BackWPup ===
|
2 |
Contributors: danielhuesken
|
3 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=daniel%40huesken-net%2ede&item_name=Daniel%20Huesken%20Plugin%20Donation&item_number=BackWPup&no_shipping=0&no_note=1&tax=0&bn=PP%2dDonationsBF&charset=UTF%2d8
|
4 |
+
Tags: backup, admin, file, Database, mysql, Cron, ftp, S3, export, xml, Rackspace, Cloud, Azure, DropBox
|
5 |
Requires at least: 2.8
|
6 |
Tested up to: 3.1.0
|
7 |
+
Stable tag: 1.6.2
|
8 |
|
9 |
+
Backup your WordPress Database and Files, and more!
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
+
Do backups and more.
|
14 |
|
15 |
* Database Backup
|
16 |
* WordPress XML Export
|
17 |
* Optimize Database
|
18 |
* Check\Repair Database
|
19 |
* File Backup
|
20 |
+
* Backups in zip, tar, tar.gz, tar.bz2 format
|
21 |
* Store backup to Folder
|
22 |
* Store backup to FTP Server
|
23 |
* Store backup to Amazon S3
|
24 |
* Store backup to Microsoft Azure (Blob)
|
25 |
* Store backup to RackSpaceCloud
|
26 |
* Store backup to DropBox
|
27 |
+
* Send Log/Backup by Email
|
28 |
|
29 |
|
30 |
+
** NO WARRANTY SUPPLIED. **
|
31 |
|
32 |
|
33 |
== Installation ==
|
39 |
== Frequently Asked Questions ==
|
40 |
= Requires =
|
41 |
* PHP 5.2.0
|
42 |
+
* WordPress 2.8, works best with 3.1
|
43 |
+
* curl (for Amazon S3, MS Azur, RackSpace, Dropbox Support)
|
44 |
* gzip (for PCLZIP and gzip archives)
|
45 |
* bzip2 (for bzip2 archives)
|
46 |
|
47 |
+
= Where is the Database dump File? =
|
48 |
+
in the root folder of the archive. <i>DBName</i>.sql
|
49 |
|
50 |
+
= Where is the WordPress Export File? =
|
51 |
+
in the root folder of the archive. <i>blogname</i>.wordpress.<i>jjjj-mm-dd</i>.xml
|
52 |
|
53 |
= Zip File Support =
|
54 |
+
Plugin uses zip extension if PHP, if not, uses PCLZIP lib extension
|
55 |
|
56 |
= Maintenance Mode =
|
57 |
Supported Plugins
|
59 |
* wp-maintenance-mode
|
60 |
* WordPress .maintenance file
|
61 |
|
62 |
+
If your site does not come back from Maintenance Mode, switch back from Maintenance Mode by changing the Plugin options or delete the <i>.maintenance</i> file in the install's root folder.
|
63 |
|
64 |
= Restore a Blog Database =
|
65 |
+
Copy the <i>DBName</i>.sql in the root folder of the site and go to the tools tab in the Plugin.
|
66 |
+
You can also use PHPMyAdmin.
|
67 |
|
68 |
+
= Abnormal Script Cancellations =
|
69 |
+
Webserver normally aborts scripts that works longer then 300s.
|
70 |
+
PHP normally aborts scripts that works longer then 30s but the plugin will try to keep this from happening.
|
71 |
|
72 |
= Memory usage =
|
73 |
+
* The plugin is coded to use low memory
|
74 |
+
* The plugin will try to increase memory automatically if needed
|
75 |
+
* PCLZIP lib needs 8MB free memory for zipping
|
76 |
+
* Emailing an archive needs a lot of memory
|
77 |
|
78 |
+
= Email archives =
|
79 |
+
I have built in many options to optimize email archives, but the mailing library uses a lot of memory.
|
80 |
+
You should only send small archives via email.
|
81 |
|
82 |
= FTP Warnings =
|
83 |
+
Please deactivate passive mode and try it again.
|
84 |
|
85 |
+
= Disable some destinations for backups =
|
86 |
+
You can set the following in wp-config.php:
|
87 |
+
<i>define('BACKWPUP_DESTS','S3,RSC,FTP,DROPBOX,MSAZURE');</i>
|
88 |
+
all listed destinations are then disabled.
|
89 |
Destinations are:
|
90 |
+
* MAIL = mail (can't disable)
|
91 |
+
* DIR = Directory (can't disable)
|
92 |
* S3 = Amazon S3
|
93 |
* RSC = RackSpaceCloud
|
94 |
* FTP = FTP Server
|
95 |
+
* DROPBOX = DropBox
|
96 |
* MSAZURE = Microsoft Azure (Blob)
|
97 |
|
98 |
== Screenshots ==
|
100 |
1. Job Page
|
101 |
|
102 |
== Changelog ==
|
103 |
+
= 1.6.2 =
|
104 |
+
* Dropbox improvements and bug fixes
|
105 |
+
|
106 |
= 1.6.1 =
|
107 |
+
* Now use web OAuth login for DropBox! Best thanks to Tijs Verkoyen for his great DropBox class.
|
108 |
+
* Only DropBox OAuth tokens are saved!
|
109 |
+
* Check DropBox Quota/Upload Filesize on Job run
|
110 |
+
* fixed bug in .tar with file/folder names longer than 100 chars
|
111 |
+
* changed user capability back to '10' when working with WP lower than 3.0
|
112 |
+
* bug fixes for old WP versions
|
113 |
+
* English text updates! Best thanks to Marcy Capron.
|
114 |
+
* general improvements
|
115 |
* bug fixes
|
116 |
|
117 |
= 1.6.0 =
|
118 |
+
* new DropBox class to use all functions (download, delete, list)
|
119 |
+
* added useful links in job edit page
|
120 |
+
* renamed functions.php to resolve problems arising from other plugins
|
121 |
+
* general improvements
|
122 |
|
123 |
= 1.5.5 =
|
124 |
+
* Updated AWS SDK to ver.1.2.6 for Amazon S3
|
125 |
+
* Added AWS Region "Northeast" (Japan)
|
126 |
* Added Microsoft Azure (Blob) as backup destination
|
127 |
* bug fixes
|
128 |
|
129 |
= 1.5.2 =
|
130 |
* changes for user checking
|
131 |
+
* removed plugin init action
|
132 |
|
133 |
= 1.5.1 =
|
134 |
* changed user capability from '10' to 'export'
|
135 |
+
* Updated AWS SDK to ver.1.2.5 for Amazon S3
|
136 |
|
137 |
= 1.5.0 =
|
138 |
* use AWS SDK ver.1.2.4 now for Amazon S3
|
139 |
+
* Update Rackspase cloud files to ver.1.7.6
|
140 |
+
* Added job setting import/export
|
141 |
+
* Download link for last backup in jobs tab
|
142 |
+
* Link for last log in jobs tab
|
143 |
+
* Logs can now be compressed
|
144 |
* Backup destinations can now be disabled (see help)
|
145 |
* Bug fixes and improvements
|
146 |
|
147 |
= 1.4.1 =
|
148 |
+
* DropBox changes
|
149 |
+
* fixed problem on send log with email
|
150 |
* Security fix (thanks Massa Danilo)
|
151 |
|
152 |
= 1.4.0 =
|
153 |
* make SSL-FTP as option
|
154 |
+
* added DropBox support (zlli)
|
155 |
|
156 |
= 1.3.6 =
|
157 |
+
* long file list no longer displayed in logs.
|
158 |
* Added option to see detailed file list
|
159 |
* removed FTP Alloc command
|
160 |
+
* set FTP normal mode if passive mode disabled
|
161 |
+
* remove FTP helper function and use FTP PHP functions
|
162 |
* spend file list 2MB free memory
|
163 |
|
164 |
= 1.3.5 =
|
165 |
* fixed problem with folder include
|
166 |
* added option to deactivate FTP passive mode
|
167 |
+
* fixed bug for parsing errors because PHP 5 move PHP 5 functions in a seperate file
|
168 |
|
169 |
= 1.3.4 =
|
170 |
* fixed warning in send mail
|
172 |
|
173 |
= 1.3.3 =
|
174 |
* fixed bug with clear only displayed
|
175 |
+
* fixed bug with Parse Error for some PHP versions
|
176 |
|
177 |
= 1.3.2 =
|
178 |
+
* added changable backup file prefix
|
179 |
* bug fixes
|
180 |
|
181 |
= 1.3.1 =
|
182 |
+
* added file and DB size information
|
183 |
* removed "LOCK TABLE" in sql dumps
|
184 |
* fixed bug in automatic job abortion
|
185 |
* fixed bug in ABSPATH if it '/'
|
186 |
+
* fixed bug in save settings
|
187 |
+
* fixed bugs if no jobs exists
|
188 |
* added link to clear running jobs
|
189 |
|
190 |
= 1.3.0 =
|
191 |
* added S3 new region codes for bucket creation
|
192 |
+
* added S3 REDUCED REDUNDANCY support on backups
|
193 |
+
* jobs will be aborted after 10 min. and can't run twice
|
194 |
* use curl for xml dump and copy if curl not works
|
195 |
+
* increased min. PHP version to 5.2.0, because then all works
|
196 |
+
* use linux cron based scheduling times
|
197 |
* added rackspacecloud.com support
|
198 |
* use WP 3.1 table creation
|
199 |
* added plugin checks for folder and new scheduling
|
211 |
* Bug fixes
|
212 |
|
213 |
= 1.1.1 =
|
214 |
+
* fixed "S3 lib not found" bug again.
|
215 |
* improved reschedule on activation problem.
|
216 |
|
217 |
= 1.1.0 =
|
240 |
* removed some not used code
|
241 |
|
242 |
= 1.0.7 =
|
243 |
+
* added button in Help
|
244 |
+
* Fixed bug on S3 file deletion
|
245 |
* get files form S3 now faster for file deletion
|
246 |
|
247 |
= 1.0.6 =
|
267 |
= 1.0.0 =
|
268 |
* now WordPress Exports to XML can made
|
269 |
* new backup files formats tar, tar.gz, tar.bz2
|
270 |
+
* all job types can be created in one job
|
271 |
+
* added PHP zip extension support (use PclZip only if not supported)
|
272 |
* removed PclZip trace code
|
273 |
* fixed time display and schedule bugs
|
274 |
* added some security
|
281 |
|
282 |
= 0.8.0 =
|
283 |
* Fixed not working default settings on settings page
|
284 |
+
* create .htaccess on Apache and index.html on other Webserver
|
285 |
* fixed global for $wp_version
|
286 |
* set max execution time to 0 for unlimited
|
287 |
* use WP function to generate options tables
|
288 |
* Backup file list and zip creation changes
|
289 |
* Added support for Amazon S3
|
290 |
* Only works with PHP 5 now
|
291 |
+
* Complete rewrite of job as PHP5 class
|
292 |
+
* PHP errors now in backup log
|
293 |
* Log now in files
|
294 |
|
295 |
= 0.7.2 =
|
310 |
|
311 |
= 0.6.5 =
|
312 |
* Prevent direct file loading
|
313 |
+
* job working in iFrame
|
314 |
* colored logs
|
315 |
* HTML fixes
|
316 |
* spell check
|
326 |
* use ftp_row for login and other commands
|
327 |
* Add option to send only email on errors
|
328 |
* Internal structure changes
|
329 |
+
* Add option to disable WP-Cron and use host's cron
|
330 |
* bug fixes
|
331 |
|
332 |
= 0.6.2 =
|
336 |
* bug fixes and little improvements
|
337 |
|
338 |
= 0.6.1 =
|
339 |
+
* Added setting for send email type.
|
340 |
+
* Optimize memory usage again
|
341 |
+
* Fixed Bug that kept cron from working
|
342 |
|
343 |
= 0.6.0 =
|
344 |
* Add Dashboard Widget
|