PluginProbe ʕ •ᴥ•ʔ
JetBackup – Backup, Restore & Migrate / 1.6.9
JetBackup – Backup, Restore & Migrate v1.6.9
3.1.22.3 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.8.1 1.4.9 1.5.0 1.5.1 1.5.1.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.10 1.6.11 1.6.12 1.6.13 1.6.15 1.6.5.1 1.6.8.8 1.6.9 1.6.9.1 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7.5 2.0.8.7 2.0.9.11 2.0.9.14 2.0.9.15 2.0.9.6 2.0.9.7 2.0.9.9 3.1.10.7 3.1.11.1 3.1.12.3 3.1.13.4 3.1.14.17 3.1.15.4 3.1.16.1 3.1.17.5 3.1.18.10 3.1.18.8 3.1.18.9 3.1.19.8 3.1.20.3 3.1.21.3 3.1.7.9 3.1.9.2 trunk 1.1.90 1.1.91 1.2.0 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2
backup / com / core / storage / SGDropboxStorage.php
backup / com / core / storage Last commit date
BackupGuardStorage.php 4 years ago SGDropbox.php 4 years ago SGDropboxStorage.php 3 years ago SGStorage.php 4 years ago
SGDropboxStorage.php
463 lines
1 <?php
2
3 require_once SG_STORAGE_PATH . 'SGStorage.php';
4
5 use Dropbox as dbx;
6
7 class SGDropboxStorage extends SGStorage
8 {
9 private $_client = null;
10 private $_fd = null;
11 private $_filePath = '';
12
13 public function init()
14 {
15 //check if curl extension is loaded
16 SGBoot::checkRequirement('curl');
17
18 // Dropbox api 2
19 $this->setActiveDirectory('');
20
21 @set_exception_handler(array('SGDropboxStorage', 'exceptionHandler'));
22 include_once SG_STORAGE_PATH . 'SGDropbox.php';
23 }
24
25 public static function exceptionHandler($exception)
26 {
27 if (SG_ENV_ADAPTER == SG_ENV_WORDPRESS) {
28 wp_die($exception->getMessage());
29 } elseif (SG_ENV_ADAPTER == SG_ENV_MAGENTO) {
30 die($exception->getMessage());
31 }
32 }
33
34 public function connect()
35 {
36 if ($this->isConnected()) {
37 return;
38 }
39
40 // phpcs:disable
41 $authCode = $this->getAuthCodeFromURL($cancel);
42
43 if ($cancel) {
44 throw new SGExceptionMethodNotAllowed('User did not allow access');
45 }
46 // phpcs:enable
47
48 $this->auth($authCode);
49 }
50
51 private function auth($authCode = '')
52 {
53 if ($authCode) {
54 try {
55 //exchange authorization code for access token
56 parse_str($_SERVER['QUERY_STRING'], $arr);
57 list($accessToken, $refreshToken) = $this->getWebAuth()->finish($arr);
58
59 $this->setAccessToken($accessToken);
60 $this->setRefreshToken($refreshToken);
61 $accountInfo = $this->getClient()->getAccountInfo();
62 SGConfig::set('SG_DROPBOX_CONNECTION_STRING', $accountInfo['email']);
63
64 $this->connected = true;
65 return;
66 } catch (Exception $ex) {
67
68 }
69 }
70
71 $refUrl = base64_encode($this->getRefURL());
72 $authorizeUrl = $this->getWebAuth()->start($refUrl);
73 header("Location: $authorizeUrl");
74 exit;
75 }
76
77 public function connectOffline()
78 {
79 if ($this->isConnected()) {
80 return;
81 }
82
83 if (!$this->getClient()) {
84 throw new SGExceptionNotFound('Access token not found');
85 }
86
87 $this->connected = true;
88 }
89
90 public function checkConnected()
91 {
92 $accessToken = $this->getAccessToken();
93 $this->connected = $accessToken ? true : false;
94 }
95
96 public function getListOfFiles()
97 {
98 if (!$this->isConnected()) {
99 throw new SGExceptionForbidden('Permission denied. Authentication required.');
100 }
101
102 $listOfFiles = array();
103 $activeDirectory = rtrim($this->getActiveDirectory()) . '/';
104 $metaData = $this->getClient()->getMetadataWithChildren($activeDirectory . SGConfig::get('SG_STORAGE_BACKUPS_FOLDER_NAME'));
105
106 foreach ($metaData['entries'] as $file) {
107 $size = $file['size'];
108 $date = $this->standardizeFileCreationDate($file['client_modified']);
109 $name = basename($file['path_display']);
110
111 $listOfFiles[$name] = array(
112 'name' => $name,
113 'size' => $size,
114 'date' => $date,
115 'path' => $file['path_display'],
116 );
117 }
118
119 krsort($listOfFiles);
120 return $listOfFiles;
121 }
122
123 public function createFolder($folderName)
124 {
125 if (!$this->isConnected()) {
126 throw new SGExceptionForbidden('Permission denied. Authentication required.');
127 }
128
129 $path = rtrim($this->getActiveDirectory(), '/') . '/' . $folderName;
130 $this->getClient()->createFolder($path);
131
132 return $path;
133 }
134
135 public function downloadFile($file, $size, $backupId = null)
136 {
137 if (!$file) {
138 return false;
139 }
140
141 $this->_filePath = SG_BACKUP_DIRECTORY . basename($file);
142 $this->_fd = fopen(SG_BACKUP_DIRECTORY . basename($file), "w");
143
144 $client = $this->getClient();
145
146 $url = "https://content.dropboxapi.com/2/files/download";
147 $params = array(
148 "path" => $file
149 );
150
151 $chunk = 1.0 * 1024 * 1024;
152 $start = 0;
153 $end = $chunk;
154 $result = true;
155
156 while (true) {
157 if ($end > $size) {
158 $end = $size;
159 }
160
161 if ($start >= $size) {
162 $result = true;
163 break;
164 }
165
166 $curl = $client->mkCurl($url);
167 $curl->set(CURLOPT_CUSTOMREQUEST, "POST");
168 $curl->set(CURLOPT_WRITEFUNCTION, array($this, 'writer'));
169 $curl->addHeader("Dropbox-API-Arg: " . json_encode($params));
170 $curl->addHeader("Range: bytes=$start-$end");
171
172 $response = $curl->exec();
173
174 if ($response->statusCode !== 206) {
175 $result = false;
176 break;
177 }
178
179 $start = $end + 1;
180 $end += $chunk;
181 }
182
183 fclose($this->_fd);
184
185 if (!$result) {
186 @unlink(SG_BACKUP_DIRECTORY . basename($file));
187 }
188
189 return $result;
190 }
191
192 public function writer($ch, $data)
193 {
194 if (!file_exists($this->_filePath)) {
195 return -1;
196 }
197
198 fwrite($this->_fd, $data);
199 return strlen($data);
200 }
201
202 private function saveStateData($uploadId, $offset)
203 {
204 $token = $this->delegate->getToken();
205 $actionId = $this->delegate->getActionId();
206 $pendingStorageUploads = $this->delegate->getPendingStorageUploads();
207 $currentUploadChunksCount = $this->delegate->getCurrentUploadChunksCount();
208 $progress = $this->delegate->getProgress();
209
210 $this->state->setProgress($progress);
211 $this->state->setCurrentUploadChunksCount($currentUploadChunksCount);
212 $this->state->setStorageType(SG_STORAGE_DROPBOX);
213 $this->state->setPendingStorageUploads($pendingStorageUploads);
214 $this->state->setToken($token);
215 $this->state->setUploadId($uploadId);
216 $this->state->setOffset($offset);
217 $this->state->setAction(SG_STATE_ACTION_UPLOADING_BACKUP);
218 $this->state->setActiveDirectory($this->getActiveDirectory());
219 $this->state->setActionId($actionId);
220 $this->state->save();
221 }
222
223 public function uploadFile($filePath)
224 {
225 if (!$this->isConnected()) {
226 throw new SGExceptionForbidden('Permission denied. Authentication required.');
227 }
228
229 if (!file_exists($filePath) || !is_readable($filePath)) {
230 throw new SGExceptionNotFound('File does not exist or is not readable: ' . $filePath);
231 }
232
233 $client = $this->getClient();
234 //$chunkSizeBytes = 2.0 * 1024 * 1024;
235 $chunkSizeBytes = (int)getCloudUploadChunkSize() * 1024 * 1024;
236
237 //Note: Because PHP's integer type is signed and many platforms use 32bit integers,
238 //some filesystem functions may return unexpected results for files which are larger than 2GB.
239 $fileSize = backupGuardRealFilesize($filePath);
240
241 $this->delegate->willStartUpload((int)ceil($fileSize / $chunkSizeBytes));
242
243 $handle = fopen($filePath, "rb");
244 $byteOffset = $this->state->getOffset();
245 fseek($handle, $byteOffset);
246
247 if ($this->state->getAction() == SG_STATE_ACTION_PREPARING_STATE_FILE) {
248 $data = fread($handle, $chunkSizeBytes);
249 $uploadId = $client->chunkedUploadStart($data);
250 $byteOffset += strlen($data);
251 } else {
252 $uploadId = $this->state->getUploadId();
253 }
254
255 SGPing::update();
256
257 while ($byteOffset < $fileSize) {
258 $data = fread($handle, $chunkSizeBytes);
259 $client->chunkedUploadContinue($uploadId, $byteOffset, $data);
260 $byteOffset += strlen($data);
261
262 if (!$this->delegate->shouldUploadNextChunk()) {
263 fclose($handle);
264 return;
265 }
266
267 SGPing::update();
268
269 $shouldReload = $this->shouldReload();
270 if ($shouldReload && backupGuardIsReloadEnabled()) {
271 $this->saveStateData($uploadId, $byteOffset);
272 @fclose($handle);
273 $this->reload();
274 }
275 }
276
277 $activeDirectory = $this->getActiveDirectory();
278
279 $path = rtrim($activeDirectory, '/') . '/' . basename($filePath);
280
281 $result = $client->chunkedUploadFinish($uploadId, $path, $byteOffset);
282 fclose($handle);
283
284 return $result;
285 }
286
287 public function fileExists($path)
288 {
289 $this->connectOffline();
290 if (!$this->isConnected()) {
291 throw new SGExceptionForbidden('Permission denied. Authentication required.');
292 }
293
294 $client = $this->getClient();
295 try {
296 $result = $client->searchFileNames(dirname($path), basename($path));
297 } catch (Exception $e) {
298 return false;
299 }
300
301 return $result;
302 }
303
304 public function deleteFile($path)
305 {
306 $this->connectOffline();
307 if (!$this->isConnected()) {
308 throw new SGExceptionForbidden('Permission denied. Authentication required.');
309 }
310
311 return $this->getClient()->delete($path);
312 }
313
314 public function deleteFolder($folderName)
315 {
316 return $this->deleteFile($folderName);
317 }
318
319 private function getAppInfo()
320 {
321 $key = SG_STORAGE_DROPBOX_KEY;
322 $secret = SG_STORAGE_DROPBOX_SECRET;
323
324 $appInfo = new dbx\AppInfo($key, $secret);
325
326 return $appInfo;
327 }
328
329 private function getAccessToken()
330 {
331 return SGConfig::get('SG_DROPBOX_ACCESS_TOKEN');
332 }
333
334 private function setAccessToken($accessToken)
335 {
336 SGConfig::set('SG_DROPBOX_ACCESS_TOKEN', $accessToken, true);
337 }
338
339 private function getRefreshToken()
340 {
341 return SGConfig::get('SG_DROPBOX_REFRESH_TOKEN');
342 }
343
344 private function setRefreshToken($refreshToken)
345 {
346 SGConfig::set('SG_DROPBOX_REFRESH_TOKEN', $refreshToken, true);
347 }
348
349 // private function getRefreshedAccessToken()
350 // {
351 // $array = array();
352 // $ch = curl_init();
353 // curl_setopt($ch, CURLOPT_URL, 'https://api.dropbox.com/oauth2/token');
354 // curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
355 // curl_setopt($ch, CURLOPT_POST, 1);
356 // curl_setopt($ch, CURLOPT_POSTFIELDS, "grant_type=refresh_token&refresh_token=" . $this->getRefreshToken());
357 // curl_setopt($ch, CURLOPT_USERPWD, SG_STORAGE_DROPBOX_KEY . ':' . SG_STORAGE_DROPBOX_SECRET);
358 // $headers = array();
359 // $headers[] = 'Content-Type: application/x-www-form-urlencoded';
360 // curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
361 // $response = json_decode(curl_exec($ch), true);
362 //
363 // if (curl_errno($ch)) {
364 // $array = ['status' => 400, 'access_token' => null];
365 // } elseif (isset($response['access_token'])) {
366 // $array = ['status' => 200, 'access_token' => $response['access_token']];
367 // }
368 // curl_close($ch);
369 //
370 // return $array;
371 // }
372
373 private function getClient()
374 {
375 if (!$this->_client) {
376 $accessToken = $this->getAccessToken();
377 if (!$accessToken) {
378 return false;
379 }
380
381 try {
382 return $this->getNewClient($accessToken);
383 } catch (dbx\Exception_InvalidAccessToken $error) {
384 $response = $this->getWebAuth()->getRefreshedAccessToken(SG_STORAGE_DROPBOX_KEY, SG_STORAGE_DROPBOX_SECRET, $this->getRefreshToken());
385
386 if ($response['status'] === 200) {
387 SGConfig::set('SG_DROPBOX_ACCESS_TOKEN', $response['access_token'], true);
388 return $this->getNewClient($response['access_token']);
389 }
390
391 return false;
392 }
393 }
394
395 return $this->_client;
396 }
397
398 private function getNewClient($accessToken)
399 {
400 $appInfo = $this->getAppInfo();
401 $client = new dbx\Client($accessToken, SG_STORAGE_DROPBOX_CLIENT_ID, null, $appInfo->getHost());
402
403 $client->getAccountInfo();
404
405 return $client;
406 }
407
408 private function getWebAuth()
409 {
410 $appInfo = $this->getAppInfo();
411 $redirectUri = SG_STORAGE_DROPBOX_REDIRECT_URI;
412 $savedCSRFToken = SGConfig::get('SG_DROPBOX_CONNECTION_CSRF_TOKEN');
413 if (!empty($savedCSRFToken)) {
414 $_SESSION['dropbox-auth-csrf-token'] = $savedCSRFToken;
415 SGConfig::set('SG_DROPBOX_CONNECTION_CSRF_TOKEN', false);
416 }
417
418 $csrfTokenStore = new dbx\ArrayEntryStore($_SESSION, 'dropbox-auth-csrf-token');
419 return new dbx\WebAuth($appInfo, SG_STORAGE_DROPBOX_CLIENT_ID, $redirectUri, $csrfTokenStore, null);
420 }
421
422 private function getCurrentURL()
423 {
424 $http = backupGuardGetCurrentUrlScheme();
425 $url = $http . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
426 return $url;
427 }
428
429 private function getRefURL()
430 {
431 $refUrl = $this->getCurrentURL();
432 if (!$_SERVER['QUERY_STRING']) {
433 $refUrl .= '?';
434 } else {
435 $refUrl .= '&';
436 }
437
438 return $refUrl;
439 }
440
441 private function getAuthCodeFromURL(&$cancel = false)
442 {
443 $query = $_SERVER['QUERY_STRING'];
444 if (!$query) {
445 return '';
446 }
447
448 $query = explode('&', $query);
449 $code = '';
450 foreach ($query as $q) {
451 $q = explode('=', $q);
452 if ($q[0] == 'code') {
453 $code = $q[1];
454 } else if ($q[0] == 'cancel' && $q[1] == '1') {
455 $cancel = true;
456 break;
457 }
458 }
459
460 return $code;
461 }
462 }
463