Version Description
- XSS fix
Download this release
Release Info
Developer | xcloner |
Plugin | XCloner – Backup and Restore |
Version | 3.1.3 |
Comparing to | |
See all releases |
Code changes from version 3.1.2 to 3.1.3
- classes/DropboxClient.php +207 -194
- readme.txt +4 -1
- 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
|
10 |
-
* @version 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 |
-
|
|
|
|
|
|
|
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 |
-
|
286 |
-
|
|
|
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 |
-
|
608 |
-
throw new DropboxException($resp->error);
|
609 |
-
return $resp;
|
610 |
}
|
611 |
-
|
612 |
|
613 |
-
|
|
|
614 |
{
|
615 |
-
|
|
|
|
|
|
|
|
|
|
|
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.
|
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¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHostedGuest">Donate</a>
|
6 |
-
Version: 3.1.
|
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¤cy_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
|