1<?php 2namespace Kunnu\Dropbox; 3 4use Kunnu\Dropbox\Models\File; 5use Kunnu\Dropbox\Models\Account; 6use Kunnu\Dropbox\Models\Thumbnail; 7use Kunnu\Dropbox\Models\AccountList; 8use Kunnu\Dropbox\Models\ModelFactory; 9use Kunnu\Dropbox\Models\FileMetadata; 10use Kunnu\Dropbox\Models\CopyReference; 11use Kunnu\Dropbox\Models\FolderMetadata; 12use Kunnu\Dropbox\Models\ModelCollection; 13use Kunnu\Dropbox\Authentication\OAuth2Client; 14use Kunnu\Dropbox\Store\PersistentDataStoreFactory; 15use Kunnu\Dropbox\Authentication\DropboxAuthHelper; 16use Kunnu\Dropbox\Exceptions\DropboxClientException; 17use Kunnu\Dropbox\Security\RandomStringGeneratorFactory; 18use Kunnu\Dropbox\Http\Clients\DropboxHttpClientFactory; 19 20/** 21 * Dropbox 22 */ 23class Dropbox 24{ 25 /** 26 * Uploading a file with the 'uploadFile' method, with the file's 27 * size less than this value (~8 MB), the simple `upload` method will be 28 * used, if the file size exceed this value (~8 MB), the `startUploadSession`, 29 * `appendUploadSession` & `finishUploadSession` methods will be used 30 * to upload the file in chunks. 31 * 32 * @const int 33 */ 34 const AUTO_CHUNKED_UPLOAD_THRESHOLD = 8000000; 35 36 /** 37 * The Chunk Size the file will be 38 * split into and uploaded (~4 MB) 39 * 40 * @const int 41 */ 42 const DEFAULT_CHUNK_SIZE = 4000000; 43 44 /** 45 * Response header containing file metadata 46 * 47 * @const string 48 */ 49 const METADATA_HEADER = 'dropbox-api-result'; 50 51 /** 52 * The Dropbox App 53 * 54 * @var \Kunnu\Dropbox\DropboxApp 55 */ 56 protected $app; 57 58 /** 59 * OAuth2 Access Token 60 * 61 * @var string 62 */ 63 protected $accessToken; 64 65 /** 66 * Dropbox Client 67 * 68 * @var \Kunnu\Dropbox\DropboxClient 69 */ 70 protected $client; 71 72 /** 73 * OAuth2 Client 74 * 75 * @var \Kunnu\Dropbox\Authentication\OAuth2Client 76 */ 77 protected $oAuth2Client; 78 79 /** 80 * Random String Generator 81 * 82 * @var \Kunnu\Dropbox\Security\RandomStringGeneratorInterface 83 */ 84 protected $randomStringGenerator; 85 86 /** 87 * Persistent Data Store 88 * 89 * @var \Kunnu\Dropbox\Store\PersistentDataStoreInterface 90 */ 91 protected $persistentDataStore; 92 93 /** 94 * Create a new Dropbox instance 95 * 96 * @param \Kunnu\Dropbox\DropboxApp 97 * @param array $config Configuration Array 98 */ 99 public function __construct(DropboxApp $app, array $config = []) 100 { 101 //Configuration 102 $config = array_merge([ 103 'http_client_handler' => null, 104 'random_string_generator' => null, 105 'persistent_data_store' => null 106 ], $config); 107 108 //Set the app 109 $this->app = $app; 110 111 //Set the access token 112 $this->setAccessToken($app->getAccessToken()); 113 114 //Make the HTTP Client 115 $httpClient = DropboxHttpClientFactory::make($config['http_client_handler']); 116 117 //Make and Set the DropboxClient 118 $this->client = new DropboxClient($httpClient); 119 120 //Make and Set the Random String Generator 121 $this->randomStringGenerator = RandomStringGeneratorFactory::makeRandomStringGenerator($config['random_string_generator']); 122 123 //Make and Set the Persistent Data Store 124 $this->persistentDataStore = PersistentDataStoreFactory::makePersistentDataStore($config['persistent_data_store']); 125 } 126 127 /** 128 * Get Dropbox Auth Helper 129 * 130 * @return \Kunnu\Dropbox\Authentication\DropboxAuthHelper 131 */ 132 public function getAuthHelper() 133 { 134 return new DropboxAuthHelper( 135 $this->getOAuth2Client(), 136 $this->getRandomStringGenerator(), 137 $this->getPersistentDataStore() 138 ); 139 } 140 141 /** 142 * Get OAuth2Client 143 * 144 * @return \Kunnu\Dropbox\Authentication\OAuth2Client 145 */ 146 public function getOAuth2Client() 147 { 148 if (!$this->oAuth2Client instanceof OAuth2Client) { 149 return new OAuth2Client( 150 $this->getApp(), 151 $this->getClient(), 152 $this->getRandomStringGenerator() 153 ); 154 } 155 156 return $this->oAuth2Client; 157 } 158 159 /** 160 * Get the Dropbox App. 161 * 162 * @return \Kunnu\Dropbox\DropboxApp Dropbox App 163 */ 164 public function getApp() 165 { 166 return $this->app; 167 } 168 169 /** 170 * Get the Client 171 * 172 * @return \Kunnu\Dropbox\DropboxClient 173 */ 174 public function getClient() 175 { 176 return $this->client; 177 } 178 179 /** 180 * Get the Random String Generator 181 * 182 * @return \Kunnu\Dropbox\Security\RandomStringGeneratorInterface 183 */ 184 public function getRandomStringGenerator() 185 { 186 return $this->randomStringGenerator; 187 } 188 189 /** 190 * Get Persistent Data Store 191 * 192 * @return \Kunnu\Dropbox\Store\PersistentDataStoreInterface 193 */ 194 public function getPersistentDataStore() 195 { 196 return $this->persistentDataStore; 197 } 198 199 /** 200 * Get the Metadata for a file or folder 201 * 202 * @param string $path Path of the file or folder 203 * @param array $params Additional Params 204 * 205 * @return \Kunnu\Dropbox\Models\FileMetadata | \Kunnu\Dropbox\Models\FolderMetadata 206 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 207 * 208 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_metadata 209 * 210 */ 211 public function getMetadata($path, array $params = []) 212 { 213 //Root folder is unsupported 214 if ($path === '/') { 215 throw new DropboxClientException("Metadata for the root folder is unsupported."); 216 } 217 218 //Set the path 219 $params['path'] = $path; 220 221 //Get File Metadata 222 $response = $this->postToAPI('/files/get_metadata', $params); 223 224 //Make and Return the Model 225 return $this->makeModelFromResponse($response); 226 } 227 228 /** 229 * Make a HTTP POST Request to the API endpoint type 230 * 231 * @param string $endpoint API Endpoint to send Request to 232 * @param array $params Request Query Params 233 * @param string $accessToken Access Token to send with the Request 234 * 235 * @return \Kunnu\Dropbox\DropboxResponse 236 */ 237 public function postToAPI($endpoint, array $params = [], $accessToken = null) 238 { 239 return $this->sendRequest("POST", $endpoint, 'api', $params, $accessToken); 240 } 241 242 /** 243 * Make Request to the API 244 * 245 * @param string $method HTTP Request Method 246 * @param string $endpoint API Endpoint to send Request to 247 * @param string $endpointType Endpoint type ['api'|'content'] 248 * @param array $params Request Query Params 249 * @param string $accessToken Access Token to send with the Request 250 * @param DropboxFile $responseFile Save response to the file 251 * 252 * @return \Kunnu\Dropbox\DropboxResponse 253 * 254 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 255 */ 256 public function sendRequest($method, $endpoint, $endpointType = 'api', array $params = [], $accessToken = null, DropboxFile $responseFile = null) 257 { 258 //Access Token 259 $accessToken = $this->getAccessToken() ? $this->getAccessToken() : $accessToken; 260 261 //Make a DropboxRequest object 262 $request = new DropboxRequest($method, $endpoint, $accessToken, $endpointType, $params); 263 264 //Make a DropboxResponse object if a response should be saved to the file 265 $response = $responseFile ? new DropboxResponseToFile($request, $responseFile) : null; 266 267 //Send Request through the DropboxClient 268 //Fetch and return the Response 269 return $this->getClient()->sendRequest($request, $response); 270 } 271 272 /** 273 * Get the Access Token. 274 * 275 * @return string Access Token 276 */ 277 public function getAccessToken() 278 { 279 return $this->accessToken; 280 } 281 282 /** 283 * Set the Access Token. 284 * 285 * @param string $accessToken Access Token 286 * 287 * @return \Kunnu\Dropbox\Dropbox Dropbox Client 288 */ 289 public function setAccessToken($accessToken) 290 { 291 $this->accessToken = $accessToken; 292 293 return $this; 294 } 295 296 /** 297 * Make Model from DropboxResponse 298 * 299 * @param DropboxResponse $response 300 * 301 * @return \Kunnu\Dropbox\Models\ModelInterface 302 * 303 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 304 */ 305 public function makeModelFromResponse(DropboxResponse $response) 306 { 307 //Get the Decoded Body 308 $body = $response->getDecodedBody(); 309 310 if (is_null($body)) { 311 $body = []; 312 } 313 314 //Make and Return the Model 315 return ModelFactory::make($body); 316 } 317 318 /** 319 * Get the contents of a Folder 320 * 321 * @param string $path Path to the folder. Defaults to root. 322 * @param array $params Additional Params 323 * 324 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder 325 * 326 * @return \Kunnu\Dropbox\Models\MetadataCollection 327 */ 328 public function listFolder($path = null, array $params = []) 329 { 330 //Specify the root folder as an 331 //empty string rather than as "/" 332 if ($path === '/') { 333 $path = ""; 334 } 335 336 //Set the path 337 $params['path'] = $path; 338 339 //Get File Metadata 340 $response = $this->postToAPI('/files/list_folder', $params); 341 342 //Make and Return the Model 343 return $this->makeModelFromResponse($response); 344 } 345 346 /** 347 * Paginate through all files and retrieve updates to the folder, 348 * using the cursor retrieved from listFolder or listFolderContinue 349 * 350 * @param string $cursor The cursor returned by your 351 * last call to listFolder or listFolderContinue 352 * 353 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder-continue 354 * 355 * @return \Kunnu\Dropbox\Models\MetadataCollection 356 */ 357 public function listFolderContinue($cursor) 358 { 359 $response = $this->postToAPI('/files/list_folder/continue', ['cursor' => $cursor]); 360 361 //Make and Return the Model 362 return $this->makeModelFromResponse($response); 363 } 364 365 /** 366 * Get a cursor for the folder's state. 367 * 368 * @param string $path Path to the folder. Defaults to root. 369 * @param array $params Additional Params 370 * 371 * @return string The Cursor for the folder's state 372 * 373 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 374 * 375 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder-get_latest_cursor 376 * 377 */ 378 public function listFolderLatestCursor($path, array $params = []) 379 { 380 //Specify the root folder as an 381 //empty string rather than as "/" 382 if ($path === '/') { 383 $path = ""; 384 } 385 386 //Set the path 387 $params['path'] = $path; 388 389 //Fetch the cursor 390 $response = $this->postToAPI('/files/list_folder/get_latest_cursor', $params); 391 392 //Retrieve the cursor 393 $body = $response->getDecodedBody(); 394 $cursor = isset($body['cursor']) ? $body['cursor'] : false; 395 396 //No cursor returned 397 if (!$cursor) { 398 throw new DropboxClientException("Could not retrieve cursor. Something went wrong."); 399 } 400 401 //Return the cursor 402 return $cursor; 403 } 404 405 /** 406 * Get Revisions of a File 407 * 408 * @param string $path Path to the file 409 * @param array $params Additional Params 410 * 411 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_revisions 412 * 413 * @return \Kunnu\Dropbox\Models\ModelCollection 414 */ 415 public function listRevisions($path, array $params = []) 416 { 417 //Set the Path 418 $params['path'] = $path; 419 420 //Fetch the Revisions 421 $response = $this->postToAPI('/files/list_revisions', $params); 422 423 //The file metadata of the entries, returned by this 424 //endpoint doesn't include a '.tag' attribute, which 425 //is used by the ModelFactory to resolve the correct 426 //model. But since we know that revisions returned 427 //are file metadata objects, we can explicitly cast 428 //them as \Kunnu\Dropbox\Models\FileMetadata manually. 429 $body = $response->getDecodedBody(); 430 $entries = isset($body['entries']) ? $body['entries'] : []; 431 $processedEntries = []; 432 433 foreach ($entries as $entry) { 434 $processedEntries[] = new FileMetadata($entry); 435 } 436 437 return new ModelCollection($processedEntries); 438 } 439 440 /** 441 * Search a folder for files/folders 442 * 443 * @param string $path Path to search 444 * @param string $query Search Query 445 * @param array $params Additional Params 446 * 447 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-search 448 * 449 * @return \Kunnu\Dropbox\Models\SearchResults 450 */ 451 public function search($path, $query, array $params = []) 452 { 453 //Specify the root folder as an 454 //empty string rather than as "/" 455 if ($path === '/') { 456 $path = ""; 457 } 458 459 //Set the path and query 460 $params['path'] = $path; 461 $params['query'] = $query; 462 463 //Fetch Search Results 464 $response = $this->postToAPI('/files/search', $params); 465 466 //Make and Return the Model 467 return $this->makeModelFromResponse($response); 468 } 469 470 /** 471 * Create a folder at the given path 472 * 473 * @param string $path Path to create 474 * @param boolean $autorename Auto Rename File 475 * 476 * @return \Kunnu\Dropbox\Models\FolderMetadata 477 * 478 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 479 * 480 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-create_folder 481 * 482 */ 483 public function createFolder($path, $autorename = false) 484 { 485 //Path cannot be null 486 if (is_null($path)) { 487 throw new DropboxClientException("Path cannot be null."); 488 } 489 490 //Create Folder 491 $response = $this->postToAPI('/files/create_folder', ['path' => $path, 'autorename' => $autorename]); 492 493 //Fetch the Metadata 494 $body = $response->getDecodedBody(); 495 496 //Make and Return the Model 497 return new FolderMetadata($body); 498 } 499 500 /** 501 * Delete a file or folder at the given path 502 * 503 * @param string $path Path to file/folder to delete 504 * 505 * @return \Kunnu\Dropbox\Models\DeletedMetadata|\Kunnu\Dropbox\Models\FileMetadata|\Kunnu\Dropbox\Models\FolderMetadata 506 * 507 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 508 * 509 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-delete 510 * 511 */ 512 public function delete($path) 513 { 514 //Path cannot be null 515 if (is_null($path)) { 516 throw new DropboxClientException("Path cannot be null."); 517 } 518 519 //Delete 520 $response = $this->postToAPI('/files/delete', ['path' => $path]); 521 522 return $this->makeModelFromResponse($response); 523 } 524 525 /** 526 * Move a file or folder to a different location 527 * 528 * @param string $fromPath Path to be moved 529 * @param string $toPath Path to be moved to 530 * 531 * @return \Kunnu\Dropbox\Models\DeletedMetadata|\Kunnu\Dropbox\Models\FileMetadata 532 * 533 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 534 * 535 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-move 536 * 537 */ 538 public function move($fromPath, $toPath) 539 { 540 //From and To paths cannot be null 541 if (is_null($fromPath) || is_null($toPath)) { 542 throw new DropboxClientException("From and To paths cannot be null."); 543 } 544 545 //Response 546 $response = $this->postToAPI('/files/move', ['from_path' => $fromPath, 'to_path' => $toPath]); 547 548 //Make and Return the Model 549 return $this->makeModelFromResponse($response); 550 } 551 552 /** 553 * Copy a file or folder to a different location 554 * 555 * @param string $fromPath Path to be copied 556 * @param string $toPath Path to be copied to 557 * 558 * @return \Kunnu\Dropbox\Models\DeletedMetadata|\Kunnu\Dropbox\Models\FileMetadata 559 * 560 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 561 * 562 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-copy 563 * 564 */ 565 public function copy($fromPath, $toPath) 566 { 567 //From and To paths cannot be null 568 if (is_null($fromPath) || is_null($toPath)) { 569 throw new DropboxClientException("From and To paths cannot be null."); 570 } 571 572 //Response 573 $response = $this->postToAPI('/files/copy', ['from_path' => $fromPath, 'to_path' => $toPath]); 574 575 //Make and Return the Model 576 return $this->makeModelFromResponse($response); 577 } 578 579 /** 580 * Restore a file to the specific version 581 * 582 * @param string $path Path to the file to restore 583 * @param string $rev Revision to store for the file 584 * 585 * @return \Kunnu\Dropbox\Models\DeletedMetadata|\Kunnu\Dropbox\Models\FileMetadata|\Kunnu\Dropbox\Models\FolderMetadata 586 * 587 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 588 * 589 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-restore 590 * 591 */ 592 public function restore($path, $rev) 593 { 594 //Path and Revision cannot be null 595 if (is_null($path) || is_null($rev)) { 596 throw new DropboxClientException("Path and Revision cannot be null."); 597 } 598 599 //Response 600 $response = $this->postToAPI('/files/restore', ['path' => $path, 'rev' => $rev]); 601 602 //Fetch the Metadata 603 $body = $response->getDecodedBody(); 604 605 //Make and Return the Model 606 return new FileMetadata($body); 607 } 608 609 /** 610 * Get Copy Reference 611 * 612 * @param string $path Path to the file or folder to get a copy reference to 613 * 614 * @return \Kunnu\Dropbox\Models\CopyReference 615 * 616 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 617 * 618 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-copy_reference-get 619 * 620 */ 621 public function getCopyReference($path) 622 { 623 //Path cannot be null 624 if (is_null($path)) { 625 throw new DropboxClientException("Path cannot be null."); 626 } 627 628 //Get Copy Reference 629 $response = $this->postToAPI('/files/copy_reference/get', ['path' => $path]); 630 $body = $response->getDecodedBody(); 631 632 //Make and Return the Model 633 return new CopyReference($body); 634 } 635 636 /** 637 * Save Copy Reference 638 * 639 * @param string $path Path to the file or folder to get a copy reference to 640 * @param string $copyReference Copy reference returned by getCopyReference 641 * 642 * @return \Kunnu\Dropbox\Models\FileMetadata|\Kunnu\Dropbox\Models\FolderMetadata 643 * 644 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 645 * 646 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-copy_reference-save 647 * 648 */ 649 public function saveCopyReference($path, $copyReference) 650 { 651 //Path and Copy Reference cannot be null 652 if (is_null($path) || is_null($copyReference)) { 653 throw new DropboxClientException("Path and Copy Reference cannot be null."); 654 } 655 656 //Save Copy Reference 657 $response = $this->postToAPI('/files/copy_reference/save', ['path' => $path, 'copy_reference' => $copyReference]); 658 $body = $response->getDecodedBody(); 659 660 //Response doesn't have Metadata 661 if (!isset($body['metadata']) || !is_array($body['metadata'])) { 662 throw new DropboxClientException("Invalid Response."); 663 } 664 665 //Make and return the Model 666 return ModelFactory::make($body['metadata']); 667 } 668 669 /** 670 * Get a temporary link to stream contents of a file 671 * 672 * @param string $path Path to the file you want a temporary link to 673 * 674 * https://www.dropbox.com/developers/documentation/http/documentation#files-get_temporary_link 675 * 676 * @return \Kunnu\Dropbox\Models\TemporaryLink 677 * 678 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 679 */ 680 public function getTemporaryLink($path) 681 { 682 //Path cannot be null 683 if (is_null($path)) { 684 throw new DropboxClientException("Path cannot be null."); 685 } 686 687 //Get Temporary Link 688 $response = $this->postToAPI('/files/get_temporary_link', ['path' => $path]); 689 690 //Make and Return the Model 691 return $this->makeModelFromResponse($response); 692 } 693 694 /** 695 * Save a specified URL into a file in user's Dropbox 696 * 697 * @param string $path Path where the URL will be saved 698 * @param string $url URL to be saved 699 * 700 * @return string Async Job ID 701 * 702 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 703 * 704 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-save_url 705 * 706 */ 707 public function saveUrl($path, $url) 708 { 709 //Path and URL cannot be null 710 if (is_null($path) || is_null($url)) { 711 throw new DropboxClientException("Path and URL cannot be null."); 712 } 713 714 //Save URL 715 $response = $this->postToAPI('/files/save_url', ['path' => $path, 'url' => $url]); 716 $body = $response->getDecodedBody(); 717 718 if (!isset($body['async_job_id'])) { 719 throw new DropboxClientException("Could not retrieve Async Job ID."); 720 } 721 722 //Return the Async Job ID 723 return $body['async_job_id']; 724 } 725 726 /** 727 * Save a specified URL into a file in user's Dropbox 728 * 729 * @param $asyncJobId 730 * 731 * @return \Kunnu\Dropbox\Models\FileMetadata|string Status (failed|in_progress) or FileMetadata (if complete) 732 * 733 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 734 * 735 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-save_url-check_job_status 736 * 737 */ 738 public function checkJobStatus($asyncJobId) 739 { 740 //Async Job ID cannot be null 741 if (is_null($asyncJobId)) { 742 throw new DropboxClientException("Async Job ID cannot be null."); 743 } 744 745 //Get Job Status 746 $response = $this->postToAPI('/files/save_url/check_job_status', ['async_job_id' => $asyncJobId]); 747 $body = $response->getDecodedBody(); 748 749 //Status 750 $status = isset($body['.tag']) ? $body['.tag'] : ''; 751 752 //If status is complete 753 if ($status === 'complete') { 754 return new FileMetadata($body); 755 } 756 757 //Return the status 758 return $status; 759 } 760 761 /** 762 * Upload a File to Dropbox 763 * 764 * @param string|DropboxFile $dropboxFile DropboxFile object or Path to file 765 * @param string $path Path to upload the file to 766 * @param array $params Additional Params 767 * 768 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload 769 * 770 * @return \Kunnu\Dropbox\Models\FileMetadata 771 */ 772 public function upload($dropboxFile, $path, array $params = []) 773 { 774 //Make Dropbox File 775 $dropboxFile = $this->makeDropboxFile($dropboxFile); 776 777 //If the file is larger than the Chunked Upload Threshold 778 if ($dropboxFile->getSize() > static::AUTO_CHUNKED_UPLOAD_THRESHOLD) { 779 //Upload the file in sessions/chunks 780 return $this->uploadChunked($dropboxFile, $path, null, null, $params); 781 } 782 783 //Simple file upload 784 return $this->simpleUpload($dropboxFile, $path, $params); 785 } 786 787 /** 788 * Make DropboxFile Object 789 * 790 * @param string|DropboxFile $dropboxFile DropboxFile object or Path to file 791 * @param int $maxLength Max Bytes to read from the file 792 * @param int $offset Seek to specified offset before reading 793 * @param string $mode The type of access 794 * 795 * @return \Kunnu\Dropbox\DropboxFile 796 */ 797 public function makeDropboxFile($dropboxFile, $maxLength = null, $offset = null, $mode = DropboxFile::MODE_READ) 798 { 799 //Uploading file by file path 800 if (!$dropboxFile instanceof DropboxFile) { 801 //Create a DropboxFile Object 802 $dropboxFile = new DropboxFile($dropboxFile, $mode); 803 } elseif ($mode !== $dropboxFile->getMode()) { 804 //Reopen the file with expected mode 805 $dropboxFile->close(); 806 $dropboxFile = new DropboxFile($dropboxFile->getFilePath(), $mode); 807 } 808 809 if (!is_null($offset)) { 810 $dropboxFile->setOffset($offset); 811 } 812 813 if (!is_null($maxLength)) { 814 $dropboxFile->setMaxLength($maxLength); 815 } 816 817 //Return the DropboxFile Object 818 return $dropboxFile; 819 } 820 821 /** 822 * Upload file in sessions/chunks 823 * 824 * @param string|DropboxFile $dropboxFile DropboxFile object or Path to file 825 * @param string $path Path to save the file to, on Dropbox 826 * @param int $fileSize The size of the file 827 * @param int $chunkSize The amount of data to upload in each chunk 828 * @param array $params Additional Params 829 * 830 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-start 831 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-finish 832 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-append_v2 833 * 834 * @return \Kunnu\Dropbox\Models\FileMetadata 835 */ 836 public function uploadChunked($dropboxFile, $path, $fileSize = null, $chunkSize = null, array $params = array()) 837 { 838 //Make Dropbox File 839 $dropboxFile = $this->makeDropboxFile($dropboxFile); 840 841 //No file size specified explicitly 842 if (is_null($fileSize)) { 843 $fileSize = $dropboxFile->getSize(); 844 } 845 846 //No chunk size specified, use default size 847 if (is_null($chunkSize)) { 848 $chunkSize = static::DEFAULT_CHUNK_SIZE; 849 } 850 851 //If the fileSize is smaller 852 //than the chunk size, we'll 853 //make the chunk size relatively 854 //smaller than the file size 855 if ($fileSize <= $chunkSize) { 856 $chunkSize = intval($fileSize / 2); 857 } 858 859 //Start the Upload Session with the file path 860 //since the DropboxFile object will be created 861 //again using the new chunk size. 862 $sessionId = $this->startUploadSession($dropboxFile->getFilePath(), $chunkSize); 863 864 //Uploaded 865 $uploaded = $chunkSize; 866 867 //Remaining 868 $remaining = $fileSize - $chunkSize; 869 870 //While the remaining bytes are 871 //more than the chunk size, append 872 //the chunk to the upload session. 873 while ($remaining > $chunkSize) { 874 //Append the next chunk to the Upload session 875 $sessionId = $this->appendUploadSession($dropboxFile, $sessionId, $uploaded, $chunkSize); 876 877 //Update remaining and uploaded 878 $uploaded = $uploaded + $chunkSize; 879 $remaining = $remaining - $chunkSize; 880 } 881 882 //Finish the Upload Session and return the Uploaded File Metadata 883 return $this->finishUploadSession($dropboxFile, $sessionId, $uploaded, $remaining, $path, $params); 884 } 885 886 /** 887 * Start an Upload Session 888 * 889 * @param string|DropboxFile $dropboxFile DropboxFile object or Path to file 890 * @param int $chunkSize Size of file chunk to upload 891 * @param boolean $close Closes the session for "appendUploadSession" 892 * 893 * @return string Unique identifier for the upload session 894 * 895 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 896 * 897 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-start 898 * 899 */ 900 public function startUploadSession($dropboxFile, $chunkSize = -1, $close = false) 901 { 902 //Make Dropbox File with the given chunk size 903 $dropboxFile = $this->makeDropboxFile($dropboxFile, $chunkSize); 904 905 //Set the close param 906 $params = [ 907 'close' => $close ? true : false, 908 'file' => $dropboxFile 909 ]; 910 911 //Upload File 912 $file = $this->postToContent('/files/upload_session/start', $params); 913 $body = $file->getDecodedBody(); 914 915 //Cannot retrieve Session ID 916 if (!isset($body['session_id'])) { 917 throw new DropboxClientException("Could not retrieve Session ID."); 918 } 919 920 //Return the Session ID 921 return $body['session_id']; 922 } 923 924 /** 925 * Make a HTTP POST Request to the Content endpoint type 926 * 927 * @param string $endpoint Content Endpoint to send Request to 928 * @param array $params Request Query Params 929 * @param string $accessToken Access Token to send with the Request 930 * @param DropboxFile $responseFile Save response to the file 931 * 932 * @return \Kunnu\Dropbox\DropboxResponse 933 */ 934 public function postToContent($endpoint, array $params = [], $accessToken = null, DropboxFile $responseFile = null) 935 { 936 return $this->sendRequest("POST", $endpoint, 'content', $params, $accessToken, $responseFile); 937 } 938 939 /** 940 * Append more data to an Upload Session 941 * 942 * @param string|DropboxFile $dropboxFile DropboxFile object or Path to file 943 * @param string $sessionId Session ID returned by `startUploadSession` 944 * @param int $offset The amount of data that has been uploaded so far 945 * @param int $chunkSize The amount of data to upload 946 * @param boolean $close Closes the session for futher "appendUploadSession" calls 947 * 948 * @return string Unique identifier for the upload session 949 * 950 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 951 * 952 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-append_v2 953 * 954 */ 955 public function appendUploadSession($dropboxFile, $sessionId, $offset, $chunkSize, $close = false) 956 { 957 //Make Dropbox File 958 $dropboxFile = $this->makeDropboxFile($dropboxFile, $chunkSize, $offset); 959 960 //Session ID, offset, chunkSize and path cannot be null 961 if (is_null($sessionId) || is_null($offset) || is_null($chunkSize)) { 962 throw new DropboxClientException("Session ID, offset and chunk size cannot be null"); 963 } 964 965 $params = []; 966 967 //Set the File 968 $params['file'] = $dropboxFile; 969 970 //Set the Cursor: Session ID and Offset 971 $params['cursor'] = ['session_id' => $sessionId, 'offset' => $offset]; 972 973 //Set the close param 974 $params['close'] = $close ? true : false; 975 976 //Since this endpoint doesn't have 977 //any return values, we'll disable the 978 //response validation for this request. 979 $params['validateResponse'] = false; 980 981 //Upload File 982 $this->postToContent('/files/upload_session/append_v2', $params); 983 984 //Make and Return the Model 985 return $sessionId; 986 } 987 988 /** 989 * Finish an upload session and save the uploaded data to the given file path 990 * 991 * @param string|DropboxFile $dropboxFile DropboxFile object or Path to file 992 * @param string $sessionId Session ID returned by `startUploadSession` 993 * @param int $offset The amount of data that has been uploaded so far 994 * @param int $remaining The amount of data that is remaining 995 * @param string $path Path to save the file to, on Dropbox 996 * @param array $params Additional Params 997 * 998 * @return \Kunnu\Dropbox\Models\FileMetadata 999 * 1000 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 1001 * 1002 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-finish 1003 * 1004 */ 1005 public function finishUploadSession($dropboxFile, $sessionId, $offset, $remaining, $path, array $params = []) 1006 { 1007 //Make Dropbox File 1008 $dropboxFile = $this->makeDropboxFile($dropboxFile, $remaining, $offset); 1009 1010 //Session ID, offset, remaining and path cannot be null 1011 if (is_null($sessionId) || is_null($path) || is_null($offset) || is_null($remaining)) { 1012 throw new DropboxClientException("Session ID, offset, remaining and path cannot be null"); 1013 } 1014 1015 $queryParams = []; 1016 1017 //Set the File 1018 $queryParams['file'] = $dropboxFile; 1019 1020 //Set the Cursor: Session ID and Offset 1021 $queryParams['cursor'] = ['session_id' => $sessionId, 'offset' => $offset]; 1022 1023 //Set the path 1024 $params['path'] = $path; 1025 //Set the Commit 1026 $queryParams['commit'] = $params; 1027 1028 //Upload File 1029 $file = $this->postToContent('/files/upload_session/finish', $queryParams); 1030 $body = $file->getDecodedBody(); 1031 1032 //Make and Return the Model 1033 return new FileMetadata($body); 1034 } 1035 1036 /** 1037 * Upload a File to Dropbox in a single request 1038 * 1039 * @param string|DropboxFile $dropboxFile DropboxFile object or Path to file 1040 * @param string $path Path to upload the file to 1041 * @param array $params Additional Params 1042 * 1043 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload 1044 * 1045 * @return \Kunnu\Dropbox\Models\FileMetadata 1046 */ 1047 public function simpleUpload($dropboxFile, $path, array $params = []) 1048 { 1049 //Make Dropbox File 1050 $dropboxFile = $this->makeDropboxFile($dropboxFile); 1051 1052 //Set the path and file 1053 $params['path'] = $path; 1054 $params['file'] = $dropboxFile; 1055 1056 //Upload File 1057 $file = $this->postToContent('/files/upload', $params); 1058 $body = $file->getDecodedBody(); 1059 1060 //Make and Return the Model 1061 return new FileMetadata($body); 1062 } 1063 1064 /** 1065 * Get a thumbnail for an image 1066 * 1067 * @param string $path Path to the file you want a thumbnail to 1068 * @param string $size Size for the thumbnail image ['thumb','small','medium','large','huge'] 1069 * @param string $format Format for the thumbnail image ['jpeg'|'png'] 1070 * 1071 * @return \Kunnu\Dropbox\Models\Thumbnail 1072 * 1073 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 1074 * 1075 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_thumbnail 1076 * 1077 */ 1078 public function getThumbnail($path, $size = 'small', $format = 'jpeg') 1079 { 1080 //Path cannot be null 1081 if (is_null($path)) { 1082 throw new DropboxClientException("Path cannot be null."); 1083 } 1084 1085 //Invalid Format 1086 if (!in_array($format, ['jpeg', 'png'])) { 1087 throw new DropboxClientException("Invalid format. Must either be 'jpeg' or 'png'."); 1088 } 1089 1090 //Thumbnail size 1091 $size = $this->getThumbnailSize($size); 1092 1093 //Get Thumbnail 1094 $response = $this->postToContent('/files/get_thumbnail', ['path' => $path, 'format' => $format, 'size' => $size]); 1095 1096 //Get file metadata from response headers 1097 $metadata = $this->getMetadataFromResponseHeaders($response); 1098 1099 //File Contents 1100 $contents = $response->getBody(); 1101 1102 //Make and return a Thumbnail model 1103 return new Thumbnail($metadata, $contents); 1104 } 1105 1106 /** 1107 * Get thumbnail size 1108 * 1109 * @param string $size Thumbnail Size 1110 * 1111 * @return string 1112 */ 1113 protected function getThumbnailSize($size) 1114 { 1115 $thumbnailSizes = [ 1116 'thumb' => 'w32h32', 1117 'small' => 'w64h64', 1118 'medium' => 'w128h128', 1119 'large' => 'w640h480', 1120 'huge' => 'w1024h768' 1121 ]; 1122 1123 return isset($thumbnailSizes[$size]) ? $thumbnailSizes[$size] : $thumbnailSizes['small']; 1124 } 1125 1126 /** 1127 * Get metadata from response headers 1128 * 1129 * @param DropboxResponse $response 1130 * 1131 * @return array 1132 */ 1133 protected function getMetadataFromResponseHeaders(DropboxResponse $response) 1134 { 1135 //Response Headers 1136 $headers = $response->getHeaders(); 1137 1138 //Empty metadata for when 1139 //metadata isn't returned 1140 $metadata = []; 1141 1142 //If metadata is available 1143 if (isset($headers[static::METADATA_HEADER])) { 1144 //File Metadata 1145 $data = $headers[static::METADATA_HEADER]; 1146 1147 //The metadata is present in the first index 1148 //of the metadata response header array 1149 if (is_array($data) && isset($data[0])) { 1150 $data = $data[0]; 1151 } 1152 1153 //Since the metadata is returned as a json string 1154 //it needs to be decoded into an associative array 1155 $metadata = json_decode((string)$data, true); 1156 } 1157 1158 //Return the metadata 1159 return $metadata; 1160 } 1161 1162 /** 1163 * Download a File 1164 * 1165 * @param string $path Path to the file you want to download 1166 * @param null|string|DropboxFile $dropboxFile DropboxFile object or Path to target file 1167 * 1168 * @return \Kunnu\Dropbox\Models\File 1169 * 1170 * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException 1171 * 1172 * @link https://www.dropbox.com/developers/documentation/http/documentation#files-download 1173 * 1174 */ 1175 public function download($path, $dropboxFile = null) 1176 { 1177 //Path cannot be null 1178 if (is_null($path)) { 1179 throw new DropboxClientException("Path cannot be null."); 1180 } 1181 1182 //Make Dropbox File if target is specified 1183 $dropboxFile = $dropboxFile ? $this->makeDropboxFile($dropboxFile, null, null, DropboxFile::MODE_WRITE) : null; 1184 1185 //Download File 1186 $response = $this->postToContent('/files/download', ['path' => $path], null, $dropboxFile); 1187 1188 //Get file metadata from response headers 1189 $metadata = $this->getMetadataFromResponseHeaders($response); 1190 1191 //File Contents 1192 $contents = $dropboxFile ? $this->makeDropboxFile($dropboxFile) : $response->getBody(); 1193 1194 //Make and return a File model 1195 return new File($metadata, $contents); 1196 } 1197 1198 /** 1199 * Get Current Account 1200 * 1201 * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account 1202 * 1203 * @return \Kunnu\Dropbox\Models\Account 1204 */ 1205 public function getCurrentAccount() 1206 { 1207 //Get current account 1208 $response = $this->postToAPI('/users/get_current_account', []); 1209 $body = $response->getDecodedBody(); 1210 1211 //Make and return the model 1212 return new Account($body); 1213 } 1214 1215 /** 1216 * Get Account 1217 * 1218 * @param string $account_id Account ID of the account to get details for 1219 * 1220 * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_account 1221 * 1222 * @return \Kunnu\Dropbox\Models\Account 1223 */ 1224 public function getAccount($account_id) 1225 { 1226 //Get account 1227 $response = $this->postToAPI('/users/get_account', ['account_id' => $account_id]); 1228 $body = $response->getDecodedBody(); 1229 1230 //Make and return the model 1231 return new Account($body); 1232 } 1233 1234 /** 1235 * Get Multiple Accounts in one call 1236 * 1237 * @param array $account_ids IDs of the accounts to get details for 1238 * 1239 * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_account_batch 1240 * 1241 * @return \Kunnu\Dropbox\Models\AccountList 1242 */ 1243 public function getAccounts(array $account_ids = []) 1244 { 1245 //Get account 1246 $response = $this->postToAPI('/users/get_account_batch', ['account_ids' => $account_ids]); 1247 $body = $response->getDecodedBody(); 1248 1249 //Make and return the model 1250 return new AccountList($body); 1251 } 1252 1253 /** 1254 * Get Space Usage for the current user's account 1255 * 1256 * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_space_usage 1257 * 1258 * @return array 1259 */ 1260 public function getSpaceUsage() 1261 { 1262 //Get space usage 1263 $response = $this->postToAPI('/users/get_space_usage', []); 1264 $body = $response->getDecodedBody(); 1265 1266 //Return the decoded body 1267 return $body; 1268 } 1269} 1270