BackWPup – WordPress Backup Plugin - Version 1.6.2

Version Description

  • Dropbox improvements and bug fixes
Download this release

Release Info

Developer danielhuesken
Plugin Icon 128x128 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 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->create_object($this->job['awsBucket'], $this->job['awsdir'].$this->backupfile, array('fileUpload' => $this->backupdir.$this->backupfile,'acl' => AmazonS3::ACL_PRIVATE,'storage' => $storage))) {//transfere file to 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
- if (filesize($this->backupdir.$this->backupfile)<Microsoft_WindowsAzure_Storage_Blob::MAX_BLOB_SIZE) { //for files bigger tha 64MB
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->setOAuthToken($this->job['dropetoken']);
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->filesPost($this->job['dropedir'], $this->backupdir.$this->backupfile);
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($_GET['oauth_token']);
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>&nbsp;&nbsp;&nbsp;&nbsp;<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->setOAuthToken($jobvalue['dropetoken']);
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->setOAuthToken($jobs[$jobid]['dropetoken']);
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 base64_decode($dropfile['data']);
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->setOAuthToken($jobvalue['dropetoken']);
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://".$jobvalue['ftpuser'].":".base64_decode($jobvalue['ftppass'])."@".$jobvalue['ftphost'].$ftpfiles;
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!=200) {
531
- echo '<span id="awsBucket" style="color:red;">'.__('No Buckets found!','backwpup').'</span>';
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&uuml;sken
7
- Version: 1.6.1
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.1');
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&uuml;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, cron, ftp, S3, export, xml, Rackspase, cloud, azure, dropbox
5
  Requires at least: 2.8
6
  Tested up to: 3.1.0
7
- Stable tag: 1.6.1
8
 
9
- Backup and more of your WordPress Blog Database and Files
10
 
11
  == Description ==
12
 
13
- Backup and more your Blog.
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
- I can give no WARRANTY to any backups...
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 better 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 use PCLZIP lib if PHP not uses zip extension
55
 
56
  = Maintenance Mode =
57
  Supported Plugins
@@ -59,40 +59,40 @@ Supported Plugins
59
  * wp-maintenance-mode
60
  * WordPress .maintenance file
61
 
62
- if your Blog do not come back from Maintenance Mode switch back from Maintenance Mode by changing the Plugin options or delete the <i>.maintenance</i> file in Blog root folder.
63
 
64
  = Restore a Blog Database =
65
- Copy the <i>DBName</i>.sql in the root folder of the Blog and go to the tools tab in the Plugin.
66
- You can use PHPMyAdmin also.
67
 
68
- = Abnormal Script aborts =
69
- Webserver normally abort Scrips that works longer then 300s.
70
- PHP normally abort Script that works longer then 30s but the Plugin try too switch off the abortion.
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 need 8MB free Memory for zipping
76
- * Mail a archive need many Memory
77
 
78
- = Mail archives =
79
- I have build in many options to Optimize the Mailing but the mailing lib uses high Memory.
80
- Place mail only little archives
81
 
82
  = FTP Warnings =
83
- Please deactivate Pasive Mode and try it again.
84
 
85
- = Disabe some destionations for Backups =
86
- You can set in wp-config.php the following:
87
- <i>define('BACKWPUP_DESTS', 'S3,RSC,FTP,DROPBOX');</i>
88
- all listed destinations are allowed than.
89
  Destinations are:
90
- * MAIL = mail (can't excluded)
91
- * DIR = Directory (can't excluded)
92
  * S3 = Amazon S3
93
  * RSC = RackSpaceCloud
94
  * FTP = FTP Server
95
- * DROPBOX = 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 Dropbox! Best thaks to Tijs Verkoyen for his dropbox class.
105
- * Only Dropbox OAuth tokens are saved!
106
- * Check Dropbox Quota/Upload Filesize on Job run
107
- * fixed bug in tar with file/folder names longer than 100 chars
108
- * changed user capability back to '10' because working with WP lower than 3.0
109
- * bug fixes for old WordPress versions
110
- * English Text updates! Best thaks to Marcy Capron.
111
- * improvements
112
  * bug fixes
113
 
114
  = 1.6.0 =
115
- * new dropbox class to use all functions (download, delete, list)
116
- * added usefull inks in job edit page
117
- * renamed functions.php to resolve problems with false includes of other plugins
118
- * improvements
119
 
120
  = 1.5.5 =
121
- * Updatet AWS SDK to ver.1.2.6 for Amazon S3
122
- * Added AWS Regin "Northeast" (Japan)
123
  * Added Microsoft Azure (Blob) as backup destination
124
  * bug fixes
125
 
126
  = 1.5.2 =
127
  * changes for user checking
128
- * removed Plugin init action
129
 
130
  = 1.5.1 =
131
  * changed user capability from '10' to 'export'
132
- * Updatet AWS SDK to ver.1.2.5 for Amazon S3
133
 
134
  = 1.5.0 =
135
  * use AWS SDK ver.1.2.4 now for Amazon S3
136
- * Update rackspase cloud files to ver.1.7.6
137
- * Added Job setteing import/export
138
- * Download link for last backup in Jobs tab
139
- * Link for last Log in Jobs tab
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
- * Dropbox changes
146
- * fixed problem on send log with mail
147
  * Security fix (thanks Massa Danilo)
148
 
149
  = 1.4.0 =
150
  * make SSL-FTP as option
151
- * added Dropbox support (zlli)
152
 
153
  = 1.3.6 =
154
- * long file list not longer displayed in logs.
155
  * Added option to see detailed file list
156
  * removed FTP Alloc command
157
- * set FTP normal mode if pasive mode disabled
158
- * remove FTP heler function and use FTP PHP functions
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 prasing errors because PHP 5 move PHP 5 functions in a seperate file
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
- * fiex bug with Parse Error for some php versions
173
 
174
  = 1.3.2 =
175
- * added changeble backup file prefix
176
  * bug fixes
177
 
178
  = 1.3.1 =
179
- * added File and DB size information
180
  * removed "LOCK TABLE" in sql dumps
181
  * fixed bug in automatic job abortion
182
  * fixed bug in ABSPATH if it '/'
183
- * fiexd bug in save settings
184
- * fiexd bugs if no jobs exists
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 put Backups
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
- * increasd min. PHP version to 5.2.0, because than all works
193
- * use linux cron based scheduing times
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 flattr button in Help
241
- * Fixed bug on S3 File deletion
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 made in one job
268
- * added PHP zip extension support (use pclzip only if not supported)
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
- * crate .htaccsses on Apache and index.html on other Webserver
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 doing as PHP5 class
289
- * PHP errors now in Backup log
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 iframe
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 Hosters cron
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 Send Mail type.
337
- * Optimize Memory usage again
338
- * Fixed Bug that cron not work
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