Completed
Pull Request — master (#222)
by
unknown
06:44
created

DiskClient::directoryContents()   B

Complexity

Conditions 3
Paths 2

Size

Total Lines 36
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 23
nc 2
nop 3
dl 0
loc 36
ccs 26
cts 26
cp 1
crap 3
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * Yandex PHP Library
4
 *
5
 * @copyright NIX Solutions Ltd.
6
 * @link https://github.com/nixsolutions/yandex-php-library
7
 */
8
9
/**
10
 * @namespace
11
 */
12
namespace Yandex\Disk;
13
14
use Psr\Http\Message\UriInterface;
15
use GuzzleHttp\Psr7\Response;
16
use GuzzleHttp\Exception\ClientException;
17
use Yandex\Common\AbstractServiceClient;
18
use Yandex\Disk\Exception\DiskRequestException;
19
20
/**
21
 * Class DiskClient
22
 *
23
 * @category Yandex
24
 * @package Disk
25
 *
26
 * @author   Alexander Mitsura <[email protected]>
27
 * @created  07.10.13 12:35
28
 *
29
 * @see https://tech.yandex.com/disk/doc/dg/concepts/api-methods-docpage/
30
 */
31
class DiskClient extends AbstractServiceClient
32
{
33
    const DECODE_TYPE_DEFAULT = self::DECODE_TYPE_XML;
34
35
    /**
36
     * @var string
37
     */
38
    private $version = 'v1';
39
40
    /**
41
     * @var string
42
     */
43
    protected $serviceDomain = 'webdav.yandex.ru';
44
45
    /**
46
     * @param string $version
47
     *
48
     * @return self
49
     */
50 1
    public function setVersion($version)
51
    {
52 1
        $this->version = $version;
53
54 1
        return $this;
55
    }
56
57
    /**
58
     * @return string
59
     */
60 2
    public function getVersion()
61
    {
62 2
        return $this->version;
63
    }
64
65
    /**
66
     * @inheritdoc
67
     */
68 2
    public function getServiceUrl($resource = '')
69
    {
70 2
        return parent::getServiceUrl($resource) . '/' . $this->version;
71
    }
72
73
    /**
74
     * @param $path
75
     * @return string
76
     */
77 1
    public function getRequestUrl($path)
78
    {
79 1
        return parent::getServiceUrl() . $path;
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getServiceUrl() instead of getRequestUrl()). Are you sure this is correct? If so, you might want to change this to $this->getServiceUrl().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
80
    }
81
82
    /**
83
     * @param string $token access token
84
     */
85 25
    public function __construct($token = '')
86
    {
87 25
        $this->setAccessToken($token);
88 25
    }
89
90
    /**
91
     * Sends a request
92
     *
93
     * @param string              $method  HTTP method
94
     * @param string|UriInterface $uri     URI object or string.
95
     * @param array               $options Request options to apply.
96
     *
97
     * @throws \Exception|\GuzzleHttp\Exception\ClientException
98
     * @return Response
99
     */
100 20
    protected function sendRequest($method, $uri, array $options = [])
101
    {
102
        try {
103 20
            $response = $this->getClient()->request($method, $uri, $options);
104 20
        } catch (ClientException $ex) {
105 2
            $result = $ex->getResponse();
106 2
            $code = $result->getStatusCode();
107 2
            $message = $result->getReasonPhrase();
108
109 2
            throw new DiskRequestException(
110 2
                'Service responded with error code: "' . $code . '" and message: "' . $message . '"',
111
                $code
112 2
            );
113
        }
114
115 18
        return $response;
116
    }
117
118
    /**
119
     * @param string $path
120
     * @return bool
121
     *
122
     * @see https://tech.yandex.com/disk/doc/dg/reference/mkcol-docpage/
123
     */
124 1
    public function createDirectory($path = '')
125
    {
126 1
        return (bool) $this->sendRequest('MKCOL', $path);
127
    }
128
129
    /**
130
     * @param string $path
131
     * @param null $offset
132
     * @param null $amount
133
     * @return array
134
     *
135
     * @see https://tech.yandex.com/disk/doc/dg/reference/propfind_contains-request-docpage/
136
     */
137 2
    public function directoryContents($path = '/', $offset = null, $amount = null)
138
    {
139 2
        $response = $this->sendRequest(
140 2
            'PROPFIND',
141 2
            $path,
142
            [
143
                'headers' => [
144
                    'Depth' => '1'
145 2
                ],
146
                'query' => [
147 2
                    'offset' => $offset,
148
                    'amount' => $amount
149 2
                ]
150 2
            ]
151 2
        );
152
153 1
        $decodedResponseBody = $this->getDecodedBody($response->getBody());
154
155 1
        $contents = [];
156 1
        foreach ($decodedResponseBody->children('DAV:') as $element) {
157 1
            array_push(
158 1
                $contents,
159
                [
160 1
                    'href' => $element->href->__toString(),
161 1
                    'status' => $element->propstat->status->__toString(),
162 1
                    'creationDate' => $element->propstat->prop->creationdate->__toString(),
163 1
                    'lastModified' => $element->propstat->prop->getlastmodified->__toString(),
164 1
                    'displayName' => $element->propstat->prop->displayname->__toString(),
165 1
                    'contentLength' => $element->propstat->prop->getcontentlength->__toString(),
166 1
                    'resourceType' => $element->propstat->prop->resourcetype->collection ? 'dir' : 'file',
167 1
                    'contentType' => $element->propstat->prop->getcontenttype->__toString()
168 1
                ]
169 1
            );
170 1
        }
171 1
        return $contents;
172
    }
173
174
    /**
175
     * @return array
176
     *
177
     * @see https://tech.yandex.com/disk/doc/dg/reference/propfind_space-request-docpage/
178
     */
179 1
    public function diskSpaceInfo()
180
    {
181
        $body = '<?xml version="1.0" encoding="utf-8" ?><D:propfind xmlns:D="DAV:">
182 1
            <D:prop><D:quota-available-bytes/><D:quota-used-bytes/></D:prop></D:propfind>';
183
184 1
        $response = $this->sendRequest(
185 1
            'PROPFIND',
186 1
            '/',
187
            [
188
                'headers' => [
189
                    'Depth' => '0'
190 1
                ],
191
                'body' => $body
192 1
            ]
193 1
        );
194
195 1
        $decodedResponseBody = $this->getDecodedBody($response->getBody());
196
197 1
        $info = (array) $decodedResponseBody->children('DAV:')->response->propstat->prop;
198
        return [
199 1
            'usedBytes' => $info['quota-used-bytes'],
200 1
            'availableBytes' => $info['quota-available-bytes']
201 1
        ];
202
    }
203
204
    /**
205
     * @param string $path
206
     * @param string $property
207
     * @param string $value
208
     * @param string $namespace
209
     * @return bool
210
     *
211
     * @see https://tech.yandex.com/disk/doc/dg/reference/proppatch-docpage/
212
     */
213 3
    public function setProperty($path = '', $property = '', $value = '', $namespace = 'default:namespace')
214
    {
215 3
        if (!empty($property) && !empty($value)) {
216
            $body = '<?xml version="1.0" encoding="utf-8" ?><propertyupdate xmlns="DAV:" xmlns:u="'
217 2
                . $namespace . '"><set><prop><u:' . $property . '>' . $value . '</u:'
218 2
                . $property . '></prop></set></propertyupdate>';
219
220 2
            $response = $this->sendRequest(
221 2
                'PROPPATCH',
222 2
                $path,
223
                [
224
                    'headers' => [
225 2
                        'Content-Length' => strlen($body),
226
                        'Content-Type' => 'application/x-www-form-urlencoded'
227 2
                    ],
228
                    'body' => $body
229 2
                ]
230 2
            );
231
232 2
            $decodedResponseBody = $this->getDecodedBody($response->getBody());
233
234 2
            $resultStatus = $decodedResponseBody->children('DAV:')->response->propstat->status;
235 2
            if (strpos($resultStatus, '200 OK')) {
236 1
                return true;
237
            }
238 1
        }
239 2
        return false;
240
    }
241
242
    /**
243
     * @param string $path
244
     * @param string $property
245
     * @param string $namespace
246
     * @return string|false
247
     *
248
     * @see https://tech.yandex.com/disk/doc/dg/reference/propfind_property-request-docpage/
249
     */
250 3
    public function getProperty($path = '', $property = '', $namespace = 'default:namespace')
251
    {
252 3
        if (!empty($property)) {
253
            $body = '<?xml version="1.0" encoding="utf-8" ?><propfind xmlns="DAV:"><prop><' . $property
254 2
                . ' xmlns="' . $namespace . '"/></prop></propfind>';
255
256 2
            $response = $this->sendRequest(
257 2
                'PROPFIND',
258 2
                $path,
259
                [
260
                    'headers' => [
261 2
                        'Depth' => '1',
262 2
                        'Content-Length' => strlen($body),
263
                        'Content-Type' => 'application/x-www-form-urlencoded'
264 2
                    ],
265
                    'body' => $body
266 2
                ]
267 2
            );
268
269 2
            $decodedResponseBody = $this->getDecodedBody($response->getBody());
270
271 2
            $resultStatus = $decodedResponseBody->children('DAV:')->response->propstat->status;
272 2
            if (strpos($resultStatus, '200 OK')) {
273 1
                return (string)$decodedResponseBody->children('DAV:')->response->propstat->prop->children();
274
            }
275 1
        }
276
277 2
        return false;
278
    }
279
280
    /**
281
     * @return string
282
     * @see https://tech.yandex.com/disk/doc/dg/reference/userinfo-docpage/
283
     */
284 1
    public function getLogin()
285
    {
286 1
        $response = $this->sendRequest(
287 1
            'GET',
288
            '/?userinfo'
289 1
        );
290 1
        $result = explode(":", $response->getBody());
291 1
        array_shift($result);
292 1
        return implode(':', $result);
293
    }
294
295
    /**
296
     * @param string $path
297
     * @return array
298
     *
299
     * @see https://tech.yandex.com/disk/doc/dg/reference/get-docpage/
300
     */
301 1
    public function getFile($path = '')
302
    {
303 1
        $response = $this->sendRequest('GET', $path);
304
305 1
        $result = [];
306 1 View Code Duplication
        foreach ($response->getHeaders() as $key => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
307 1
            $result['headers'][strtolower($key)] = $value[0];
308 1
        }
309 1
        $result['body'] = $response->getBody();
310 1
        return $result;
311
    }
312
313
    /**
314
     * @param string $path
315
     * @param string $destination
316
     * @param string $name
317
     * @return string|false
318
     *
319
     * @see https://tech.yandex.com/disk/doc/dg/reference/get-docpage/
320
     */
321 2
    public function downloadFile($path = '', $destination = '', $name = '')
322
    {
323 2
        $response = $this->sendRequest('GET', $path);
324 2
        if ($name === '' && $response->getHeader('Content-Disposition')
325 2
            && is_array($response->getHeader('Content-Disposition'))
326 2
            && count($response->getHeader('Content-Disposition')) > 0
327 2
        ) {
328 1
            $matchResults = [];
329 1
            preg_match(
330 1
                "/.*?filename=\"(.*?)\".*?/",
331 1
                $response->getHeader('Content-Disposition')[0],
332
                $matchResults
333 1
            );
334 1
            $name = urldecode($matchResults[1]);
335 1
        }
336
337 2
        $file = $destination . $name;
338
339 2
        $result = file_put_contents($file, $response->getBody()) ? $file : false;
340
341 2
        return $result;
342
    }
343
344
    /**
345
     * @param string $path
346
     * @param array $file
347
     * @param array $extraHeaders
348
     * @return Response
349
     *
350
     * @see https://tech.yandex.com/disk/doc/dg/reference/put-docpage/
351
     */
352 1
    public function uploadFile($path = '', $file = null, $extraHeaders = null)
353
    {
354 1
        if (file_exists($file['path'])) {
355
            $headers = [
356 1
                'Content-Length' => (string)$file['size']
357 1
            ];
358 1
            $finfo = finfo_open(FILEINFO_MIME);
359 1
            $mime = finfo_file($finfo, $file['path']);
360 1
            $parts = explode(";", $mime);
361 1
            $headers['Content-Type'] = $parts[0];
362 1
            $headers['Etag'] = md5_file($file['path']);
363 1
            $headers['Sha256'] = hash_file('sha256', $file['path']);
364 1
            $headers = isset($extraHeaders) ? array_merge($headers, $extraHeaders) : $headers;
365
366 1
            return $this->sendRequest(
367 1
                'PUT',
368 1
                $path . $file['name'],
369
                [
370 1
                    'headers' => $headers,
371 1
                    'body' => fopen($file['path'], 'rb'),
372
                    'expect' => true
373 1
                ]
374 1
            );
375 1
        }
376 1
    }
377
378
    /**
379
     * @param string $path
380
     * @param array  $file
381
     * @param array  $extraHeaders
382
     *
383
     * @return Response
384
     *
385 1
     * @see https://tech.yandex.com/disk/doc/dg/reference/put-docpage/
386
     * @throws \Exception|ClientException
387 1
     */
388 1
    public function uploadRemoteFile($path = '', $file = null, $extraHeaders = null)
389 1
    {
390
        $headers = [];
391
392 1
        //@formatter:off
393
        $headers['Content-Length'] = (string)$file['size'];
394 1
        $headers['Content-Type']   = (string)$file['mime'];
395 1
        $headers['Etag']           = (string)$file['md5'];
396 1
        $headers['Sha256']         = (string)$file['sha256'];
397
        //@formatter:on
398 1
399 1
        if(!empty($extraHeaders)){
400 1
            $headers = array_merge($headers, (array)$extraHeaders);
401 1
        }
402
403 1
        $client  = $this->getClient();
404 1
        $request = $client->createRequest(
0 ignored issues
show
Bug introduced by
The method createRequest() does not exist on GuzzleHttp\ClientInterface. Did you maybe mean request()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
405
            'PUT',
406
            $this->getServiceUrl(),
407
            [
408
                'headers' => $headers,
409
                'body'    => fopen($file['path'], 'rb'),
410
                'expect'  => true
411
            ]
412
        );
413
        $request->setPath($path . $file['name']);
414 1
415
        return $this->sendRequest($client, $request);
0 ignored issues
show
Documentation introduced by
$client is of type object<GuzzleHttp\ClientInterface>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
416 1
    }
417 1
418 1
    /**
419
     * @param $path
420
     * @param $size
421
     * @return array
422 1
     *
423 1
     * @see https://tech.yandex.com/disk/doc/dg/reference/preview-docpage/
424 1
     */
425
    public function getImagePreview($path, $size)
426
    {
427
        $response = $this->sendRequest(
428
            'GET',
429
            $path,
430
            [
431
                'query' => [
432
                    'preview' => '',
433
                    'size' => $size
434 1
                ]
435
            ]
436 1
        );
437 1
438 1
        $result = [];
439 View Code Duplication
        foreach ($response->getHeaders() as $key => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
440
            $result['headers'][strtolower($key)] = $value[0];
441
        }
442 1
443 1
        $result['body'] = $response->getBody();
444 1
        return $result;
445
    }
446
447
    /**
448
     * @param string $target
449
     * @param string $destination
450
     * @return bool
451
     *
452
     * @see https://tech.yandex.com/disk/doc/dg/reference/copy-docpage/
453 1
     */
454
    public function copy($target = '', $destination = '')
455 1
    {
456
        return (bool) $this->sendRequest(
457
            'COPY',
458
            $target,
459
            [
460
                'headers' => [
461
                    'Destination' => $destination
462
                ]
463
            ]
464
        );
465 1
    }
466
467
    /**
468
     * @param string $path
469 1
     * @param string $destination
470
     * @return bool
471 1
     *
472 1
     * @see https://tech.yandex.com/disk/doc/dg/reference/move-docpage/
473 1
     */
474
    public function move($path = '', $destination = '')
475
    {
476 1
        return (bool) $this->sendRequest(
477 1
            'MOVE',
478
            $path,
479 1
            [
480 1
                'headers' => [
481
                    'Destination' => $destination
482 1
                ]
483
            ]
484 1
        );
485 1
    }
486
487
    /**
488
     * @param string $path
489
     * @return bool
490
     *
491
     * @see https://tech.yandex.com/disk/doc/dg/reference/delete-docpage/
492
     */
493
    public function delete($path = '')
494 1
    {
495
        return (bool) $this->sendRequest('DELETE', $path);
496
    }
497
498 1
    /**
499
     * @param string $path
500 1
     * @return string
501 1
     *
502 1
     * @see https://tech.yandex.com/disk/doc/dg/reference/publish-docpage/#publish-s_1
503
     * @see https://tech.yandex.com/disk/doc/dg/reference/publish-docpage/#publish-s
504
     */
505 1
    public function startPublishing($path = '')
506 1
    {
507
        $body = '<propertyupdate xmlns="DAV:"><set><prop>
508 1
            <public_url xmlns="urn:yandex:disk:meta">true</public_url>
509 1
            </prop></set></propertyupdate>';
510 1
511
        $response = $this->sendRequest(
512
            'PROPPATCH',
513
            $path,
514
            [
515
                'headers' => [
516
                    'Content-Length' => strlen($body)
517
                ],
518 1
                'body' => $body
519
            ]
520 1
        );
521
522 1
        $decodedResponseBody = $this->getDecodedBody($response->getBody());
523 1
524 1
        $publicUrl = $decodedResponseBody->children('DAV:')->response->propstat->prop->children()->public_url;
525
        return (string)$publicUrl;
526
    }
527 1
528
    /**
529 1
     * @param string $path
530
     * @return void
531 1
     *
532 1
     * @see @https://tech.yandex.com/disk/doc/dg/reference/publish-docpage/#unpublish
533
     */
534 1
    public function stopPublishing($path = '')
535
    {
536 1
        $body = '<propertyupdate xmlns="DAV:"><remove><prop>
537 1
            <public_url xmlns="urn:yandex:disk:meta" />
538
            </prop></remove></propertyupdate>';
539
540
        $this->sendRequest(
541
            'PROPPATCH',
542
            $path,
543
            [
544
                'headers' => [
545
                    'Content-Length' => strlen($body)
546
                ],
547
                'body' => $body
548
            ]
549
        );
550
    }
551
552
    /**
553
     * @param string $path
554
     * @return string|bool
555
     *
556
     * @see https://tech.yandex.com/disk/doc/dg/reference/publish-docpage/#unpublish_1
557
     */
558
    public function checkPublishing($path = '')
559
    {
560
        $body = '<propfind xmlns="DAV:"><prop><public_url xmlns="urn:yandex:disk:meta"/></prop></propfind>';
561
562
        $response = $this->sendRequest(
563
            'PROPFIND',
564
            $path,
565
            [
566
                'headers' => [
567
                    'Content-Length' => strlen($body),
568
                    'Depth' => '0'
569
                ],
570
                'body' => $body
571
            ]
572
        );
573
574
        $decodedResponseBody = $this->getDecodedBody($response->getBody());
575
576
        $propArray = (array) $decodedResponseBody->children('DAV:')->response->propstat->prop->children();
577
        return empty($propArray['public_url']) ? (bool)false : (string)$propArray['public_url'];
578
    }
579
}
580