Issues (20)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Client/Cosapi.php (10 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Freyo\Flysystem\QcloudCOSv3\Client;
4
5
class Cosapi
6
{
7
    //计算sign签名的时间参数
8
    const EXPIRED_SECONDS = 180;
9
    //512K
10
    const SLICE_SIZE_512K = 524288;
11
    //1M
12
    const SLICE_SIZE_1M = 1048576;
13
    //2M
14
    const SLICE_SIZE_2M = 2097152;
15
    //3M
16
    const SLICE_SIZE_3M = 3145728;
17
    //20M 大于20M的文件需要进行分片传输
18
    const MAX_UNSLICE_FILE_SIZE = 20971520;
19
    //失败尝试次数
20
    const MAX_RETRY_TIMES = 3;
21
    //返回的错误码
22
    const COSAPI_PARAMS_ERROR = -1;
23
    const COSAPI_NETWORK_ERROR = -2;
24
25
    //HTTP请求超时时间
26
    private static $timeout = 60;
27
28
    /**
29
     * 获取当前指定时区的 Unix 时间戳
30
     *
31
     * @param string $timezone
32
     *
33
     * @return int
34
     */
35 14
    public static function time($timezone = 'Asia/Shanghai')
36
    {
37 14
        return date_create('now', timezone_open($timezone))->getTimestamp();
38
    }
39
40
    /*
41
     * 设置HTTP请求超时时间
42
     *
43
     * @param  int  $timeout  超时时长
44
     *
45
     * @return bool
46
     */
47
    public static function setTimeout($timeout = 60)
48
    {
49
        if (!is_int($timeout) || $timeout < 0) {
50
            return false;
51
        }
52
53
        self::$timeout = $timeout;
54
55
        return true;
56
    }
57
58
    /**
59
     * 上传文件,自动判断文件大小,如果小于20M则使用普通文件上传,大于20M则使用分片上传.
60
     *
61
     * @param string $bucketName bucket名称
62
     * @param string $srcPath    本地文件路径
63
     * @param string $dstPath    上传的文件路径
64
     * @param string $bizAttr    文件属性
65
     * @param string $sliceSize  分片大小(512k,1m,2m,3m),默认:1m
66
     * @param string $insertOnly 同名文件是否覆盖
67
     *
68
     * @return array
69
     */
70 2
    public static function upload($bucketName, $srcPath, $dstPath,
71
                $bizAttr = null, $sliceSize = null, $insertOnly = null)
72
    {
73 2 View Code Duplication
        if (!file_exists($srcPath)) {
0 ignored issues
show
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...
74
            return [
75
                    'code'    => self::COSAPI_PARAMS_ERROR,
76
                    'message' => 'file '.$srcPath.' not exists',
77
                    'data'    => [], ];
78
        }
79
80 2
        $dstPath = '/'.ltrim($dstPath, '/');
81
82
        //文件大于20M则使用分片传输
83 2
        if (filesize($srcPath) < self::MAX_UNSLICE_FILE_SIZE) {
84 2
            return self::uploadfile($bucketName, $srcPath, $dstPath, $bizAttr, $insertOnly);
85
        } else {
86
            $sliceSize = self::getSliceSize($sliceSize);
87
88
            return self::upload_slice($bucketName, $srcPath, $dstPath, $bizAttr, $sliceSize, $insertOnly);
89
        }
90
    }
91
92
    /**
93
     * 创建目录.
94
     *
95
     * @param string $bucketName bucket名称
96
     * @param string $path       目录路径
97
     * @param string $bizAttr    目录属性
98
     *
99
     * @return array
100
     */
101 1
    public static function createFolder($bucketName, $path, $bizAttr = null)
102
    {
103 1
        $path = self::normalizerPath($path, true);
104 1
        $path = self::cosUrlEncode($path);
105 1
        $expired = self::time() + self::EXPIRED_SECONDS;
106 1
        $url = self::generateResUrl($bucketName, $path);
107 1
        $sign = Auth::appSign($expired, $bucketName);
108
109
        $data = [
110 1
            'op'       => 'create',
111 1
            'biz_attr' => (isset($bizAttr) ? $bizAttr : ''),
112 1
        ];
113
114 1
        $data = json_encode($data);
115
116
        $req = [
117 1
            'url'     => $url,
118 1
            'method'  => 'post',
119 1
            'timeout' => self::$timeout,
120 1
            'data'    => $data,
121
            'header'  => [
122 1
                'Authorization:'.$sign,
123 1
                'Content-Type: application/json',
124 1
            ],
125 1
        ];
126
127 1
        return self::sendRequest($req);
128
    }
129
130
    /**
131
     * 目录列表.
132
     *
133
     * @param string $bucketName bucket名称
134
     * @param string $path       目录路径,sdk会补齐末尾的 '/'
135
     * @param int    $num        拉取的总数
136
     * @param string $pattern    eListBoth,ListDirOnly,eListFileOnly  默认both
137
     * @param int    $order      默认正序(=0), 填1为反序,
138
     * @param string $context    透传字段,用于翻页,前端不需理解,需要往前/往后翻页则透传回来
139
     *
140
     * @return array
141
     */
142 1 View Code Duplication
    public static function listFolder(
0 ignored issues
show
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...
143
                    $bucketName, $path, $num = 20,
144
                    $pattern = 'eListBoth', $order = 0,
145
                    $context = null)
146
    {
147 1
        $path = self::normalizerPath($path, true);
148
149 1
        return self::listBase($bucketName, $path, $num,
150 1
                $pattern, $order, $context);
151
    }
152
153
    /**
154
     * 目录列表(前缀搜索).
155
     *
156
     * @param string $bucketName bucket名称
157
     * @param string $prefix     列出含此前缀的所有文件
158
     * @param int    $num        拉取的总数
159
     * @param string $pattern    eListBoth(默认),ListDirOnly,eListFileOnly
160
     * @param int    $order      默认正序(=0), 填1为反序,
161
     * @param string $context    透传字段,用于翻页,前端不需理解,需要往前/往后翻页则透传回来
162
     *
163
     * @return array
164
     */
165 View Code Duplication
    public static function prefixSearch(
0 ignored issues
show
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...
166
                    $bucketName, $prefix, $num = 20,
167
                    $pattern = 'eListBoth', $order = 0,
168
                    $context = null)
169
    {
170
        $path = self::normalizerPath($prefix);
171
172
        return self::listBase($bucketName, $path, $num,
173
                $pattern, $order, $context);
174
    }
175
176
    /**
177
     * 目录更新.
178
     *
179
     * @param string $bucketName bucket名称
180
     * @param string $path       文件夹路径,SDK会补齐末尾的 '/'
181
     * @param string $bizAttr    目录属性
182
     *
183
     * @return array
184
     */
185
    public static function updateFolder($bucketName, $path, $bizAttr = null)
186
    {
187
        $path = self::normalizerPath($path, true);
188
189
        return self::updateBase($bucketName, $path, $bizAttr);
190
    }
191
192
    /**
193
     * 查询目录信息.
194
     *
195
     * @param string $bucketName bucket名称
196
     * @param string $path       目录路径
197
     *
198
     * @return array
199
     */
200
    public static function statFolder($bucketName, $path)
201
    {
202
        $path = self::normalizerPath($path, true);
203
204
        return self::statBase($bucketName, $path);
205
    }
206
207
    /**
208
     * 删除目录.
209
     *
210
     * @param string $bucketName bucket名称
211
     * @param string $path       目录路径
212
     *                           注意不能删除bucket下根目录/
213
     *
214
     * @return array
215
     */
216 1
    public static function delFolder($bucketName, $path)
217
    {
218 1
        $path = self::normalizerPath($path, true);
219
220 1
        return self::delBase($bucketName, $path);
221
    }
222
223
    /**
224
     * 更新文件.
225
     *
226
     * @param string $bucketName             bucket名称
227
     * @param string $path                   文件路径
228
     * @param null   $bizAttr
229
     * @param string $authority              :  eInvalid(继承Bucket的读写权限)/eWRPrivate(私有读写)/eWPrivateRPublic(公有读私有写)
230
     * @param array  $customer_headers_array 携带的用户自定义头域,包括
231
     *                                       'Cache-Control' => '*'
232
     *                                       'Content-Type' => '*'
233
     *                                       'Content-Disposition' => '*'
234
     *                                       'Content-Language' => '*'
235
     *                                       'x-cos-meta-自定义内容' => '*'
236
     *
237
     * @return array
238
     */
239 1
    public static function update($bucketName, $path,
240
                    $bizAttr = null, $authority = null, $customer_headers_array = null)
241
    {
242 1
        $path = self::normalizerPath($path);
243
244 1
        return self::updateBase($bucketName, $path, $bizAttr, $authority, $customer_headers_array);
245
    }
246
247
    /**
248
     * 移动(重命名)文件.
249
     *
250
     * @param string $bucketName  bucket名称
251
     * @param string $srcPath     源文件路径
252
     * @param string $dstPath     目的文件名(可以是单独文件名也可以是带目录的文件名)
253
     * @param int    $toOverWrite 是否覆盖(当目的文件名已经存在同名文件时是否覆盖)
254
     *
255
     * @return array
256
     */
257 1
    public static function move($bucketName, $srcPath, $dstPath, $toOverWrite = 0)
258
    {
259 1
        $srcPath = self::normalizerPath($srcPath);
260 1
        $dstPath = self::normalizerPath($dstPath);
261
262 1
        $srcPath = self::cosUrlEncode($srcPath);
263 1
        $url = self::generateResUrl($bucketName, $srcPath);
264 1
        $sign = Auth::appSign_once($srcPath, $bucketName);
265
266
        $data = [
267 1
            'op'            => 'move',
268 1
            'dest_fileid'   => $dstPath,
269 1
            'to_over_write' => $toOverWrite,
270 1
        ];
271
272 1
        $data = json_encode($data);
273
274
        $req = [
275 1
            'url'     => $url,
276 1
            'method'  => 'post',
277 1
            'timeout' => self::$timeout,
278 1
            'data'    => $data,
279
            'header'  => [
280 1
                    'Authorization: '.$sign,
281 1
                    'Content-Type: application/json',
282 1
            ],
283 1
        ];
284
285 1
        return self::sendRequest($req);
286
    }
287
288
    /**
289
     * 查询文件信息.
290
     *
291
     * @param string $bucketName bucket名称
292
     * @param string $path       文件路径
293
     *
294
     * @return array
295
     */
296 6
    public static function stat($bucketName, $path)
297
    {
298 6
        $path = self::normalizerPath($path);
299
300 6
        return self::statBase($bucketName, $path);
301
    }
302
303
    /**
304
     * 删除文件.
305
     *
306
     * @param string $bucketName
307
     * @param string $path       文件路径
308
     *
309
     * @return array
310
     */
311 1
    public static function delFile($bucketName, $path)
312
    {
313 1
        $path = self::normalizerPath($path);
314
315 1
        return self::delBase($bucketName, $path);
316
    }
317
318
    /**
319
     * 内部方法, 上传文件.
320
     *
321
     * @param string $bucketName bucket名称
322
     * @param string $srcPath    本地文件路径
323
     * @param string $dstPath    上传的文件路径
324
     * @param string $bizAttr    文件属性
325
     * @param int    $insertOnly 是否覆盖同名文件:0 覆盖,1:不覆盖
326
     *
327
     * @return array
328
     */
329 2
    private static function uploadfile($bucketName, $srcPath, $dstPath, $bizAttr = null, $insertOnly = null)
330
    {
331 2
        $srcPath = realpath($srcPath);
332 2
        $dstPath = self::cosUrlEncode($dstPath);
333
334 2 View Code Duplication
        if (filesize($srcPath) >= self::MAX_UNSLICE_FILE_SIZE) {
0 ignored issues
show
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...
335
            return [
336
                    'code'    => self::COSAPI_PARAMS_ERROR,
337
                    'message' => 'file '.$srcPath.' larger then 20M, please use upload_slice interface',
338
                    'data'    => [], ];
339
        }
340
341 2
        $expired = self::time() + self::EXPIRED_SECONDS;
342 2
        $url = self::generateResUrl($bucketName, $dstPath);
343 2
        $sign = Auth::appSign($expired, $bucketName);
344 2
        $sha1 = hash_file('sha1', $srcPath);
345
346
        $data = [
347 2
            'op'       => 'upload',
348 2
            'sha'      => $sha1,
349 2
            'biz_attr' => (isset($bizAttr) ? $bizAttr : ''),
350 2
        ];
351
352 2
        if (function_exists('curl_file_create')) {
353 2
            $data['filecontent'] = curl_file_create($srcPath);
354 2
        } else {
355
            $data['filecontent'] = '@'.$srcPath;
356
        }
357
358 2
        if (isset($insertOnly) && strlen($insertOnly) > 0) {
359 2
            $data['insertOnly'] = (($insertOnly == 0 || $insertOnly == '0') ? 0 : 1);
360 2
        }
361
362
        $req = [
363 2
            'url'     => $url,
364 2
            'method'  => 'post',
365 2
            'timeout' => self::$timeout,
366 2
            'data'    => $data,
367
            'header'  => [
368 2
                'Authorization:'.$sign,
369 2
            ],
370 2
        ];
371
372 2
        return self::sendRequest($req);
373
    }
374
375
    /**
376
     * 内部方法,上传文件.
377
     *
378
     * @param string $bucketName bucket名称
379
     * @param string $srcPath    本地文件路径
380
     * @param string $dstPath    上传的文件路径
381
     * @param string $bizAttr    文件属性
382
     * @param string $sliceSize  分片大小
383
     * @param int    $insertOnly 是否覆盖同名文件:0 覆盖,1:不覆盖
384
     *
385
     * @return array
386
     */
387
    private static function upload_slice(
388
        $bucketName, $srcPath, $dstPath,
389
        $bizAttr = null, $sliceSize = null, $insertOnly = null)
390
    {
391
        $srcPath = realpath($srcPath);
392
        $fileSize = filesize($srcPath);
393
        $dstPath = self::cosUrlEncode($dstPath);
394
395
        $expired = self::time() + self::EXPIRED_SECONDS;
396
        $url = self::generateResUrl($bucketName, $dstPath);
397
        $sign = Auth::appSign($expired, $bucketName);
398
        $sha1 = hash_file('sha1', $srcPath);
399
400
        $ret = self::upload_prepare(
401
                $fileSize, $sha1, $sliceSize,
402
                $sign, $url, $bizAttr, $insertOnly);
403
404
        if ($ret['code'] != 0) {
405
            return $ret;
406
        }
407
408
        if (isset($ret['data'])
409
                && isset($ret['data']['url'])) {
410
            //秒传命中,直接返回了url
411
            return $ret;
412
        }
413
414
        $sliceSize = $ret['data']['slice_size'];
415
        if ($sliceSize > self::SLICE_SIZE_3M ||
416
            $sliceSize <= 0) {
417
            $ret['code'] = self::COSAPI_PARAMS_ERROR;
418
            $ret['message'] = 'illegal slice size';
419
420
            return $ret;
421
        }
422
423
        $session = $ret['data']['session'];
424
        $offset = $ret['data']['offset'];
425
426
        $sliceCnt = ceil($fileSize / $sliceSize);
427
        // expired seconds for one slice mutiply by slice count
428
        // will be the expired seconds for whole file
429
        $expired = self::time() + (self::EXPIRED_SECONDS * $sliceCnt);
430
        $sign = Auth::appSign($expired, $bucketName);
431
432
        $ret = self::upload_data(
433
                $fileSize, $sha1, $sliceSize,
434
                $sign, $url, $srcPath,
435
                $offset, $session);
436
437
        return $ret;
438
    }
439
440
    /**
441
     * 第一个分片控制消息.
442
     *
443
     * @param string $fileSize   文件大小
444
     * @param string $sha1       文件sha值
445
     * @param string $sliceSize  分片大小
446
     * @param string $sign       签名
447
     * @param string $url        URL
448
     * @param string $bizAttr    文件属性
449
     * @param string $insertOnly 同名文件是否覆盖
450
     *
451
     * @return array
452
     */
453
    private static function upload_prepare(
454
        $fileSize, $sha1, $sliceSize,
455
        $sign, $url, $bizAttr = null, $insertOnly = null)
456
    {
457
        $data = [
458
            'op'       => 'upload_slice',
459
            'filesize' => $fileSize,
460
            'sha'      => $sha1,
461
        ];
462
463
        if (isset($bizAttr) && strlen($bizAttr)) {
464
            $data['biz_attr'] = $bizAttr;
465
        }
466
467
        if (isset($insertOnly)) {
468
            $data['insertOnly'] = (($insertOnly == 0) ? 0 : 1);
469
        }
470
471
        if ($sliceSize <= self::SLICE_SIZE_3M) {
472
            $data['slice_size'] = $sliceSize;
473
        } else {
474
            $data['slice_size'] = self::SLICE_SIZE_3M;
475
        }
476
477
        $req = [
478
            'url'     => $url,
479
            'method'  => 'post',
480
            'timeout' => self::$timeout,
481
            'data'    => $data,
482
            'header'  => [
483
                'Authorization:'.$sign,
484
            ],
485
        ];
486
487
        $ret = self::sendRequest($req);
488
489
        return $ret;
490
    }
491
492
    /**
493
     * 分片上传.
494
     *
495
     * @param int    $fileSize  文件大小
496
     * @param string $sha1      文件sha值
497
     * @param int    $sliceSize 文件分片大小
498
     * @param string $sign      签名
499
     * @param string $url       url
500
     * @param string $srcPath   源文件路径
501
     * @param int    $offset    文件偏移offset
502
     * @param string $session   session
503
     *
504
     * @return array
505
     */
506
    private static function upload_data(
507
            $fileSize, $sha1, $sliceSize,
508
            $sign, $url, $srcPath,
509
            $offset, $session)
510
    {
511
        while ($fileSize > $offset) {
512
            $filecontent = file_get_contents(
513
                    $srcPath, false, null,
514
                    $offset, $sliceSize);
515
516 View Code Duplication
            if ($filecontent === false) {
0 ignored issues
show
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...
517
                return [
518
                    'code'    => self::COSAPI_PARAMS_ERROR,
519
                    'message' => 'read file '.$srcPath.' error',
520
                    'data'    => [],
521
                ];
522
            }
523
524
            $boundary = '---------------------------'.substr(md5(mt_rand()), 0, 10);
525
            $data = self::generateSliceBody(
526
                    $filecontent, $offset, $sha1,
527
                    $session, basename($srcPath), $boundary);
528
529
            $req = [
530
                'url'     => $url,
531
                'method'  => 'post',
532
                'timeout' => self::$timeout,
533
                'data'    => $data,
534
                'header'  => [
535
                    'Authorization:'.$sign,
536
                    'Content-Type: multipart/form-data; boundary='.$boundary,
537
                ],
538
            ];
539
540
            $retry_times = 0;
541
            do {
542
                $ret = self::sendRequest($req);
543
                if ($ret['code'] == 0) {
544
                    break;
545
                }
546
                $retry_times++;
547
            } while ($retry_times < self::MAX_RETRY_TIMES);
548
549
            if ($ret['code'] != 0) {
550
                return $ret;
551
            }
552
553
            if (!empty($ret['data']['session'])) {
554
                $session = $ret['data']['session'];
555
            }
556
557
            $offset += $sliceSize;
558
        }
559
560
        return $ret;
0 ignored issues
show
The variable $ret does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
561
    }
562
563
    /**
564
     * 构造分片body体.
565
     *
566
     * @param string $fileContent 文件内容
567
     * @param string $offset      文件偏移
568
     * @param string $sha         文件sha值
569
     * @param string $session     session
570
     * @param string $fileName    文件名
571
     * @param string $boundary    分隔符
572
     *
573
     * @return string
574
     */
575
    private static function generateSliceBody(
576
            $fileContent, $offset, $sha,
0 ignored issues
show
The parameter $sha is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
577
            $session, $fileName, $boundary)
578
    {
579
        $formdata = '';
580
581
        $formdata .= '--'.$boundary."\r\n";
582
        $formdata .= "content-disposition: form-data; name=\"op\"\r\n\r\nupload_slice\r\n";
583
584
        $formdata .= '--'.$boundary."\r\n";
585
        $formdata .= "content-disposition: form-data; name=\"offset\"\r\n\r\n".$offset."\r\n";
586
587
        $formdata .= '--'.$boundary."\r\n";
588
        $formdata .= "content-disposition: form-data; name=\"session\"\r\n\r\n".$session."\r\n";
589
590
        $formdata .= '--'.$boundary."\r\n";
591
        $formdata .= 'content-disposition: form-data; name="fileContent"; filename="'.$fileName."\"\r\n";
592
        $formdata .= "content-type: application/octet-stream\r\n\r\n";
593
594
        $data = $formdata.$fileContent."\r\n--".$boundary."--\r\n";
595
596
        return $data;
597
    }
598
599
    /**
600
     * 内部公共函数.
601
     *
602
     * @param string $bucketName bucket名称
603
     * @param string $path       文件夹路径
604
     * @param int    $num        拉取的总数
605
     * @param string $pattern    eListBoth(默认),ListDirOnly,eListFileOnly
606
     * @param int    $order      默认正序(=0), 填1为反序,
607
     * @param string $context    在翻页查询时候用到
608
     *
609
     * @return array
610
     */
611 1
    private static function listBase(
612
                    $bucketName, $path, $num = 20,
613
                    $pattern = 'eListBoth', $order = 0, $context = null)
614
    {
615 1
        $path = self::cosUrlEncode($path);
616 1
        $expired = self::time() + self::EXPIRED_SECONDS;
617 1
        $url = self::generateResUrl($bucketName, $path);
618 1
        $sign = Auth::appSign($expired, $bucketName);
619
620
        $data = [
621 1
            'op' => 'list',
622 1
        ];
623
624 1
        if (self::isPatternValid($pattern) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
625
            return [
626
                    'code'    => self::COSAPI_PARAMS_ERROR,
627
                    'message' => 'parameter pattern invalid',
628
                ];
629
        }
630 1
        $data['pattern'] = $pattern;
631
632 1
        if ($order != 0 && $order != 1) {
633
            return [
634
                    'code'    => self::COSAPI_PARAMS_ERROR,
635
                    'message' => 'parameter order invalid',
636
            ];
637
        }
638 1
        $data['order'] = $order;
639
640 1
        if ($num < 0 || $num > 199) {
641
            return [
642
                    'code'    => self::COSAPI_PARAMS_ERROR,
643
                    'message' => 'parameter num invalid, num need less then 200',
644
            ];
645
        }
646 1
        $data['num'] = $num;
647
648 1
        if (isset($context)) {
649
            $data['context'] = $context;
650
        }
651
652 1
        $url = $url.'?'.http_build_query($data);
653
654
        $req = [
655 1
            'url'     => $url,
656 1
            'method'  => 'get',
657 1
            'timeout' => self::$timeout,
658
            'header'  => [
659 1
                'Authorization:'.$sign,
660 1
            ],
661 1
        ];
662
663 1
        return self::sendRequest($req);
664
    }
665
666
    /**
667
     * 内部公共方法(更新文件和更新文件夹).
668
     *
669
     * @param string $bucketName           bucket名称
670
     * @param string $path                 路径
671
     * @param string $bizAttr              文件/目录属性
672
     * @param string $authority            :  eInvalid/eWRPrivate(私有)/eWPrivateRPublic(公有读写)
673
     * @param array  $custom_headers_array 携带的用户自定义头域,包括
674
     *                                     'Cache-Control' => '*'
675
     *                                     'Content-Type' => '*'
676
     *                                     'Content-Disposition' => '*'
677
     *                                     'Content-Language' => '*'
678
     *                                     'x-cos-meta-自定义内容' => '*'
679
     *
680
     * @return array|mixed
681
     */
682 1
    private static function updateBase($bucketName, $path,
683
                    $bizAttr = null, $authority = null, $custom_headers_array = null)
684
    {
685 1
        $path = self::cosUrlEncode($path);
686
687 1
        $url = self::generateResUrl($bucketName, $path);
688 1
        $sign = Auth::appSign_once(
689 1
                $path, $bucketName);
690
691
        $data = [
692 1
            'op' => 'update',
693 1
        ];
694
695 1
        $flag = 0;
696 1
        if (isset($bizAttr)) {
697
            $data['biz_attr'] = $bizAttr;
698
            $flag = $flag | 0x01;
699
        }
700
701 1
        if (isset($authority) && strlen($authority) > 0) {
702 1
            if (self::isAuthorityValid($authority) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
703
                return [
704
                    'code'    => self::COSAPI_PARAMS_ERROR,
705
                    'message' => 'parameter authority invalid',
706
                    ];
707
            }
708
709 1
            $data['authority'] = $authority;
710 1
            $flag = $flag | 0x80;
711 1
        }
712
713 1
        if (isset($custom_headers_array)) {
714
            $data['custom_headers'] = [];
715
            self::add_customer_header($data['custom_headers'], $custom_headers_array);
716
            $flag = $flag | 0x40;
717
        }
718
719 1
        if ($flag != 0 && $flag != 1) {
720 1
            $data['flag'] = $flag;
721 1
        }
722
723 1
        $data = json_encode($data);
724
725
        $req = [
726 1
            'url'     => $url,
727 1
            'method'  => 'post',
728 1
            'timeout' => self::$timeout,
729 1
            'data'    => $data,
730
            'header'  => [
731 1
                'Authorization:'.$sign,
732 1
                'Content-Type: application/json',
733 1
            ],
734 1
        ];
735
736 1
        return self::sendRequest($req);
737
    }
738
739
    /**
740
     * 内部方法.
741
     *
742
     * @param string $bucketName bucket名称
743
     * @param string $path       文件/目录路径
744
     *
745
     * @return array
746
     */
747 6
    private static function statBase($bucketName, $path)
748
    {
749 6
        $path = self::cosUrlEncode($path);
750 6
        $expired = self::time() + self::EXPIRED_SECONDS;
751 6
        $url = self::generateResUrl($bucketName, $path);
752 6
        $sign = Auth::appSign($expired, $bucketName);
753
754
        $data = [
755 6
            'op' => 'stat',
756 6
        ];
757
758 6
        $url = $url.'?'.http_build_query($data);
759
760
        $req = [
761 6
            'url'     => $url,
762 6
            'method'  => 'get',
763 6
            'timeout' => self::$timeout,
764
            'header'  => [
765 6
                'Authorization:'.$sign,
766 6
            ],
767 6
        ];
768
769 6
        return self::sendRequest($req);
770
    }
771
772
    /**
773
     * 内部私有方法.
774
     *
775
     * @param string $bucketName bucket名称
776
     * @param string $path       文件/目录路径路径
777
     *
778
     * @return array
779
     */
780 2
    private static function delBase($bucketName, $path)
781
    {
782 2
        if ($path == '/') {
783
            return [
784
                    'code'    => self::COSAPI_PARAMS_ERROR,
785
                    'message' => 'can not delete bucket using api! go to http://console.qcloud.com/cos to operate bucket',
786
                    ];
787
        }
788
789 2
        $path = self::cosUrlEncode($path);
790
791 2
        $url = self::generateResUrl($bucketName, $path);
792 2
        $sign = Auth::appSign_once(
793 2
                $path, $bucketName);
794
795
        $data = [
796 2
            'op' => 'delete',
797 2
        ];
798
799 2
        $data = json_encode($data);
800
801
        $req = [
802 2
            'url'     => $url,
803 2
            'method'  => 'post',
804 2
            'timeout' => self::$timeout,
805 2
            'data'    => $data,
806
            'header'  => [
807 2
                'Authorization:'.$sign,
808 2
                'Content-Type: application/json',
809 2
            ],
810 2
        ];
811
812 2
        return self::sendRequest($req);
813
    }
814
815
    /**
816
     * 内部公共方法, 路径编码
817
     *
818
     * @param string $path 待编码路径
819
     *
820
     * @return mixed
821
     */
822 14
    private static function cosUrlEncode($path)
823
    {
824 14
        return str_replace('%2F', '/', rawurlencode($path));
825
    }
826
827
    /**
828
     * 内部公共方法, 构造URL.
829
     *
830
     * @param string $bucketName
831
     * @param string $dstPath
832
     *
833
     * @return string
834
     */
835 14
    private static function generateResUrl($bucketName, $dstPath)
836
    {
837 14
        return Conf::API_COSAPI_END_POINT.Conf::getAppId().'/'.$bucketName.$dstPath;
838
    }
839
840
    /**
841
     * 内部公共方法, 发送消息.
842
     *
843
     * @param array $req
844
     *
845
     * @return array
846
     */
847 14
    private static function sendRequest($req)
848
    {
849 14
        $rsp = Http::send($req);
850
851 14
        $ret = json_decode($rsp, true);
852
853 14
        if ($ret) {
854 14
            if (0 === $ret['code']) {
855
                return $ret;
856
            } else {
857
                return [
858 14
                    'code'    => $ret['code'],
859 14
                    'message' => $ret['message'],
860 14
                    'data'    => [],
861 14
                ];
862
            }
863
        } else {
864
            return [
865
                'code'    => self::COSAPI_NETWORK_ERROR,
866
                'message' => $rsp,
867
                'data'    => [],
868
            ];
869
        }
870
    }
871
872
    /**
873
     * 设置分片大小.
874
     *
875
     * @param string $sliceSize
876
     *
877
     * @return int
878
     */
879
    private static function getSliceSize($sliceSize)
880
    {
881
        $size = self::SLICE_SIZE_1M;
882
        if (!isset($sliceSize)) {
883
            return $size;
884
        }
885
886
        if ($sliceSize <= self::SLICE_SIZE_512K) {
887
            $size = self::SLICE_SIZE_512K;
888
        } elseif ($sliceSize <= self::SLICE_SIZE_1M) {
889
            $size = self::SLICE_SIZE_1M;
890
        } elseif ($sliceSize <= self::SLICE_SIZE_2M) {
891
            $size = self::SLICE_SIZE_2M;
892
        } else {
893
            $size = self::SLICE_SIZE_3M;
894
        }
895
896
        return $size;
897
    }
898
899
    /**
900
     * 内部方法, 规整文件路径.
901
     *
902
     * @param string $path     文件路径
903
     * @param bool   $isfolder 是否为文件夹
904
     *
905
     * @return string
906
     */
907 12
    private static function normalizerPath($path, $isfolder = false)
908
    {
909 12
        if (preg_match('/^\//', $path) == 0) {
910 12
            $path = '/'.$path;
911 12
        }
912
913 12
        if ($isfolder == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
914 3
            if (preg_match('/\/$/', $path) == 0) {
915 3
                $path = $path.'/';
916 3
            }
917 3
        }
918
919 12
        return $path;
920
    }
921
922
    /**
923
     * 判断authority值是否正确.
924
     *
925
     * @param string $authority
926
     *
927
     * @return bool
928
     */
929 1
    private static function isAuthorityValid($authority)
930
    {
931
        if ($authority == 'eInvalid'
932 1
        || $authority == 'eWRPrivate'
933 1
        || $authority == 'eWPrivateRPublic') {
934 1
            return true;
935
        }
936
937
        return false;
938
    }
939
940
    /**
941
     * 判断pattern值是否正确.
942
     *
943
     *
944
     * @param string $pattern
945
     *
946
     * @return bool
947
     */
948 1
    private static function isPatternValid($pattern)
949
    {
950
        if ($pattern == 'eListBoth'
951 1
        || $pattern == 'eListDirOnly'
952 1
        || $pattern == 'eListFileOnly') {
953 1
            return true;
954
        }
955
956
        return false;
957
    }
958
959
    /**
960
     * 判断是否符合自定义属性.
961
     *
962
     * @param string $key
963
     *
964
     * @return bool
965
     */
966
    private static function isCustomer_header($key)
967
    {
968
        if ($key == 'Cache-Control'
969
        || $key == 'Content-Type'
970
        || $key == 'Content-Disposition'
971
        || $key == 'Content-Language'
972
        || substr($key, 0, strlen('x-cos-meta-')) == 'x-cos-meta-') {
973
            return true;
974
        }
975
976
        return false;
977
    }
978
979
    /**
980
     * 增加自定义属性到data中.
981
     *
982
     * @param array $data
983
     * @param array $customer_headers_array
984
     */
985
    private static function add_customer_header(&$data, &$customer_headers_array)
986
    {
987
        if (count($customer_headers_array) < 1) {
988
            return;
989
        }
990
        foreach ($customer_headers_array as $key=>$value) {
991
            if (self::isCustomer_header($key)) {
992
                $data[$key] = $value;
993
            }
994
        }
995
    }
996
}
997