DropboxClient::setupDropboxHeaders()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 3
eloc 7
c 3
b 1
f 0
nc 2
nop 0
dl 0
loc 14
ccs 7
cts 7
cp 1
crap 3
rs 10
1
<?php
2
3
namespace Srmklive\Dropbox\Client;
4
5
use GuzzleHttp\Client as HttpClient;
6
use GuzzleHttp\Exception\ClientException as HttpClientException;
7
use GuzzleHttp\Psr7\StreamWrapper;
8
use Srmklive\Dropbox\Exceptions\BadRequest;
9
use Srmklive\Dropbox\UploadContent;
10
11
class DropboxClient
12
{
13
    use UploadContent;
0 ignored issues
show
Bug introduced by
The trait Srmklive\Dropbox\UploadContent requires the property $offset which is not provided by Srmklive\Dropbox\Client\DropboxClient.
Loading history...
14
15
    const THUMBNAIL_FORMAT_JPEG = 'jpeg';
16
    const THUMBNAIL_FORMAT_PNG = 'png';
17
18
    const THUMBNAIL_SIZE_XS = 'w32h32';
19
    const THUMBNAIL_SIZE_S = 'w64h64';
20
    const THUMBNAIL_SIZE_M = 'w128h128';
21
    const THUMBNAIL_SIZE_L = 'w640h480';
22
    const THUMBNAIL_SIZE_XL = 'w1024h768';
23
24
    const MAX_CHUNK_SIZE = 157286400;
25
26
    /** @var \GuzzleHttp\Client */
27
    protected $client;
28
29
    /**
30
     * Dropbox OAuth access token.
31
     *
32
     * @var string
33
     */
34
    protected $accessToken;
35
36
    /**
37
     * Dropbox API v2 Url.
38
     *
39
     * @var string
40
     */
41
    protected $apiUrl;
42
43
    /**
44
     * Dropbox content API v2 url for uploading content.
45
     *
46
     * @var string
47
     */
48
    protected $apiContentUrl;
49
50
    /**
51
     * Dropbox API v2 endpoint.
52
     *
53
     * @var string
54
     */
55
    protected $apiEndpoint;
56
57
    /**
58
     * @var mixed
59
     */
60
    protected $content;
61
62
    /**
63
     * Dropbox API request data.
64
     *
65
     * @var array
66
     */
67
    protected $request;
68
69
    /**
70
     * @var int
71
     */
72
    protected $maxChunkSize;
73
74
    /**
75
     * DropboxClient constructor.
76
     *
77
     * @param string             $token
78
     * @param \GuzzleHttp\Client $client
79
     * @param int                $maxChunkSize
80
     */
81 24
    public function __construct($token, HttpClient $client = null, $maxChunkSize = self::MAX_CHUNK_SIZE)
82
    {
83 24
        $this->setAccessToken($token);
84
85 24
        $this->setClient($client);
86
87 24
        $this->apiUrl = 'https://api.dropboxapi.com/2/';
88 24
        $this->apiContentUrl = 'https://content.dropboxapi.com/2/';
89 24
        $this->maxChunkSize = ($maxChunkSize < self::MAX_CHUNK_SIZE ?
90 24
            ($maxChunkSize > 1 ? $maxChunkSize : 1) : self::MAX_CHUNK_SIZE);
91 24
    }
92
93
    /**
94
     * Set Http Client.
95
     *
96
     * @param \GuzzleHttp\Client $client
97
     */
98 24
    protected function setClient(HttpClient $client = null)
99
    {
100 24
        if ($client instanceof HttpClient) {
101 19
            $this->client = $client;
102
        } else {
103 5
            $this->client = new HttpClient([
104
                'headers' => [
105 5
                    'Authorization' => "Bearer {$this->accessToken}",
106
                ],
107
            ]);
108
        }
109 24
    }
110
111
    /**
112
     * Set Dropbox OAuth access token.
113
     *
114
     * @param string $token
115
     */
116 24
    protected function setAccessToken($token)
117
    {
118 24
        $this->accessToken = $token;
119 24
    }
120
121
    /**
122
     * Copy a file or folder to a different location in the user's Dropbox.
123
     *
124
     * If the source path is a folder all its contents will be copied.
125
     *
126
     * @param string $fromPath
127
     * @param string $toPath
128
     *
129
     * @throws \Exception
130
     *
131
     * @return \Psr\Http\Message\ResponseInterface
132
     *
133
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-copy
134
     */
135 1
    public function copy($fromPath, $toPath)
136
    {
137 1
        $this->setupRequest([
138 1
            'from_path' => $this->normalizePath($fromPath),
139 1
            'to_path'   => $this->normalizePath($toPath),
140
        ]);
141
142 1
        $this->apiEndpoint = 'files/copy';
143
144 1
        return $this->doDropboxApiRequest();
145
    }
146
147
    /**
148
     * Create a folder at a given path.
149
     *
150
     * @param string $path
151
     *
152
     * @throws \Exception
153
     *
154
     * @return \Psr\Http\Message\ResponseInterface
155
     *
156
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-create_folder
157
     */
158 1
    public function createFolder($path)
159
    {
160 1
        $this->setupRequest([
161 1
            'path' => $this->normalizePath($path),
162
        ]);
163
164 1
        $this->apiEndpoint = 'files/create_folder';
165
166 1
        $response = $this->doDropboxApiRequest();
167 1
        $response['.tag'] = 'folder';
168
169 1
        return $response;
170
    }
171
172
    /**
173
     * Delete the file or folder at a given path.
174
     *
175
     * If the path is a folder, all its contents will be deleted too.
176
     * A successful response indicates that the file or folder was deleted.
177
     *
178
     * @param string $path
179
     *
180
     * @throws \Exception
181
     *
182
     * @return \Psr\Http\Message\ResponseInterface
183
     *
184
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-delete
185
     */
186 1
    public function delete($path)
187
    {
188 1
        $this->setupRequest([
189 1
            'path' => $this->normalizePath($path),
190
        ]);
191
192 1
        $this->apiEndpoint = 'files/delete';
193
194 1
        return $this->doDropboxApiRequest();
195
    }
196
197
    /**
198
     * Download a file from a user's Dropbox.
199
     *
200
     * @param string $path
201
     *
202
     * @throws \Exception
203
     *
204
     * @return resource
205
     *
206
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-download
207
     */
208 1
    public function download($path)
209
    {
210 1
        $this->setupRequest([
211 1
            'path' => $this->normalizePath($path),
212
        ]);
213
214 1
        $this->apiEndpoint = 'files/download';
215
216 1
        $this->content = null;
217
218 1
        $response = $this->doDropboxApiContentRequest();
219
220 1
        return StreamWrapper::getResource($response->getBody());
221
    }
222
223
    /**
224
     * Returns the metadata for a file or folder.
225
     *
226
     * Note: Metadata for the root folder is unsupported.
227
     *
228
     * @param string $path
229
     *
230
     * @throws \Exception
231
     *
232
     * @return \Psr\Http\Message\ResponseInterface
233
     *
234
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_metadata
235
     */
236 1
    public function getMetaData($path)
237
    {
238 1
        $this->setupRequest([
239 1
            'path' => $this->normalizePath($path),
240
        ]);
241
242 1
        $this->apiEndpoint = 'files/get_metadata';
243
244 1
        return $this->doDropboxApiRequest();
245
    }
246
247
    /**
248
     * Get a temporary link to stream content of a file.
249
     *
250
     * This link will expire in four hours and afterwards you will get 410 Gone.
251
     * Content-Type of the link is determined automatically by the file's mime type.
252
     *
253
     * @param string $path
254
     *
255
     * @throws \Exception
256
     *
257
     * @return string
258
     *
259
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_temporary_link
260
     */
261 1
    public function getTemporaryLink($path)
262
    {
263 1
        $this->setupRequest([
264 1
            'path' => $this->normalizePath($path),
265
        ]);
266
267 1
        $this->apiEndpoint = 'files/get_temporary_link';
268
269 1
        $response = $this->doDropboxApiRequest();
270
271 1
        return $response['link'];
272
    }
273
274
    /**
275
     * Get a thumbnail for an image.
276
     *
277
     * This method currently supports files with the following file extensions:
278
     * jpg, jpeg, png, tiff, tif, gif and bmp.
279
     *
280
     * Photos that are larger than 20MB in size won't be converted to a thumbnail.
281
     *
282
     * @param string $path
283
     * @param string $format
284
     * @param string $size
285
     *
286
     * @throws \Exception
287
     *
288
     * @return string
289
     */
290 1
    public function getThumbnail($path, $format = 'jpeg', $size = 'w64h64')
291
    {
292 1
        $this->setupRequest([
293 1
            'path'   => $this->normalizePath($path),
294 1
            'format' => $format,
295 1
            'size'   => $size,
296
        ]);
297
298 1
        $this->apiEndpoint = 'files/get_thumbnail';
299
300 1
        $this->content = null;
301
302 1
        $response = $this->doDropboxApiContentRequest();
303
304 1
        return (string) $response->getBody();
305
    }
306
307
    /**
308
     * Starts returning the contents of a folder.
309
     *
310
     * If the result's ListFolderResult.has_more field is true, call
311
     * list_folder/continue with the returned ListFolderResult.cursor to retrieve more entries.
312
     *
313
     * Note: auth.RateLimitError may be returned if multiple list_folder or list_folder/continue calls
314
     * with same parameters are made simultaneously by same API app for same user. If your app implements
315
     * retry logic, please hold off the retry until the previous request finishes.
316
     *
317
     * @param string $path
318
     * @param bool   $recursive
319
     *
320
     * @throws \Exception
321
     *
322
     * @return \Psr\Http\Message\ResponseInterface
323
     *
324
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder
325
     */
326 1
    public function listFolder($path = '', $recursive = false)
327
    {
328 1
        $this->setupRequest([
329 1
            'path'      => $this->normalizePath($path),
330 1
            'recursive' => $recursive,
331
        ]);
332
333 1
        $this->apiEndpoint = 'files/list_folder';
334
335 1
        return $this->doDropboxApiRequest();
336
    }
337
338
    /**
339
     * Once a cursor has been retrieved from list_folder, use this to paginate through all files and
340
     * retrieve updates to the folder, following the same rules as documented for list_folder.
341
     *
342
     * @param string $cursor
343
     *
344
     * @throws \Exception
345
     *
346
     * @return \Psr\Http\Message\ResponseInterface
347
     *
348
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder-continue
349
     */
350 1
    public function listFolderContinue($cursor = '')
351
    {
352 1
        $this->setupRequest([
353 1
            'cursor' => $cursor,
354
        ]);
355
356 1
        $this->apiEndpoint = 'files/list_folder/continue';
357
358 1
        return $this->doDropboxApiRequest();
359
    }
360
361
    /**
362
     * Move a file or folder to a different location in the user's Dropbox.
363
     *
364
     * If the source path is a folder all its contents will be moved.
365
     *
366
     * @param string $fromPath
367
     * @param string $toPath
368
     *
369
     * @throws \Exception
370
     *
371
     * @return \Psr\Http\Message\ResponseInterface
372
     *
373
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-move
374
     */
375 1
    public function move($fromPath, $toPath)
376
    {
377 1
        $this->setupRequest([
378 1
            'from_path' => $this->normalizePath($fromPath),
379 1
            'to_path'   => $this->normalizePath($toPath),
380
        ]);
381
382 1
        $this->apiEndpoint = 'files/move_v2';
383
384 1
        return $this->doDropboxApiRequest();
385
    }
386
387
    /**
388
     * Create a new file with the contents provided in the request.
389
     *
390
     * Do not use this to upload a file larger than 150 MB. Instead, create an upload session with upload_session/start.
391
     *
392
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload
393
     *
394
     * @param string          $path
395
     * @param string|resource $contents
396
     * @param string|array    $mode
397
     *
398
     * @throws \Exception
399
     *
400
     * @return array
401
     */
402 1
    public function upload($path, $contents, $mode = 'add')
403
    {
404 1
        if ($this->shouldUploadChunk($contents)) {
405
            return $this->uploadChunk($path, $contents, $mode);
0 ignored issues
show
Bug introduced by
It seems like $mode can also be of type array; however, parameter $mode of Srmklive\Dropbox\Client\...oxClient::uploadChunk() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

405
            return $this->uploadChunk($path, $contents, /** @scrutinizer ignore-type */ $mode);
Loading history...
406
        }
407
408 1
        $this->setupRequest([
409 1
            'path' => $this->normalizePath($path),
410 1
            'mode' => $mode,
411
        ]);
412
413 1
        $this->content = $contents;
414
415 1
        $this->apiEndpoint = 'files/upload';
416
417 1
        $response = $this->doDropboxApiContentRequest();
418
419 1
        $metadata = json_decode($response->getBody(), true);
420 1
        $metadata['.tag'] = 'file';
421
422 1
        return $metadata;
423
    }
424
425
    /**
426
     * Get Account Info for current authenticated user.
427
     *
428
     * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
429
     *
430
     * @throws \Exception
431
     *
432
     * @return \Psr\Http\Message\ResponseInterface
433
     */
434 1
    public function getAccountInfo()
435
    {
436 1
        $this->apiEndpoint = 'users/get_current_account';
437
438 1
        return $this->doDropboxApiRequest();
439
    }
440
441
    /**
442
     * Revoke current access token.
443
     *
444
     * @link https://www.dropbox.com/developers/documentation/http/documentation#auth-token-revoke
445
     *
446
     * @throws \Exception
447
     *
448
     * @return \Psr\Http\Message\ResponseInterface
449
     */
450 1
    public function revokeToken()
451
    {
452 1
        $this->apiEndpoint = 'auth/token/revoke';
453
454 1
        return $this->doDropboxApiRequest();
455
    }
456
457
    /**
458
     * Set Dropbox API request data.
459
     *
460
     * @param array $request
461
     */
462 17
    protected function setupRequest($request)
463
    {
464 17
        $this->request = $request;
465 17
    }
466
467
    /**
468
     * Perform Dropbox API v2 request.
469
     *
470
     * @param $endpoint
471
     * @param $payload
472
     *
473
     * @throws \Exception
474
     *
475
     * @return \Psr\Http\Message\ResponseInterface
476
     */
477 2
    public function performApiRequest($endpoint, $payload)
478
    {
479 2
        $this->setupRequest($payload);
480 2
        $this->apiEndpoint = $endpoint;
481
482 2
        return $this->doDropboxApiRequest();
483
    }
484
485
    /**
486
     * Perform Dropbox API v2 content request.
487
     *
488
     * @param $endpoint
489
     * @param $payload
490
     *
491
     * @throws \Exception
492
     *
493
     * @return \Psr\Http\Message\ResponseInterface
494
     */
495 1
    public function performContentApiRequest($endpoint, $payload)
496
    {
497 1
        $this->setupRequest($payload);
498 1
        $this->apiEndpoint = $endpoint;
499
500 1
        return $this->doDropboxApiContentRequest();
501
    }
502
503
    /**
504
     * Perform Dropbox API request.
505
     *
506
     * @throws \Exception
507
     *
508
     * @return \Psr\Http\Message\ResponseInterface
509
     */
510 12
    protected function doDropboxApiRequest()
511
    {
512 12
        $request = empty($this->request) ? [] : ['json' => $this->request];
513
514
        try {
515 12
            $response = $this->client->post("{$this->apiUrl}{$this->apiEndpoint}", $request);
516 2
        } catch (HttpClientException $exception) {
517 2
            throw $this->determineException($exception);
518
        }
519
520 10
        return json_decode($response->getBody(), true);
521
    }
522
523
    /**
524
     * Setup headers for Dropbox API request.
525
     *
526
     * @return array
527
     */
528 7
    protected function setupDropboxHeaders()
529
    {
530
        $headers = [
531 7
            'Dropbox-API-Arg' => json_encode(
532 7
                $this->request
533
            ),
534
        ];
535 7
        if (!empty($this->content) ||
536 7
               $this->apiEndpoint == 'files/upload_session/finish') {
537
            // The upload_session/finish API requires a Content-Type, always
538 4
            $headers['Content-Type'] = 'application/octet-stream';
539
        }
540
541 7
        return $headers;
542
    }
543
544
    /**
545
     * Perform Dropbox API request.
546
     *
547
     * @throws \Exception
548
     *
549
     * @return \Psr\Http\Message\ResponseInterface
550
     */
551 7
    protected function doDropboxApiContentRequest()
552
    {
553
        try {
554 7
            $response = $this->client->post("{$this->apiContentUrl}{$this->apiEndpoint}", [
555 7
                'headers' => $this->setupDropboxHeaders(),
556 7
                'body'    => !empty($this->content) ? $this->content : '',
557
            ]);
558 1
        } catch (HttpClientException $exception) {
559 1
            throw $this->determineException($exception);
560
        }
561
562 6
        return $response;
563
    }
564
565
    /**
566
     * Normalize path.
567
     *
568
     * @param string $path
569
     *
570
     * @return string
571
     */
572 11
    protected function normalizePath($path)
573
    {
574 11
        if (preg_match("/^id:.*|^rev:.*|^(ns:[0-9]+(\/.*)?)/", $path) === 1) {
575 1
            return $path;
576
        }
577
578 11
        $path = (trim($path, '/') === '') ? '' : '/'.$path;
579
580 11
        return str_replace('//', '/', $path);
581
    }
582
583
    /**
584
     * Catch Dropbox API request exception.
585
     *
586
     * @param HttpClientException $exception
587
     *
588
     * @return \Exception
589
     */
590 3
    protected function determineException(HttpClientException $exception)
591
    {
592 3
        if (!empty($exception->getResponse()) && in_array($exception->getResponse()->getStatusCode(), [400, 409])) {
593 2
            return new BadRequest($exception->getResponse());
594
        }
595
596 1
        return $exception;
597
    }
598
}
599