Passed
Push — master ( e39da6...9f5525 )
by sabaku
04:31
created

Upyun::avMeta()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 7
ccs 5
cts 5
cp 1
crap 1
rs 9.4285
1
<?php
2
/**
3
 * 又拍云 PHP-SDK
4
 */
5
namespace Upyun;
6
7
use Upyun\Api\Rest;
8
9
use GuzzleHttp\Client;
10
use GuzzleHttp\Psr7;
11
use GuzzleHttp;
12
13
/**
14
 * Class Upyun
15
 *
16
 * 又拍云云存储、云处理接口
17
 *
18
 * Upyun 类实现了又拍云云存储和云处理的所有接口,通过该类可以实现文件上传、下载;图片视频等多媒体资源云处理。
19
 * 本文档中,提到的"服务"是指又拍云文件加速回又拍云源类型的服务(即原先的存储类空间)。
20
 *
21
 * @package Upyun
22
 */
23
class Upyun
24
{
25
26
    /**
27
     * @var Config: 服务配置
28
     */
29
    protected $config;
30
31
    // 异步云处理任务类型
32
    /**
33
     * @var string 异步音视频处理
34
     */
35
    public static $PROCESS_TYPE_MEDIA = 'media';
36
    /**
37
     * @var string 文件压缩
38
     */
39
    public static $PROCESS_TYPE_ZIP = 'zip-file';
40
    /**
41
     * @var string 解压缩
42
     */
43
    public static $PROCESS_TYPE_UNZIP = 'unzip-file';
44
    /**
45
     * @var string 文件拉取
46
     */
47
    public static $PROCESS_TYPE_SYNC_FILE = 'sync-remote-file-to-upyun';
48
    /**
49
     * @var string 文档转换
50
     */
51
    public static $PROCESS_TYPE_CONVERT = 'document-type-convert';
52
    /**
53
     * @var string 异步图片拼接
54
     */
55
    public static $PROCESS_TYPE_STITCH = 'picture-stitch';
56
57
    /**
58
     * Upyun constructor.
59
     *
60
     * @param Config $config 服务配置
61
     */
62 1
    public function __construct(Config $config)
63
    {
64 1
        $this->setConfig($config);
65 1
    }
66
67
    /**
68
     * 配置服务信息
69
     *
70
     * 当需要操作的新的服务时,使用该方法传入新的服务配置即可
71
     *
72
     * @param Config $config 服务配置
73
     *
74
     * @return $this
75
     */
76 1
    public function setConfig(Config $config)
77
    {
78 1
        $this->config = $config;
79 1
        return $this;
80
    }
81
82
    /**
83
     * 上传一个文件到又拍云存储
84
     *
85
     * 上传的文件格式支持文件流或者字符串方式上传。除简单的文件上传外,针对多媒体资源(图片、音视频),还可以设置同步/异步预处理多媒体资源,例如:图片的裁剪缩放,音视频的转码截图等等众多又拍云强大的云处理功能
86
     *
87
     * @param string $path 被上传的文件在又拍云存储服务中保存的路径
88
     * @param string|resource $content 被上传的文件内容(字符串),或者打开该文件获得的文件句柄(文件流)。当上传本地大文件时,推荐使用文件流的方式上传
89
     * @param array $params 上传文件时,附加的自定义参数。支持 Content-MD5 Content-Type Content-Secret 等,详见 [上传参数](http://docs.upyun.com/api/rest_api/#_2),例如:
90
     * - 设置文件[保护秘钥](http://docs.upyun.com/api/rest_api/#Content-Secret) `write($path, $content, array('Content-Secret' => 'my-secret'))`;
91
     * - 添加[文件元信息](http://docs.upyun.com/api/rest_api/#metadata) `write($path, $content, array('X-Upyun-Meta-Foo' =>
92
     * 'bar'))`
93
     * - [图片同步预处理](http://docs.upyun.com/cloud/image/#_5) `write($path, $content, array('x-gmkerl-thumb' => '/format/png'))`
94
     * @param bool $withAsyncProcess  默认为 `false`,当上传图片或者音视频资源时,可以设置该参数为 `true`,开启图片音视频的[异步处理功能](http://docs.upyun.com/api/form_api/#_6) ,例如:
95
     *```
96
     * // 以下参数会将新上传的图片,再异步生成另一份 png 格式的图片,原图不受影响
97
     * write($path, $content, array(
98
     *    'apps' => array(
99
     *        array(
100
     *            'name' => 'thumb',         //异步图片处理任务
101
     *            'x-gmkerl-thumb' => '/format/png', // 格式化图片为 png 格式
102
     *            'save_as': '/iamge/png/new.png',   // 处理成功后的图片保存路径
103
     *            'notify_url': 'http://your.notify.url'  // 异步任务完成后的回调地址
104
     *        )
105
     *    )
106
     * ), true);
107
     *```
108
     *
109
     *
110
     *
111
     * @return array|bool 若文件是图片则返回图片基本信息,如:`array('x-upyun-width' => 123, 'x-upyun-height' => 50, 'x-upyun-frames'
112
     * => 1, 'x-upyun-file-type' => 'JPEG')`,否则返回空数组。当使用异步预处理功能时,返回结果为布尔值,成功为 `true`。
113
     *
114
     * @throws \Exception 上传失败时,抛出异常
115
     */
116 12
    public function write($path, $content, $params = array(), $withAsyncProcess = false)
117
    {
118 12
        if (!$content) {
119
            throw new \Exception('write content can not be empty.');
120
        }
121
122 12
        $upload = new Uploader($this->config);
123 12
        $response = $upload->upload($path, $content, $params, $withAsyncProcess);
124 11
        if ($withAsyncProcess) {
125 1
            return $response;
126
        }
127 10
        return Util::getHeaderParams($response->getHeaders());
128
    }
129
130
    /**
131
     * 读取云存储文件/目录内容
132
     *
133
     * @param string $path 又拍云存储中的文件或者目录路径
134
     * @param resource $saveHandler 文件内容写入本地文件流。例如 `$saveHandler = fopen('/local/file', 'w')
135
     * `。当设置该参数时,将以文件流的方式,直接将又拍云中的文件写入本地的文件流,或其他可以写入的流
136
     * @param array $params  可选参数,读取目录内容时,需要设置三个参数: `X-List-Iter` 分页开始位置(第一页不需要设置),`X-List-Limit` 获取的文件数量(默认 100,最大
137
     * 10000),`X-List-Order` 结果以时间正序或者倒序
138
     *
139
     * @return mixed $return 当读取文件且没有设置 `$saveHandler` 参数时,返回一个字符串类型,表示文件内容;设置了 `$saveHandler` 参数时,返回布尔值
140
     * `true`。当读取目录时,返回一个数组,表示目录下的文件列表。目录下文件内容过多时,需要通过判断返回数组中的 `is_end` 属性,进行分页读取内容
141
     *
142
     * @throws \Exception
143
     */
144 3
    public function read($path, $saveHandler = null, $params = array())
145
    {
146 3
        $req = new Rest($this->config);
147 3
        $response = $req->request('GET', $path)
148 3
            ->withHeaders($params)
149 3
            ->send();
150
151
152 2
        $params = Util::getHeaderParams($response->getHeaders());
153
154
155 2
        if (! isset($params['x-upyun-list-iter'])) {
156 1
            if (is_resource($saveHandler)) {
157 1
                Psr7\copy_to_stream($response->getBody(), Psr7\stream_for($saveHandler));
158 1
                return true;
159
            } else {
160 1
                return $response->getBody()->getContents();
161
            }
162
        } else {
163 1
            $files = Util::parseDir($response->getBody()->getContents());
164 1
            return array('files' => $files, 'is_end' => $params['x-upyun-list-iter'] === 'g2gCZAAEbmV4dGQAA2VvZg', 'iter' => $params['x-upyun-list-iter']);
165
        }
166
    }
167
168
    /**
169
     * 判断文件是否存在于又拍云存储
170
     *
171
     * 注意: 对刚删除的文件, 立即调用该方法可能会返回 true, 因为服务端执行删除操作后可能会有很短暂的延迟.
172
     *
173
     * @param string $path 云存储的文件路径
174
     *
175
     * @return bool 存在时返回 `true`,否则返回 `false`
176
     * @throws \Exception
177
     */
178 2
    public function has($path)
179
    {
180 2
        $req = new Rest($this->config);
181
        try {
182 2
            $req->request('HEAD', $path)
183 2
                            ->send();
184 2
        } catch (GuzzleHttp\Exception\BadResponseException $e) {
185 1
            $statusCode = $e->getResponse()->getStatusCode();
186 1
            if ($statusCode === 404) {
187 1
                return false;
188
            } else {
189
                throw $e;
190
            }
191
        }
192
193 2
        return true;
194
    }
195
196
    /**
197
     * 获取云存储文件/目录的基本信息
198
     *
199
     * @param string $path 云存储的文件路径
200
     * @param array $otherHeaders 设置了后,方法将返回其他 http header 中的信息,默认为空
201
     *
202
     * @return array 返回一个数组,默认包含以下 key
203
     * - `x-upyun-file-type` 当 $path 是目录时,值为 *folder*,当 $path 是文件时,值为 *file*,
204
     * - `x-upyun-file-size` 文件大小
205
     * - `x-upyun-file-date` 文件的创建时间
206
     */
207 2
    public function info($path, $otherHeaders = array())
208
    {
209 2
        $req = new Rest($this->config);
210 2
        $response = $req->request('HEAD', $path)
211 2
                        ->send();
212 2
        return Util::getHeaderParams($response->getHeaders(), $otherHeaders);
213
    }
214
215
    /**
216
     * 获取文件的文档类型
217
     * @param string $path 云存储文件路径
218
     * @return string 文档类型,e.g: `appcation/json`,获取失败返回空字符串
219
     */
220 1
    public function getMimetype($path)
221
    {
222 1
        $params = $this->info($path, array('content-type'));
223 1
        if (isset($params['content-type'])) {
224 1
            return explode(';', $params['content-type'])[0];
225
        }
226
        return '';
227
    }
228
229
    /**
230
     * 删除文件或者目录
231
     *
232
     * @param string $path 文件或目录在又拍云存储的路径
233
     * @param bool $async 是否异步删除,默认为 false,表示同步删除。当需要批量删除大量文件时,必须选择异步删除
234
     *
235
     * @return bool 删除成功返回 true,否则 false
236
     * @throws \Exception 删除不存在的文件将会抛出异常
237
     */
238 4
    public function delete($path, $async = false)
239
    {
240 4
        $req = new Rest($this->config);
241 4
        $req->request('DELETE', $path);
242 4
        if ($async) {
243
            $req->withHeader('x-upyun-async', 'true');
244
        }
245 4
        $res = $req->send();
246 3
        return $res->getStatusCode() === 200;
247
    }
248
249
    /**
250
     * 创建目录
251
     *
252
     * @param string $path 需要在又拍云存储创建的目录路径
253
     *
254
     * @return bool 创建成功返回 true,否则返回 false
255
     * @throws \Exception
256
     */
257 2 View Code Duplication
    public function createDir($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
258
    {
259 2
        $path = rtrim($path, '/') . '/';
260 2
        $req = new Rest($this->config);
261 2
        $res = $req->request('POST', $path)
262 2
            ->withHeader('folder', 'true')
263 2
            ->send();
264 2
        return $res->getStatusCode() === 200;
265
    }
266
267
    /**
268
     * 删除文件或者目录
269
     *
270
     * @param string $path 需要被删除的云存储文件或目录路径
271
     *
272
     * @return bool 成功返回 true,否则 false
273
     * @throws \Exception
274
     */
275 1
    public function deleteDir($path)
276
    {
277 1
        return $this->delete($path);
278
    }
279
280
    /**
281
     * 获取目录下存储使用量
282
     *
283
     * @param string $path 云存储目录路径,默认为根目录,表示整个云存储服务使用的空间大小
284
     * @return string 存储使用量,单位字节
285
     * @throws \Exception
286
     */
287 1 View Code Duplication
    public function usage($path = '/')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
288
    {
289 1
        $path = rtrim($path, '/') . '/';
290 1
        $req = new Rest($this->config);
291 1
        $response = $req->request('GET', $path . '?usage')
292 1
            ->send();
293
294 1
        return $response->getBody()->getContents();
295
    }
296
297
    /**
298
     * 刷新缓存
299
     *
300
     * @param array|string $urls 需要刷新的文件 url 列表
301
     *
302
     * @return array 刷新失败的 url 列表,若全部刷新成功则为空数组
303
     */
304 1
    public function purge($urls)
305
    {
306 1
        $urlString = $urls;
307 1
        if (is_array($urls)) {
308
            $urlString = implode("\n", $urls);
309
        }
310
311 1
        $client = new Client([
312 1
            'timeout' => $this->config->timeout
313 1
        ]);
314 1
        $response = $client->request('POST', Config::ED_PURGE, [
315 1
            'headers' =>  Signature::getPurgeSignHeader($this->config, $urlString),
316 1
            'form_params' => ['purge' => $urlString]
317 1
        ]);
318 1
        $result = json_decode($response->getBody()->getContents(), true);
319 1
        return $result['invalid_domain_of_url'];
320
    }
321
322
    /**
323
     * 异步云处理
324
     *
325
     * 该方法是基于[又拍云云处理](http://docs.upyun.com/cloud/) 服务实现,可以实现音视频的转码、切片、剪辑;文件的压缩解压缩;文件拉取功能
326
     *
327
     * 注意:
328
     * - 所有需要调用该方法处理的资源,必须已经上传到云存储服务
329
     * - 使用 `process` 之前,必须配置 `config->processNotifyUrl`,否则会提交任务失败
330
     *
331
     * 例如视频转码:
332
     * ```
333
     *  process(array(
334
     *    array(
335
     *        'type' => 'video',  // video 表示视频任务, audio 表示音频任务
336
     *        'avopts' => '/s/240p(4:3)/as/1/r/30', // 处理参数,`s` 表示输出的分辨率,`r` 表示视频帧率,`as` 表示是否自动调整分辨率
337
     *        'save_as' => '/video/240/new.mp4', // 新视频在又拍云存储的保存路径
338
     *    ),
339
     *    ... // 同时还可以添加其他任务
340
     * ), Upyun::$PROCESS_TYPE_MEDIA, $source)
341
     * ```
342
     *
343
     * @param array $tasks 需要处理的任务
344
     * @param string $type 异步云处理任务类型,可选值:
345
     * - `Upyun::$PROCESS_TYPE_MEDIA` 异步音视频处理
346
     * - `Upyun::$PROCESS_TYPE_ZIP` 文件压缩
347
     * - `Upyun::$PROCESS_TYPE_UNZIP` 文件解压
348
     * - `Upyun::$PROCESS_TYPE_SYNC_FILE` 文件拉取
349
     * - `Upyun::$PROCESS_TYPE_STITCH` 图片拼接
350
     * @param string $source 可选参数,处理异步音视频任务时,需要传递该参数,表示需要处理的文件路径
351
     *
352
     * @return array 任务 ID,提交了多少任务,便会返回多少任务 ID,与提交任务的顺序保持一致。可以通过任务 ID 查询处理进度。格式如下:
353
     * ```
354
     * array(
355
     * '35f0148d414a688a275bf915ba7cebb2',
356
     * '98adbaa52b2f63d6d7f327a0ff223348',
357
     * )
358
     * ```
359
     * @throws \Exception
360
     */
361 1
    public function process($tasks, $type, $source = '')
362
    {
363 1
        $video = new Api\Pretreat($this->config);
364
365 1
        $options = array();
366
        switch($type) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after SWITCH keyword; 0 found
Loading history...
367 1
            case self::$PROCESS_TYPE_MEDIA:
368 1
                $options['accept'] = 'json';
369 1
                $options['source'] = $source;
370 1
                break;
371 1
            case self::$PROCESS_TYPE_ZIP:
372 1
                $options['app_name'] = 'compress';
373 1
                break;
374
            case self::$PROCESS_TYPE_UNZIP:
375
                $options['app_name'] = 'depress';
376
                break;
377
            case self::$PROCESS_TYPE_SYNC_FILE:
378
                $options['app_name'] = 'spiderman';
379
                break;
380
            case self::$PROCESS_TYPE_SYNC_FILE:
381
                $options['app_name'] = 'uconvert';
382
                break;
383
            case self::$PROCESS_TYPE_STITCH:
384
                $options['app_name'] = 'jigsaw';
385
                break;
386
            default:
387
                throw new \Exception('upyun - not support process type.');
388
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
389
        }
390 1
        return $video->process($tasks, $options);
391
    }
392
393
    /**
394
     * 查询异步云处理任务进度
395
     *
396
     * 根据 `process` 方法返回的任务 ID,通过该访问查询处理进度
397
     *
398
     * @param array $taskIds 任务 ID
399
     *
400
     * @return bool|array 查询失败返回布尔值 `false`,否则返回每个任务的百分比进度信息,格式如下:
401
     * ```
402
     * array(
403
     *     '35f0148d414a688a275bf915ba7cebb2' => 100,  // 100 表示任务完成
404
     *     'c3103189fa906a5354d29bd807e8dc51' => 35,
405
     *     '98adbaa52b2f63d6d7f327a0ff223348' => null, // null 表示任务未开始,或异常
406
     * )
407
     * ```
408
     */
409 1
    public function queryProcessStatus($taskIds)
410
    {
411 1
        $video = new Api\Pretreat($this->config);
412 1
        return $video->query($taskIds, '/status/');
413
    }
414
415
    /**
416
     *  查询异步云处理任务结果
417
     *
418
     * 根据 `process` 方法返回的任务 ID,通过该访问查询处理结果,会包含每个任务详细信息
419
     * @param array $taskIds 任务 ID
420
     *
421
     * @return bool|mixed 查询失败返回 `false`,否则返回每个任务的处理结果,格式如下:
422
     * ```
423
     * array(
424
     *    '9d9c32b63a1034834e77672c6f51f661' => array(
425
     *         'path' => array('/v2.mp4'),
426
     *         'signature' => '4042c1f07f546d28',
427
     *         'status_code' => 200,
428
     *         'service_name' => 'your_storage_service',
429
     *         'description' => 'OK',
430
     *         'task_id' => '9d9c32b63a1034834e77672c6f51f661',
431
     *         'timestamp' => 1472010684
432
     *    )
433
     * )
434
     * ```
435
     */
436 1
    public function queryProcessResult($taskIds)
437
    {
438 1
        $video = new Api\Pretreat($this->config);
439 1
        return $video->query($taskIds, '/result/');
440
    }
441
442
    /**
443
     * 多个 m3u8 文件拼接
444
     * @param array $files  保存在又拍云云存储中的多个 m3u8 文件路径
445
     * @param string $saveAs 拼接生成的新 m3u8 文件保存路径
446
     *
447
     * @return array 见 [m3u8 拼接 - 响应](http://docs.upyun.com/cloud/sync_video/#_3)
448
     */
449
    public function m3u8Concat($files, $saveAs)
450
    {
451
        $p = new Api\SyncVideo($this->config);
452
        return $p->process([
453
            'm3u8s' => $files,
454
            'save_as' => $saveAs,
455
        ], '/m3u8er/concat');
456
    }
457
458
    /**
459
     * 单个 m3u8 文件剪辑
460
     * @param string $file 需要剪辑的又拍云云存储中的 m3u8 文件路径
461
     * @param string $saveAs 剪辑完成后新的 m3u8 文件保存路径
462
     * @param array $slice 需要被保留或删除的片段。
463
     * @param bool $$isInclude 默认为 `true` 表示 `$slice` 参数描述的片段被保留,否则表示 `$slice` 参数描述的片段被删除
0 ignored issues
show
Documentation introduced by
There is no parameter named $$isInclude. Did you maybe mean $isInclude?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
464
     * @param bool $index 指定 `$slice` 参数的格式,默认为 `false` 表示使用时间范围描述片段,单位秒:`[<开始时间>, <结束时间>]`;`true` 表示使用 `m3u8` 文件的分片序号,从 0 开始,这种方式可以一次对多个片段操作
465
     *
466
     * @return array 见 [m3u8 剪辑 - 响应](http://docs.upyun.com/cloud/sync_video/#_6)
467
     */
468
    public function m3u8Clip($file, $saveAs, $slice = array(), $isInclude = true, $index = false)
469
    {
470
        $p = new Api\SyncVideo($this->config);
471
        $params = [
472
            'm3u8' => $file,
473
            'save_as' => $saveAs,
474
            'index' => $index,
475
        ];
476
        if ($$isInclude) {
477
            $params['include'] = $slice;
478
        } else {
479
            $params['exclude'] = $slice;
480
        }
481
        return $p->process($params, '/m3u8er/clip');
482
    }
483
484
    /**
485
     * 获取单个 m3u8 文件描述信息
486
     * @param string $file 又拍云云存储的中的 m3u8 文件路径
487
     *
488
     * @return array 见 [获取 m3u8 信息 - 响应](http://docs.upyun.com/cloud/sync_video/#_6)
489
     */
490
    public function m3u8Meta($file)
491
    {
492
        $p = new Api\SyncVideo($this->config);
493
        return $p->process([
494
            'm3u8' => $file,
495
        ], '/m3u8er/get_meta');
496
    }
497
498
    /**
499
     * 视频截图,可以对 mp4、m3u8 等视频文件进行截图
500
     * @param string $file 需要截图的又拍云云存储中的视频文件路径
501
     * @param string $saveAs 截图保存路径
502
     * @param string $point 截图时间点,`HH:MM:SS` 格式
503
     * @param string $size 截图尺寸 `宽x高` 格式的字符串。默认和视频尺寸一致
504
     * @param string $format 截图保存的格式,默认根据 `$saveAs` 参数的后缀生成,可以指定 `jpg | png | webp` 三种格式
505
     *
506
     * @return array 见 [视频截图 - 响应](http://docs.upyun.com/cloud/sync_video/#m3u8_2)
507
     */
508 1
    public function snapshot($file, $saveAs, $point, $size = '', $format = '')
509
    {
510 1
        $p = new Api\SyncVideo($this->config);
511
        $params = [
512 1
            'source' => $file,
513 1
            'save_as' => $saveAs,
514 1
            'point' => $point,
515 1
        ];
516 1
        if ($size) {
517 1
            $params['size'] = $size;
518 1
        }
519 1
        if ($format) {
520 1
            $params['format'] = $format;
521 1
        }
522 1
        return $p->process($params, '/snapshot');
523
    }
524
525
    /**
526
     * 获取音视频文件元信息
527
     * @param string $file 又拍云云存储的中的音视频文件路径
528
     *
529
     * @return array 见 [获取音视频文件信息 - 响应](http://docs.upyun.com/cloud/sync_video/#_16)
530
     */
531 1
    public function avMeta($file)
532
    {
533 1
        $p = new Api\SyncVideo($this->config);
534 1
        return $p->process([
535 1
            'source' => $file,
536 1
        ], '/avmeta/get_meta');
537
    }
538
}
539