XCloner – Backup and Restore - Version 3.1.3

Version Description

  • XSS fix
Download this release

Release Info

Developer xcloner
Plugin Icon 128x128 XCloner – Backup and Restore
Version 3.1.3
Comparing to
See all releases

Code changes from version 3.1.2 to 3.1.3

Files changed (3) hide show
  1. classes/DropboxClient.php +207 -194
  2. readme.txt +4 -1
  3. xcloner.php +1 -1
classes/DropboxClient.php CHANGED
@@ -1,73 +1,76 @@
1
  <?php
2
- /**
3
  * DropPHP - A simple Dropbox client that works without cURL.
4
  *
5
  * http://fabi.me/en/php-projects/dropphp-dropbox-api-client/
6
- *
7
- *
8
  * @author Fabian Schlieper <fabian@fabi.me>
9
- * @copyright Fabian Schlieper 2012
10
- * @version 1.6
11
  * @license See LICENSE
12
  *
13
  */
14
-
15
  require_once(dirname(__FILE__)."/OAuthSimple.php");
16
 
17
  class DropboxClient {
18
-
19
  const API_URL = "https://api.dropbox.com/1/";
20
  const API_CONTENT_URL = "https://api-content.dropbox.com/1/";
21
-
22
  const BUFFER_SIZE = 4096;
23
-
24
  const MAX_UPLOAD_CHUNK_SIZE = 150000000; // 150MB
25
-
26
  const UPLOAD_CHUNK_SIZE = 4000000; // 4MB
27
 
28
- private $appParams;
29
  private $consumerToken;
30
-
31
  private $requestToken;
32
  private $accessToken;
33
-
34
  private $locale;
35
  private $rootPath;
36
-
37
  private $useCurl;
38
-
39
  function __construct ($app_params, $locale = "en"){
40
  $this->appParams = $app_params;
41
  if(empty($app_params['app_key']))
42
  throw new DropboxException("App Key is empty!");
43
-
44
- $this->consumerToken = array('t' => $this->appParams['app_key'], 's' => $this->appParams['app_secret']);
45
  $this->locale = $locale;
46
  $this->rootPath = empty($app_params['app_full_access']) ? "sandbox" : "dropbox";
47
-
48
  $this->requestToken = null;
49
  $this->accessToken = null;
50
-
51
  $this->useCurl = function_exists('curl_init');
52
  }
53
-
54
- /**
 
 
 
55
  * Sets whether to use cURL if its available or PHP HTTP wrappers otherwise
56
- *
57
  * @access public
58
  * @return boolean Whether to actually use cURL (always false if not installed)
59
- */
60
  public function SetUseCUrl($use_it)
61
  {
62
- return ($this->useCurl = $use_it && function_exists('curl_init'));
63
  }
64
-
65
  // ##################################################
66
  // Authorization
67
-
68
- /**
69
  * Step 1 of authentication process. Retrieves a request token or returns a previously retrieved one.
70
- *
71
  * @access public
72
  * @param boolean $get_new_token Optional (default false). Wether to retrieve a new request token.
73
  * @return array Request Token array.
@@ -76,31 +79,31 @@ class DropboxClient {
76
  {
77
  if(!empty($this->requestToken) && !$get_new_token)
78
  return $this->requestToken;
79
-
80
  $rt = $this->authCall("oauth/request_token");
81
  if(empty($rt) || empty($rt['oauth_token']))
82
  throw new DropboxException('Could not get request token!');
83
 
84
  return ($this->requestToken = array('t'=>$rt['oauth_token'], 's'=>$rt['oauth_token_secret']));
85
  }
86
-
87
- /**
88
  * Step 2. Returns a URL the user must be redirected to in order to connect the app to their Dropbox account
89
- *
90
  * @access public
91
  * @param string $return_url URL users are redirected after authorization
92
  * @return string URL
93
  */
94
  public function BuildAuthorizeUrl($return_url)
95
  {
96
- $rt = $this->GetRequestToken();
97
  if(empty($rt) || empty($rt['t'])) throw new DropboxException('Request Token Invalid ('.print_r($rt,true).').');
98
  return "https://www.dropbox.com/1/oauth/authorize?oauth_token=".$rt['t']."&oauth_callback=".urlencode($return_url);
99
  }
100
-
101
- /**
102
  * Step 3. Acquires an access token. This is the final step of authentication.
103
- *
104
  * @access public
105
  * @param array $request_token Optional. The previously retrieved request token. This parameter can only be skipped if the DropboxClient object has been (de)serialized.
106
  * @return array Access Token array.
@@ -108,20 +111,20 @@ class DropboxClient {
108
  public function GetAccessToken($request_token = null)
109
  {
110
  if(!empty($this->accessToken)) return $this->accessToken;
111
-
112
- if(empty($request_token)) $request_token = $this->requestToken;
113
- if(empty($request_token)) throw new DropboxException('Request token required!');
114
-
115
  $at = $this->authCall("oauth/access_token", $request_token);
116
  if(empty($at))
117
  throw new DropboxException(sprintf('Could not get access token! (request token: %s)', $request_token['t']));
118
-
119
  return ($this->accessToken = array('t'=>$at['oauth_token'], 's'=>$at['oauth_token_secret']));
120
  }
121
-
122
- /**
123
  * Sets a previously retrieved (and stored) access token.
124
- *
125
  * @access public
126
  * @param string|object $token The Access Token
127
  * @return none
@@ -130,79 +133,79 @@ class DropboxClient {
130
  {
131
  if(empty($token['t']) || empty($token['s'])) throw new DropboxException('Passed invalid access token.');
132
  $this->accessToken = $token;
133
- }
134
-
135
- /**
136
  * Checks if an access token has been set.
137
- *
138
  * @access public
139
  * @return boolean Authorized or not
140
  */
141
  public function IsAuthorized()
142
  {
143
- if(empty($this->accessToken)) return false;
144
  return true;
145
  }
146
-
147
-
148
  // ##################################################
149
  // API Functions
150
-
151
-
152
- /**
153
  * Retrieves information about the user's account.
154
- *
155
  * @access public
156
  * @return object Account info object. See https://www.dropbox.com/developers/reference/api#account-info
157
- */
158
  public function GetAccountInfo()
159
  {
160
  return $this->apiCall("account/info", "GET");
161
  }
162
-
163
-
164
- /**
165
  * Get file list of a dropbox folder.
166
- *
167
  * @access public
168
  * @param string|object $dropbox_path Dropbox path of the folder
169
- * @return array An array with metadata of files/folders keyed by paths
170
- */
171
  public function GetFiles($dropbox_path='', $recursive=false, $include_deleted=false)
172
  {
173
  if(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path;
174
  return $this->getFileTree($dropbox_path, $include_deleted, $recursive ? 1000 : 0);
175
  }
176
-
177
- /**
178
  * Get file or folder metadata
179
- *
180
  * @access public
181
  * @param $dropbox_path string Dropbox path of the file or folder
182
- */
183
  public function GetMetadata($dropbox_path, $include_deleted=false, $rev=null)
184
  {
185
  if(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path;
186
  return $this->apiCall("metadata/$this->rootPath/$dropbox_path", "GET", compact('include_deleted','rev'));
187
  }
188
-
189
- /**
190
  * Download a file to the webserver
191
- *
192
  * @access public
193
- * @param string|object $dropbox_file Dropbox path or metadata object of the file to download.
194
  * @param string $dest_path Local path for destination
195
  * @param string $rev Optional. The revision of the file to retrieve. This defaults to the most recent revision.
196
  * @param callback $progress_changed_callback Optional. Callback that will be called during download with 2 args: 1. bytes loaded, 2. file size
197
  * @return object Dropbox file metadata
198
- */
199
  public function DownloadFile($dropbox_file, $dest_path='', $rev=null, $progress_changed_callback = null)
200
  {
201
  if(is_object($dropbox_file) && !empty($dropbox_file->path))
202
  $dropbox_file = $dropbox_file->path;
203
-
204
  if(empty($dest_path)) $dest_path = basename($dropbox_file);
205
-
206
  $url = $this->cleanUrl(self::API_CONTENT_URL."/files/$this->rootPath/$dropbox_file")
207
  . (!empty($rev) ? ('?'.http_build_query(array('rev' => $rev),'','&')) : '');
208
  $context = $this->createRequestContext($url, "GET");
@@ -212,7 +215,7 @@ class DropboxClient {
212
  @fclose($rh);
213
  throw new DropboxException("Could not create file $dest_path !");
214
  }
215
-
216
  if($this->useCurl) {
217
  curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
218
  curl_setopt($context, CURLOPT_RETURNTRANSFER, true);
@@ -220,17 +223,17 @@ class DropboxClient {
220
  $response_headers = array();
221
  self::execCurlAndClose($context, $response_headers);
222
  fclose($fh);
223
- $meta = self::getMetaFromHeaders($response_headers);
224
  $bytes_loaded = filesize($dest_path);
225
  } else {
226
  $rh = @fopen($url, 'rb', false, $context); // read binary
227
  if($rh === false)
228
  throw new DropboxException("HTTP request to $url failed!");
229
-
230
-
231
  // get file meta from HTTP header
232
  $s_meta = stream_get_meta_data($rh);
233
- $meta = self::getMetaFromHeaders($s_meta['wrapper_data']);
234
  $bytes_loaded = 0;
235
  while (!feof($rh)) {
236
  if(($s=fwrite($fh, fread($rh, self::BUFFER_SIZE))) === false) {
@@ -243,85 +246,85 @@ class DropboxClient {
243
  call_user_func($progress_changed_callback, $bytes_loaded, $meta->bytes);
244
  }
245
  }
246
-
247
  fclose($rh);
248
  fclose($fh);
249
  }
250
-
251
  if($meta->bytes != $bytes_loaded)
252
- throw new DropboxException("Download size mismatch! (header:{$meta->bytes} vs actual:{$bytes_loaded}");
253
-
254
  return $meta;
255
  }
256
-
257
- /**
258
  * Upload a file to dropbox
259
- *
260
  * @access public
261
  * @param $src_file string Local file to upload
262
  * @param $dropbox_path string Dropbox path for destination
263
  * @return object Dropbox file metadata
264
- */
265
  public function UploadFile($src_file, $dropbox_path='', $overwrite=true, $parent_rev=null)
266
  {
267
  if(empty($dropbox_path)) $dropbox_path = basename($src_file);
268
  elseif(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path;
269
-
 
 
 
 
 
 
 
 
 
 
270
  $file_size = filesize($src_file);
271
-
272
  if($file_size > self::MAX_UPLOAD_CHUNK_SIZE)
273
- {
274
  $fh = fopen($src_file,'rb');
275
  if($fh === false)
276
  throw new DropboxException();
277
-
278
  $upload_id = null;
279
  $offset = 0;
280
 
281
-
282
- while(!feof($fh)) {
283
  $url = $this->cleanUrl(self::API_CONTENT_URL."/chunked_upload").'?'.http_build_query(compact('upload_id', 'offset'),'','&');
284
-
285
- if($this->useCurl) {
286
- $context = $this->createRequestContext($url, "PUT");
 
287
  curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
288
- curl_setopt($context, CURLOPT_PUT, 1);
289
- curl_setopt($context, CURLOPT_INFILE, $fh);
290
- $chunk_size = min(self::UPLOAD_CHUNK_SIZE, $file_size - $offset);
291
- $offset += $chunk_size;
292
- curl_setopt($context, CURLOPT_INFILESIZE, $chunk_size);
293
  $response = json_decode(self::execCurlAndClose($context));
294
-
295
- fseek($fh,$offset);
296
- if($offset >= $file_size)
297
- break;
298
  } else {
299
- $content = fread($fh, self::UPLOAD_CHUNK_SIZE);
300
-
301
- $context = $this->createRequestContext($url, "PUT", $content);
302
- $offset += strlen($content);
303
- unset($content);
304
-
305
  $response = json_decode(file_get_contents($url, false, $context));
306
  }
 
 
307
  unset($context);
308
-
 
 
309
  if(empty($upload_id)) {
310
  $upload_id = $response->upload_id;
311
  if(empty($upload_id)) throw new DropboxException("Upload ID empty!");
312
  }
 
 
313
  }
314
-
315
  @fclose($fh);
316
-
317
- $this->useCurl = $prev_useCurl;
318
-
319
  return $this->apiCall("commit_chunked_upload/$this->rootPath/$dropbox_path", "POST", compact('overwrite','parent_rev','upload_id'), true);
320
  }
321
-
322
  $query = http_build_query(array_merge(compact('overwrite', 'parent_rev'), array('locale' => $this->locale)),'','&');
323
  $url = $this->cleanUrl(self::API_CONTENT_URL."/files_put/$this->rootPath/$dropbox_path")."?$query";
324
-
325
  if($this->useCurl) {
326
  $context = $this->createRequestContext($url, "PUT");
327
  curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
@@ -331,18 +334,18 @@ class DropboxClient {
331
  curl_setopt($context, CURLOPT_INFILESIZE, filesize($src_file));
332
  $meta = json_decode(self::execCurlAndClose($context));
333
  fclose($fh);
334
- return $meta;
335
  } else {
336
  $content = file_get_contents($src_file);
337
  if(strlen($content) == 0)
338
  throw new DropboxException("Could not read file $src_file or file is empty!");
339
-
340
  $context = $this->createRequestContext($url, "PUT", $content);
341
-
342
- return json_decode(file_get_contents($url, false, $context));
343
  }
344
  }
345
-
346
  /**
347
  * Get thumbnail for a specified image
348
  *
@@ -357,13 +360,13 @@ class DropboxClient {
357
  if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
358
  $url = $this->cleanUrl(self::API_CONTENT_URL."thumbnails/$this->rootPath/$dropbox_file")
359
  . '?' . http_build_query(array('format' => $format, 'size' => $size),'','&');
360
- $context = $this->createRequestContext($url, "GET");
361
-
362
  if($this->useCurl) {
363
  curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
364
  curl_setopt($context, CURLOPT_RETURNTRANSFER, true);
365
  }
366
-
367
  $thumb = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, NULL, $context);
368
 
369
  if($echo) {
@@ -372,11 +375,11 @@ class DropboxClient {
372
  unset($thumb);
373
  return;
374
  }
375
-
376
  return $thumb;
377
  }
378
-
379
-
380
  function GetLink($dropbox_file, $preview=true, $short=true, &$expires=null)
381
  {
382
  if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
@@ -384,29 +387,29 @@ class DropboxClient {
384
  $expires = strtotime($url->expires);
385
  return $url->url;
386
  }
387
-
388
  function Delta($cursor)
389
  {
390
  return $this->apiCall("delta", "POST", compact('cursor'));
391
  }
392
-
393
  function GetRevisions($dropbox_file, $rev_limit=10)
394
  {
395
  if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
396
  return $this->apiCall("revisions/$this->rootPath/$dropbox_file", "GET", compact('rev_limit'));
397
  }
398
-
399
  function Restore($dropbox_file, $rev)
400
  {
401
  if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
402
  return $this->apiCall("restore/$this->rootPath/$dropbox_file", "POST", compact('rev'));
403
  }
404
-
405
  function Search($path, $query, $file_limit=1000, $include_deleted=false)
406
  {
407
  return $this->apiCall("search/$this->rootPath/$path", "POST", compact('query','file_limit','include_deleted'));
408
  }
409
-
410
  function GetCopyRef($dropbox_file, &$expires=null)
411
  {
412
  if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
@@ -414,56 +417,56 @@ class DropboxClient {
414
  $expires = strtotime($ref->expires);
415
  return $ref->copy_ref;
416
  }
417
-
418
-
419
  function Copy($from_path, $to_path, $copy_ref=false)
420
  {
421
  if(is_object($from_path) && !empty($from_path->path)) $from_path = $from_path->path;
422
  return $this->apiCall("fileops/copy", "POST", array('root'=> $this->rootPath, ($copy_ref ? 'from_copy_ref' : 'from_path') => $from_path, 'to_path' => $to_path));
423
  }
424
-
425
- /**
426
  * Creates a new folder in the DropBox
427
- *
428
  * @access public
429
  * @param $path string The path to the new folder to create
430
  * @return object Dropbox folder metadata
431
- */
432
  function CreateFolder($path)
433
  {
434
  return $this->apiCall("fileops/create_folder", "POST", array('root'=> $this->rootPath, 'path' => $path));
435
  }
436
-
437
- /**
438
  * Delete file or folder
439
- *
440
  * @access public
441
  * @param $path mixed The path or metadata of the file/folder to be deleted.
442
  * @return object Dropbox metadata of deleted file or folder
443
- */
444
  function Delete($path)
445
  {
446
  if(is_object($path) && !empty($path->path)) $path = $path->path;
447
  return $this->apiCall("fileops/delete", "POST", array('locale' =>null, 'root'=> $this->rootPath, 'path' => $path));
448
  }
449
-
450
  function Move($from_path, $to_path)
451
  {
452
  if(is_object($from_path) && !empty($from_path->path)) $from_path = $from_path->path;
453
  return $this->apiCall("fileops/move", "POST", array('root'=> $this->rootPath, 'from_path' => $from_path, 'to_path' => $to_path));
454
  }
455
-
456
  function getFileTree($path="", $include_deleted = false, $max_depth = 0, $depth=0)
457
  {
458
  static $files;
459
  if($depth == 0) $files = array();
460
-
461
  $dir = $this->apiCall("metadata/$this->rootPath/$path", "GET", compact('include_deleted'));
462
-
463
  if(empty($dir) || !is_object($dir)) return false;
464
-
465
  if(!empty($dir->error)) throw new DropboxException($dir->error);
466
-
467
  foreach($dir->contents as $item)
468
  {
469
  $files[trim($item->path,'/')] = $item;
@@ -472,42 +475,42 @@ class DropboxClient {
472
  $this->getFileTree($item->path, $include_deleted, $max_depth, $depth+1);
473
  }
474
  }
475
-
476
  return $files;
477
  }
478
-
479
  function createCurl($url, $http_context)
480
  {
481
  $ch = curl_init($url);
482
-
483
  $curl_opts = array(
484
  CURLOPT_HEADER => false, // exclude header from output
485
  //CURLOPT_MUTE => true, // no output!
486
  CURLOPT_RETURNTRANSFER => true, // but return!
487
  CURLOPT_SSL_VERIFYPEER => false,
488
  );
489
-
490
- $curl_opts[CURLOPT_CUSTOMREQUEST] = $http_context['method'];
491
-
492
  if(!empty($http_context['content'])) {
493
  $curl_opts[CURLOPT_POSTFIELDS] =& $http_context['content'];
494
  if(defined("CURLOPT_POSTFIELDSIZE"))
495
  $curl_opts[CURLOPT_POSTFIELDSIZE] = strlen($http_context['content']);
496
  }
497
-
498
  $curl_opts[CURLOPT_HTTPHEADER] = array_map('trim',explode("\n",$http_context['header']));
499
-
500
  curl_setopt_array($ch, $curl_opts);
501
  return $ch;
502
  }
503
-
504
  static private $_curlHeadersRef;
505
  static function _curlHeaderCallback($ch, $header)
506
  {
507
  self::$_curlHeadersRef[] = trim($header);
508
  return strlen($header);
509
  }
510
-
511
  static function &execCurlAndClose($ch, &$out_response_headers = null)
512
  {
513
  if(is_array($out_response_headers)) {
@@ -521,41 +524,41 @@ class DropboxClient {
521
  if($err_no || $res === false) {
522
  throw new DropboxException("cURL-Error ($err_no): $err_str");
523
  }
524
-
525
  return $res;
526
  }
527
-
528
  private function createRequestContext($url, $method, &$content=null, $oauth_token=-1)
529
  {
530
  if($oauth_token === -1)
531
- $oauth_token = $this->accessToken;
532
 
533
  $method = strtoupper($method);
534
  $http_context = array('method'=>$method, 'header'=> '');
535
-
536
  $oauth = new OAuthSimple($this->consumerToken['t'],$this->consumerToken['s']);
537
-
538
  if(empty($oauth_token) && !empty($this->accessToken))
539
  $oauth_token = $this->accessToken;
540
-
541
  if(!empty($oauth_token)) {
542
  $oauth->setParameters(array('oauth_token' => $oauth_token['t']));
543
  $oauth->signatures(array('oauth_secret'=>$oauth_token['s']));
544
  }
545
-
546
  if(!empty($content)) {
547
  $post_vars = ($method != "PUT" && preg_match("/^[a-z][a-z0-9_]*=/i", substr($content, 0, 32)));
548
  $http_context['header'] .= "Content-Length: ".strlen($content)."\r\n";
549
- $http_context['header'] .= "Content-Type: application/".($post_vars?"x-www-form-urlencoded":"octet-stream")."\r\n";
550
- $http_context['content'] =& $content;
551
  if($method == "POST" && $post_vars)
552
- $oauth->setParameters($content);
553
  } elseif($method == "POST") {
554
  // make sure that content-length is always set when post request (otherwise some wrappers fail!)
555
  $http_context['content'] = "";
556
  $http_context['header'] .= "Content-Length: 0\r\n";
557
  }
558
-
559
 
560
  // check for query vars in url and add them to oauth parameters (and remove from path)
561
  $path = $url;
@@ -564,57 +567,67 @@ class DropboxClient {
564
  $oauth->setParameters(substr($query,1));
565
  $path = substr($url, 0, -strlen($query));
566
  }
567
-
568
-
569
  $signed = $oauth->sign(array(
570
  'action' => $method,
571
  'path'=> $path));
572
- //print_r($signed);
573
-
574
  $http_context['header'] .= "Authorization: ".$signed['header']."\r\n";
575
-
576
  return $this->useCurl ? $this->createCurl($url, $http_context) : stream_context_create(array('http'=>$http_context));
577
  }
578
-
579
  private function authCall($path, $request_token=null)
580
  {
581
  $url = $this->cleanUrl(self::API_URL.$path);
582
  $dummy = null;
583
  $context = $this->createRequestContext($url, "POST", $dummy, $request_token);
584
-
585
  $contents = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, false, $context);
586
  $data = array();
587
  parse_str($contents, $data);
588
  return $data;
589
  }
590
-
591
-
 
 
 
 
 
 
 
592
  private function apiCall($path, $method, $params=array(), $content_call=false)
593
  {
594
  $url = $this->cleanUrl(($content_call ? self::API_CONTENT_URL : self::API_URL).$path);
595
  $content = http_build_query(array_merge(array('locale'=>$this->locale), $params),'','&');
596
-
597
  if($method == "GET") {
598
  $url .= "?".$content;
599
  $content = null;
600
  }
601
-
602
  $context = $this->createRequestContext($url, $method, $content);
603
  $json = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, false, $context);
604
  //if($json === false)
605
  // throw new DropboxException();
606
  $resp = json_decode($json);
607
- if(!empty($resp->error))
608
- throw new DropboxException($resp->error);
609
- return $resp;
610
  }
611
-
612
 
613
- private static function getMetaFromHeaders(&$header_array)
 
614
  {
615
- return json_decode(substr(@array_shift(array_filter($header_array, create_function('$s', 'return strpos($s, "x-dropbox-metadata:") === 0;'))), 20));
 
 
 
 
 
616
  }
617
-
618
 
619
  function cleanUrl($url) {
620
  $p = substr($url,0,8);
@@ -626,8 +639,8 @@ class DropboxClient {
626
  }
627
 
628
  class DropboxException extends Exception {
629
-
630
- public function __construct($err = null, $isDebug = FALSE)
631
  {
632
  if(is_null($err)) {
633
  $el = error_get_last();
@@ -642,12 +655,12 @@ class DropboxException extends Exception {
642
  self::display_error($err, TRUE);
643
  }
644
  }
645
-
646
  public static function log_error($err)
647
  {
648
- error_log($err, 0);
649
  }
650
-
651
  public static function display_error($err, $kill = FALSE)
652
  {
653
  print_r($err);
@@ -656,4 +669,4 @@ class DropboxException extends Exception {
656
  die();
657
  }
658
  }
659
- }
1
  <?php
2
+ /**
3
  * DropPHP - A simple Dropbox client that works without cURL.
4
  *
5
  * http://fabi.me/en/php-projects/dropphp-dropbox-api-client/
6
+ *
7
+ *
8
  * @author Fabian Schlieper <fabian@fabi.me>
9
+ * @copyright Fabian Schlieper 2014
10
+ * @version 1.7.1
11
  * @license See LICENSE
12
  *
13
  */
14
+
15
  require_once(dirname(__FILE__)."/OAuthSimple.php");
16
 
17
  class DropboxClient {
18
+
19
  const API_URL = "https://api.dropbox.com/1/";
20
  const API_CONTENT_URL = "https://api-content.dropbox.com/1/";
21
+
22
  const BUFFER_SIZE = 4096;
23
+
24
  const MAX_UPLOAD_CHUNK_SIZE = 150000000; // 150MB
25
+
26
  const UPLOAD_CHUNK_SIZE = 4000000; // 4MB
27
 
28
+ private $appParams;
29
  private $consumerToken;
30
+
31
  private $requestToken;
32
  private $accessToken;
33
+
34
  private $locale;
35
  private $rootPath;
36
+
37
  private $useCurl;
38
+
39
  function __construct ($app_params, $locale = "en"){
40
  $this->appParams = $app_params;
41
  if(empty($app_params['app_key']))
42
  throw new DropboxException("App Key is empty!");
43
+
44
+ $this->consumerToken = array('t' => $this->appParams['app_key'], 's' => $this->appParams['app_secret']);
45
  $this->locale = $locale;
46
  $this->rootPath = empty($app_params['app_full_access']) ? "sandbox" : "dropbox";
47
+
48
  $this->requestToken = null;
49
  $this->accessToken = null;
50
+
51
  $this->useCurl = function_exists('curl_init');
52
  }
53
+
54
+ function __wakeup() {
55
+ $this->useCurl = $this->useCurl && function_exists('curl_init');
56
+ }
57
+ /**
58
  * Sets whether to use cURL if its available or PHP HTTP wrappers otherwise
59
+ *
60
  * @access public
61
  * @return boolean Whether to actually use cURL (always false if not installed)
62
+ */
63
  public function SetUseCUrl($use_it)
64
  {
65
+ return ($this->useCurl = ($use_it && function_exists('curl_init')));
66
  }
67
+
68
  // ##################################################
69
  // Authorization
70
+
71
+ /**
72
  * Step 1 of authentication process. Retrieves a request token or returns a previously retrieved one.
73
+ *
74
  * @access public
75
  * @param boolean $get_new_token Optional (default false). Wether to retrieve a new request token.
76
  * @return array Request Token array.
79
  {
80
  if(!empty($this->requestToken) && !$get_new_token)
81
  return $this->requestToken;
82
+
83
  $rt = $this->authCall("oauth/request_token");
84
  if(empty($rt) || empty($rt['oauth_token']))
85
  throw new DropboxException('Could not get request token!');
86
 
87
  return ($this->requestToken = array('t'=>$rt['oauth_token'], 's'=>$rt['oauth_token_secret']));
88
  }
89
+
90
+ /**
91
  * Step 2. Returns a URL the user must be redirected to in order to connect the app to their Dropbox account
92
+ *
93
  * @access public
94
  * @param string $return_url URL users are redirected after authorization
95
  * @return string URL
96
  */
97
  public function BuildAuthorizeUrl($return_url)
98
  {
99
+ $rt = $this->GetRequestToken();
100
  if(empty($rt) || empty($rt['t'])) throw new DropboxException('Request Token Invalid ('.print_r($rt,true).').');
101
  return "https://www.dropbox.com/1/oauth/authorize?oauth_token=".$rt['t']."&oauth_callback=".urlencode($return_url);
102
  }
103
+
104
+ /**
105
  * Step 3. Acquires an access token. This is the final step of authentication.
106
+ *
107
  * @access public
108
  * @param array $request_token Optional. The previously retrieved request token. This parameter can only be skipped if the DropboxClient object has been (de)serialized.
109
  * @return array Access Token array.
111
  public function GetAccessToken($request_token = null)
112
  {
113
  if(!empty($this->accessToken)) return $this->accessToken;
114
+
115
+ if(empty($request_token)) $request_token = $this->requestToken;
116
+ if(empty($request_token)) throw new DropboxException('Request token required!');
117
+
118
  $at = $this->authCall("oauth/access_token", $request_token);
119
  if(empty($at))
120
  throw new DropboxException(sprintf('Could not get access token! (request token: %s)', $request_token['t']));
121
+
122
  return ($this->accessToken = array('t'=>$at['oauth_token'], 's'=>$at['oauth_token_secret']));
123
  }
124
+
125
+ /**
126
  * Sets a previously retrieved (and stored) access token.
127
+ *
128
  * @access public
129
  * @param string|object $token The Access Token
130
  * @return none
133
  {
134
  if(empty($token['t']) || empty($token['s'])) throw new DropboxException('Passed invalid access token.');
135
  $this->accessToken = $token;
136
+ }
137
+
138
+ /**
139
  * Checks if an access token has been set.
140
+ *
141
  * @access public
142
  * @return boolean Authorized or not
143
  */
144
  public function IsAuthorized()
145
  {
146
+ if(empty($this->accessToken)) return false;
147
  return true;
148
  }
149
+
150
+
151
  // ##################################################
152
  // API Functions
153
+
154
+
155
+ /**
156
  * Retrieves information about the user's account.
157
+ *
158
  * @access public
159
  * @return object Account info object. See https://www.dropbox.com/developers/reference/api#account-info
160
+ */
161
  public function GetAccountInfo()
162
  {
163
  return $this->apiCall("account/info", "GET");
164
  }
165
+
166
+
167
+ /**
168
  * Get file list of a dropbox folder.
169
+ *
170
  * @access public
171
  * @param string|object $dropbox_path Dropbox path of the folder
172
+ * @return array An array with metadata of files/folders keyed by paths
173
+ */
174
  public function GetFiles($dropbox_path='', $recursive=false, $include_deleted=false)
175
  {
176
  if(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path;
177
  return $this->getFileTree($dropbox_path, $include_deleted, $recursive ? 1000 : 0);
178
  }
179
+
180
+ /**
181
  * Get file or folder metadata
182
+ *
183
  * @access public
184
  * @param $dropbox_path string Dropbox path of the file or folder
185
+ */
186
  public function GetMetadata($dropbox_path, $include_deleted=false, $rev=null)
187
  {
188
  if(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path;
189
  return $this->apiCall("metadata/$this->rootPath/$dropbox_path", "GET", compact('include_deleted','rev'));
190
  }
191
+
192
+ /**
193
  * Download a file to the webserver
194
+ *
195
  * @access public
196
+ * @param string|object $dropbox_file Dropbox path or metadata object of the file to download.
197
  * @param string $dest_path Local path for destination
198
  * @param string $rev Optional. The revision of the file to retrieve. This defaults to the most recent revision.
199
  * @param callback $progress_changed_callback Optional. Callback that will be called during download with 2 args: 1. bytes loaded, 2. file size
200
  * @return object Dropbox file metadata
201
+ */
202
  public function DownloadFile($dropbox_file, $dest_path='', $rev=null, $progress_changed_callback = null)
203
  {
204
  if(is_object($dropbox_file) && !empty($dropbox_file->path))
205
  $dropbox_file = $dropbox_file->path;
206
+
207
  if(empty($dest_path)) $dest_path = basename($dropbox_file);
208
+
209
  $url = $this->cleanUrl(self::API_CONTENT_URL."/files/$this->rootPath/$dropbox_file")
210
  . (!empty($rev) ? ('?'.http_build_query(array('rev' => $rev),'','&')) : '');
211
  $context = $this->createRequestContext($url, "GET");
215
  @fclose($rh);
216
  throw new DropboxException("Could not create file $dest_path !");
217
  }
218
+
219
  if($this->useCurl) {
220
  curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
221
  curl_setopt($context, CURLOPT_RETURNTRANSFER, true);
223
  $response_headers = array();
224
  self::execCurlAndClose($context, $response_headers);
225
  fclose($fh);
226
+ $meta = self::getMetaFromHeaders($response_headers, true);
227
  $bytes_loaded = filesize($dest_path);
228
  } else {
229
  $rh = @fopen($url, 'rb', false, $context); // read binary
230
  if($rh === false)
231
  throw new DropboxException("HTTP request to $url failed!");
232
+
233
+
234
  // get file meta from HTTP header
235
  $s_meta = stream_get_meta_data($rh);
236
+ $meta = self::getMetaFromHeaders($s_meta['wrapper_data'], true);
237
  $bytes_loaded = 0;
238
  while (!feof($rh)) {
239
  if(($s=fwrite($fh, fread($rh, self::BUFFER_SIZE))) === false) {
246
  call_user_func($progress_changed_callback, $bytes_loaded, $meta->bytes);
247
  }
248
  }
249
+
250
  fclose($rh);
251
  fclose($fh);
252
  }
253
+
254
  if($meta->bytes != $bytes_loaded)
255
+ throw new DropboxException("Download size mismatch! (header:{$meta->bytes} vs actual:{$bytes_loaded}; curl:{$this->useCurl})");
256
+
257
  return $meta;
258
  }
259
+
260
+ /**
261
  * Upload a file to dropbox
262
+ *
263
  * @access public
264
  * @param $src_file string Local file to upload
265
  * @param $dropbox_path string Dropbox path for destination
266
  * @return object Dropbox file metadata
267
+ */
268
  public function UploadFile($src_file, $dropbox_path='', $overwrite=true, $parent_rev=null)
269
  {
270
  if(empty($dropbox_path)) $dropbox_path = basename($src_file);
271
  elseif(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path;
272
+
273
+ // make sure the dropbox_path is not a dir. if it is, append baseneme of $src_file
274
+ $dropbox_bn = basename($dropbox_path);
275
+ if(strpos($dropbox_bn,'.') === false) { // check if ext. is missing -> could be a directory!
276
+ try {
277
+ $meta = $this->GetMetadata($dropbox_path);
278
+ if($meta && $meta->is_dir)
279
+ $dropbox_path = $dropbox_path . '/'. basename($src_file);
280
+ } catch(Exception $e) {}
281
+ }
282
+
283
  $file_size = filesize($src_file);
284
+
285
  if($file_size > self::MAX_UPLOAD_CHUNK_SIZE)
286
+ {
287
  $fh = fopen($src_file,'rb');
288
  if($fh === false)
289
  throw new DropboxException();
290
+
291
  $upload_id = null;
292
  $offset = 0;
293
 
294
+
295
+ while(!feof($fh)) {
296
  $url = $this->cleanUrl(self::API_CONTENT_URL."/chunked_upload").'?'.http_build_query(compact('upload_id', 'offset'),'','&');
297
+ $content = fread($fh, self::UPLOAD_CHUNK_SIZE);
298
+ $context = $this->createRequestContext($url, "PUT", $content);
299
+
300
+ if($this->useCurl) {
301
  curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
 
 
 
 
 
302
  $response = json_decode(self::execCurlAndClose($context));
 
 
 
 
303
  } else {
 
 
 
 
 
 
304
  $response = json_decode(file_get_contents($url, false, $context));
305
  }
306
+ $offset += strlen($content);
307
+ unset($content);
308
  unset($context);
309
+
310
+ self::checkForError($response);
311
+
312
  if(empty($upload_id)) {
313
  $upload_id = $response->upload_id;
314
  if(empty($upload_id)) throw new DropboxException("Upload ID empty!");
315
  }
316
+ if($offset >= $file_size)
317
+ break;
318
  }
319
+
320
  @fclose($fh);
321
+
 
 
322
  return $this->apiCall("commit_chunked_upload/$this->rootPath/$dropbox_path", "POST", compact('overwrite','parent_rev','upload_id'), true);
323
  }
324
+
325
  $query = http_build_query(array_merge(compact('overwrite', 'parent_rev'), array('locale' => $this->locale)),'','&');
326
  $url = $this->cleanUrl(self::API_CONTENT_URL."/files_put/$this->rootPath/$dropbox_path")."?$query";
327
+
328
  if($this->useCurl) {
329
  $context = $this->createRequestContext($url, "PUT");
330
  curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
334
  curl_setopt($context, CURLOPT_INFILESIZE, filesize($src_file));
335
  $meta = json_decode(self::execCurlAndClose($context));
336
  fclose($fh);
337
+ return self::checkForError($meta);
338
  } else {
339
  $content = file_get_contents($src_file);
340
  if(strlen($content) == 0)
341
  throw new DropboxException("Could not read file $src_file or file is empty!");
342
+
343
  $context = $this->createRequestContext($url, "PUT", $content);
344
+
345
+ return self::checkForError(json_decode(file_get_contents($url, false, $context)));
346
  }
347
  }
348
+
349
  /**
350
  * Get thumbnail for a specified image
351
  *
360
  if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
361
  $url = $this->cleanUrl(self::API_CONTENT_URL."thumbnails/$this->rootPath/$dropbox_file")
362
  . '?' . http_build_query(array('format' => $format, 'size' => $size),'','&');
363
+ $context = $this->createRequestContext($url, "GET");
364
+
365
  if($this->useCurl) {
366
  curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
367
  curl_setopt($context, CURLOPT_RETURNTRANSFER, true);
368
  }
369
+
370
  $thumb = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, NULL, $context);
371
 
372
  if($echo) {
375
  unset($thumb);
376
  return;
377
  }
378
+
379
  return $thumb;
380
  }
381
+
382
+
383
  function GetLink($dropbox_file, $preview=true, $short=true, &$expires=null)
384
  {
385
  if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
387
  $expires = strtotime($url->expires);
388
  return $url->url;
389
  }
390
+
391
  function Delta($cursor)
392
  {
393
  return $this->apiCall("delta", "POST", compact('cursor'));
394
  }
395
+
396
  function GetRevisions($dropbox_file, $rev_limit=10)
397
  {
398
  if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
399
  return $this->apiCall("revisions/$this->rootPath/$dropbox_file", "GET", compact('rev_limit'));
400
  }
401
+
402
  function Restore($dropbox_file, $rev)
403
  {
404
  if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
405
  return $this->apiCall("restore/$this->rootPath/$dropbox_file", "POST", compact('rev'));
406
  }
407
+
408
  function Search($path, $query, $file_limit=1000, $include_deleted=false)
409
  {
410
  return $this->apiCall("search/$this->rootPath/$path", "POST", compact('query','file_limit','include_deleted'));
411
  }
412
+
413
  function GetCopyRef($dropbox_file, &$expires=null)
414
  {
415
  if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
417
  $expires = strtotime($ref->expires);
418
  return $ref->copy_ref;
419
  }
420
+
421
+
422
  function Copy($from_path, $to_path, $copy_ref=false)
423
  {
424
  if(is_object($from_path) && !empty($from_path->path)) $from_path = $from_path->path;
425
  return $this->apiCall("fileops/copy", "POST", array('root'=> $this->rootPath, ($copy_ref ? 'from_copy_ref' : 'from_path') => $from_path, 'to_path' => $to_path));
426
  }
427
+
428
+ /**
429
  * Creates a new folder in the DropBox
430
+ *
431
  * @access public
432
  * @param $path string The path to the new folder to create
433
  * @return object Dropbox folder metadata
434
+ */
435
  function CreateFolder($path)
436
  {
437
  return $this->apiCall("fileops/create_folder", "POST", array('root'=> $this->rootPath, 'path' => $path));
438
  }
439
+
440
+ /**
441
  * Delete file or folder
442
+ *
443
  * @access public
444
  * @param $path mixed The path or metadata of the file/folder to be deleted.
445
  * @return object Dropbox metadata of deleted file or folder
446
+ */
447
  function Delete($path)
448
  {
449
  if(is_object($path) && !empty($path->path)) $path = $path->path;
450
  return $this->apiCall("fileops/delete", "POST", array('locale' =>null, 'root'=> $this->rootPath, 'path' => $path));
451
  }
452
+
453
  function Move($from_path, $to_path)
454
  {
455
  if(is_object($from_path) && !empty($from_path->path)) $from_path = $from_path->path;
456
  return $this->apiCall("fileops/move", "POST", array('root'=> $this->rootPath, 'from_path' => $from_path, 'to_path' => $to_path));
457
  }
458
+
459
  function getFileTree($path="", $include_deleted = false, $max_depth = 0, $depth=0)
460
  {
461
  static $files;
462
  if($depth == 0) $files = array();
463
+
464
  $dir = $this->apiCall("metadata/$this->rootPath/$path", "GET", compact('include_deleted'));
465
+
466
  if(empty($dir) || !is_object($dir)) return false;
467
+
468
  if(!empty($dir->error)) throw new DropboxException($dir->error);
469
+
470
  foreach($dir->contents as $item)
471
  {
472
  $files[trim($item->path,'/')] = $item;
475
  $this->getFileTree($item->path, $include_deleted, $max_depth, $depth+1);
476
  }
477
  }
478
+
479
  return $files;
480
  }
481
+
482
  function createCurl($url, $http_context)
483
  {
484
  $ch = curl_init($url);
485
+
486
  $curl_opts = array(
487
  CURLOPT_HEADER => false, // exclude header from output
488
  //CURLOPT_MUTE => true, // no output!
489
  CURLOPT_RETURNTRANSFER => true, // but return!
490
  CURLOPT_SSL_VERIFYPEER => false,
491
  );
492
+
493
+ $curl_opts[CURLOPT_CUSTOMREQUEST] = $http_context['method'];
494
+
495
  if(!empty($http_context['content'])) {
496
  $curl_opts[CURLOPT_POSTFIELDS] =& $http_context['content'];
497
  if(defined("CURLOPT_POSTFIELDSIZE"))
498
  $curl_opts[CURLOPT_POSTFIELDSIZE] = strlen($http_context['content']);
499
  }
500
+
501
  $curl_opts[CURLOPT_HTTPHEADER] = array_map('trim',explode("\n",$http_context['header']));
502
+
503
  curl_setopt_array($ch, $curl_opts);
504
  return $ch;
505
  }
506
+
507
  static private $_curlHeadersRef;
508
  static function _curlHeaderCallback($ch, $header)
509
  {
510
  self::$_curlHeadersRef[] = trim($header);
511
  return strlen($header);
512
  }
513
+
514
  static function &execCurlAndClose($ch, &$out_response_headers = null)
515
  {
516
  if(is_array($out_response_headers)) {
524
  if($err_no || $res === false) {
525
  throw new DropboxException("cURL-Error ($err_no): $err_str");
526
  }
527
+
528
  return $res;
529
  }
530
+
531
  private function createRequestContext($url, $method, &$content=null, $oauth_token=-1)
532
  {
533
  if($oauth_token === -1)
534
+ $oauth_token = $this->accessToken;
535
 
536
  $method = strtoupper($method);
537
  $http_context = array('method'=>$method, 'header'=> '');
538
+
539
  $oauth = new OAuthSimple($this->consumerToken['t'],$this->consumerToken['s']);
540
+
541
  if(empty($oauth_token) && !empty($this->accessToken))
542
  $oauth_token = $this->accessToken;
543
+
544
  if(!empty($oauth_token)) {
545
  $oauth->setParameters(array('oauth_token' => $oauth_token['t']));
546
  $oauth->signatures(array('oauth_secret'=>$oauth_token['s']));
547
  }
548
+
549
  if(!empty($content)) {
550
  $post_vars = ($method != "PUT" && preg_match("/^[a-z][a-z0-9_]*=/i", substr($content, 0, 32)));
551
  $http_context['header'] .= "Content-Length: ".strlen($content)."\r\n";
552
+ $http_context['header'] .= "Content-Type: application/".($post_vars?"x-www-form-urlencoded":"octet-stream")."\r\n";
553
+ $http_context['content'] =& $content;
554
  if($method == "POST" && $post_vars)
555
+ $oauth->setParameters($content);
556
  } elseif($method == "POST") {
557
  // make sure that content-length is always set when post request (otherwise some wrappers fail!)
558
  $http_context['content'] = "";
559
  $http_context['header'] .= "Content-Length: 0\r\n";
560
  }
561
+
562
 
563
  // check for query vars in url and add them to oauth parameters (and remove from path)
564
  $path = $url;
567
  $oauth->setParameters(substr($query,1));
568
  $path = substr($url, 0, -strlen($query));
569
  }
570
+
571
+
572
  $signed = $oauth->sign(array(
573
  'action' => $method,
574
  'path'=> $path));
575
+ //print_r($signed);
576
+
577
  $http_context['header'] .= "Authorization: ".$signed['header']."\r\n";
578
+
579
  return $this->useCurl ? $this->createCurl($url, $http_context) : stream_context_create(array('http'=>$http_context));
580
  }
581
+
582
  private function authCall($path, $request_token=null)
583
  {
584
  $url = $this->cleanUrl(self::API_URL.$path);
585
  $dummy = null;
586
  $context = $this->createRequestContext($url, "POST", $dummy, $request_token);
587
+
588
  $contents = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, false, $context);
589
  $data = array();
590
  parse_str($contents, $data);
591
  return $data;
592
  }
593
+
594
+ private static function checkForError($resp)
595
+ {
596
+ if(!empty($resp->error))
597
+ throw new DropboxException($resp->error);
598
+ return $resp;
599
+ }
600
+
601
+
602
  private function apiCall($path, $method, $params=array(), $content_call=false)
603
  {
604
  $url = $this->cleanUrl(($content_call ? self::API_CONTENT_URL : self::API_URL).$path);
605
  $content = http_build_query(array_merge(array('locale'=>$this->locale), $params),'','&');
606
+
607
  if($method == "GET") {
608
  $url .= "?".$content;
609
  $content = null;
610
  }
611
+
612
  $context = $this->createRequestContext($url, $method, $content);
613
  $json = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, false, $context);
614
  //if($json === false)
615
  // throw new DropboxException();
616
  $resp = json_decode($json);
617
+ return self::checkForError($resp);
 
 
618
  }
 
619
 
620
+
621
+ private static function getMetaFromHeaders(&$header_array, $throw_on_error=false)
622
  {
623
+ $obj = json_decode(substr(@array_shift(array_filter($header_array, create_function('$s', 'return stripos($s, "x-dropbox-metadata:") === 0;'))), 20));
624
+ if($throw_on_error && (empty($obj)||!is_object($obj)))
625
+ throw new DropboxException("Could not retrieve meta data from header data: ".print_r($header_array,true));
626
+ if($throw_on_error)
627
+ self::checkForError ($obj);
628
+ return $obj;
629
  }
630
+
631
 
632
  function cleanUrl($url) {
633
  $p = substr($url,0,8);
639
  }
640
 
641
  class DropboxException extends Exception {
642
+
643
+ public function __construct($err = null, $isDebug = FALSE)
644
  {
645
  if(is_null($err)) {
646
  $el = error_get_last();
655
  self::display_error($err, TRUE);
656
  }
657
  }
658
+
659
  public static function log_error($err)
660
  {
661
+ error_log($err, 0);
662
  }
663
+
664
  public static function display_error($err, $kill = FALSE)
665
  {
666
  print_r($err);
669
  die();
670
  }
671
  }
672
+ }
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: http://www.xcloner.com/
4
  Tags: backup, restore, plugin, database, full backup, cloner, xcloner, theme, files, upload, wordpress backup, backup plugin, database backup, database restore, site move, transfer, blog transfer, BuddyPress
5
  Requires at least: 2.0.2
6
  Tested up to: 4.2
7
- Stable tag: 3.1.2
8
 
9
  XCloner is a full backup and restore plugin for Wordpress, it will backup and restore both files and database. www.xcloner.com
10
 
@@ -70,6 +70,9 @@ If the inside Clone option fails for some reason, you need to:
70
 
71
  == Changelog ==
72
 
 
 
 
73
  = 3.1.2 =
74
  * vulnerability fix
75
 
4
  Tags: backup, restore, plugin, database, full backup, cloner, xcloner, theme, files, upload, wordpress backup, backup plugin, database backup, database restore, site move, transfer, blog transfer, BuddyPress
5
  Requires at least: 2.0.2
6
  Tested up to: 4.2
7
+ Stable tag: 3.1.3
8
 
9
  XCloner is a full backup and restore plugin for Wordpress, it will backup and restore both files and database. www.xcloner.com
10
 
70
 
71
  == Changelog ==
72
 
73
+ = 3.1.3 =
74
+ * XSS fix
75
+
76
  = 3.1.2 =
77
  * vulnerability fix
78
 
xcloner.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: XCloner
4
  Plugin URI: http://www.xcloner.com
5
  Description: XCloner is a tool that will help you manage your website backups, generate/restore/move so your website will be always secured! With XCloner you will be able to clone your site to any other location with just a few clicks. Don't forget to create the 'administrator/backups' directory in your Wordpress root and make it fully writeable. <a href="plugins.php?page=xcloner_show">Open XCloner</a> | <a href="http://www.xcloner.com/support/premium-support/">Get Premium Support</a> | <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=info%40xcloner%2ecom&lc=US&item_name=XCloner%20Support&no_note=0&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHostedGuest">Donate</a>
6
- Version: 3.1.2
7
  Author: Liuta Ovidiu
8
  Author URI: http://www.xcloner.com
9
  Plugin URI: http://www.xcloner.com
3
  Plugin Name: XCloner
4
  Plugin URI: http://www.xcloner.com
5
  Description: XCloner is a tool that will help you manage your website backups, generate/restore/move so your website will be always secured! With XCloner you will be able to clone your site to any other location with just a few clicks. Don't forget to create the 'administrator/backups' directory in your Wordpress root and make it fully writeable. <a href="plugins.php?page=xcloner_show">Open XCloner</a> | <a href="http://www.xcloner.com/support/premium-support/">Get Premium Support</a> | <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=info%40xcloner%2ecom&lc=US&item_name=XCloner%20Support&no_note=0&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHostedGuest">Donate</a>
6
+ Version: 3.1.3
7
  Author: Liuta Ovidiu
8
  Author URI: http://www.xcloner.com
9
  Plugin URI: http://www.xcloner.com