Passed
Push — master ( 21a6a4...4428d0 )
by xiaohui
03:17
created

UploadClient::sendRequest()   F

Complexity

Conditions 12
Paths 450

Size

Total Lines 67
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 50
nc 450
nop 4
dl 0
loc 67
rs 3.5638
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace AliMedia\Core;
3
4
use AliMedia\Conf\Conf;
5
use AliMedia\Utils\EncodeUtils;
6
use AliMedia\Utils\UploadOption;
7
use AliMedia\Utils\UploadPolicy;
8
use AliMedia\Utils\UpOptionType;
9
use XiaohuiLam\LaravelFilesystem\Wantu\UploadException;
10
use Exception;
11
12
class UploadClient
13
{
14
    private $upload_host;
15
    private $ak;
16
    private $sk;
17
    private $type; // "CLOUD" or "TOP";
18
19
    public function __construct($ak, $sk, $type = Conf::TYPE_TOP)
20
    {
21
        $this->ak = $ak;
22
        $this->sk = $sk;
23
        $this->type = $type;
24
        $this->upload_host = Conf::UPLOAD_HOST_MEDIA;
25
    }
26
27
    /**
28
     * 上传文件。根据文件大小判断是否进行分片
29
     * @param string $filePath  文件路径
30
     * @param UploadPolicy $uploadPolicy    上传策略
31
     * @param UploadOption $uploadOption    上传选项
32
     * @return array
33
     */
34
    public function upload($filePath, UploadPolicy $uploadPolicy, UploadOption $uploadOption = null)
35
    {
36
        $encodePath = iconv('UTF-8', 'GB2312', $filePath); //中文需要转换成gb2312,file_exist等函数才能识别
37
        if (!file_exists($encodePath)) {
38
            return $this->errorResponse("FileNotExist", "file not exist");
39
        }
40
        if (empty($uploadOption)) {
41
            $uploadOption = new UploadOption();     //如果用户没有传递UploadOption,则生成一个默认的
42
        }
43
        if (empty($uploadOption->name)) {
44
            $uploadOption->name = basename($filePath);        //如果用户没有设置name属性,则使用上传时的文件名
45
        }
46
        // UploadPolicy 和 UploadOption检查
47
        list($isValid, $message) = $this->checkUploadInfo($uploadPolicy, $uploadOption);
48
        if (!$isValid) {
49
            return $this->errorResponse("ErrorUploadInfo", "error upload policy or option:" . $message);
50
        }
51
        $fileSize = filesize($encodePath);
52
        // 文件大于设定的分片大小(默认2M),则进行分片上传uploadSuperfile()
53
        if ($fileSize > ($uploadOption->blockSize)) {
54
            return $this->uploadSuperFile($encodePath, $uploadPolicy, $uploadOption);
55
        }
56
        // 文件不大于设定的分片大小(默认2M),则直接上传uploadMiniFile()
57
        return $this->uploadMiniFile($encodePath, $uploadPolicy, $uploadOption);
58
    }
59
60
    /**
61
     * 上传小文件
62
     * @param string $filePath 文件路径
63
     * @param UploadPolicy $uploadPolicy 上传策略
64
     * @param UploadOption $uploadOption 上传选项
65
     * @return array
66
     */
67
    protected function uploadMiniFile($filePath, UploadPolicy $uploadPolicy, UploadOption $uploadOption = null)
68
    {
69
        $data = file_get_contents($filePath);
70
        $uploadOption->setContent($data);
0 ignored issues
show
Bug introduced by
The method setContent() does not exist on null. ( Ignorable by Annotation )

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

70
        $uploadOption->/** @scrutinizer ignore-call */ 
71
                       setContent($data);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
71
        $url = $this->upload_host . Conf::UPLOAD_API_UPLOAD;        //普通上传的API
72
        return $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
0 ignored issues
show
Bug introduced by
It seems like $uploadOption can also be of type null; however, parameter $uploadOption of AliMedia\Core\UploadClient::sendRequest() does only seem to accept AliMedia\Utils\UploadOption, 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

72
        return $this->sendRequest('POST', $url, $uploadPolicy, /** @scrutinizer ignore-type */ $uploadOption);
Loading history...
73
    }
74
75
    /**
76
     * 分片上传大文件
77
     * @param string $filePath 文件路径
78
     * @param UploadPolicy $uploadPolicy 上传策略
79
     * @param UploadOption $uploadOption 上传选项
80
     * @return array
81
     */
82
    protected function uploadSuperFile($filePath, UploadPolicy $uploadPolicy, UploadOption $uploadOption = null)
83
    {
84
        $fileSize = filesize($filePath);        // 文件大小
85
        $blockSize = $uploadOption->blockSize;  // 文件分片大小
86
        $blockNum = intval(ceil($fileSize / $blockSize)); // 文件分片后的块数
87
        for ($i = 0; $i < $blockNum; $i++) {
88
            $currentSize = $blockSize; // 当前文件块的大小
89
            if (($i + 1) === $blockNum) {
90
                $currentSize = ($fileSize - ($blockNum - 1) * $blockSize); // 计算最后一个块的大小
91
            }
92
            $offset = $i * $blockSize; // 当前文件块相对于文件开头的偏移量(块的起始位置)
93
            $blockData = file_get_contents($filePath, 0, null, $offset, $currentSize); //当前文件块的数据
94
            $uploadOption->setContent($blockData); // 设置待上传的文件块
95
            $httpRes = null;
96
            if (0 == $i) {
97
                // 分片初始化阶段
98
                $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_INIT;        //初始化分片上传的API
99
                $uploadOption->optionType = UpOptionType::BLOCK_INIT_UPLOAD;    //初始化分片时的Option类型
100
                $httpRes = $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
0 ignored issues
show
Bug introduced by
It seems like $uploadOption can also be of type null; however, parameter $uploadOption of AliMedia\Core\UploadClient::sendRequest() does only seem to accept AliMedia\Utils\UploadOption, 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

100
                $httpRes = $this->sendRequest('POST', $url, $uploadPolicy, /** @scrutinizer ignore-type */ $uploadOption);
Loading history...
101
                $uploadId = isset($httpRes['uploadId']) ? $httpRes['uploadId'] : null; // 分片上传ID(OSS用于区分上传的id)
102
                $id = isset($httpRes['id']) ? $httpRes['id'] : null; // 上传唯一ID(多媒体服务用于区分上传的id)
103
                $uploadOption->setUploadId($uploadId);
104
                $uploadOption->setUniqueIdId($id);
105
            } else {
106
                // 分片上传过程中
107
                $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_UPLOAD;      //分片上传过程中的API
108
                $uploadOption->optionType = UpOptionType::BLOCK_RUN_UPLOAD;     //分片上传过程中的Option类型
109
                $uploadOption->setPartNumber($i + 1);                           //
110
                $httpRes = $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
111
            }
112
            // 如果分片上传失败,则取消cancel分片上传任务,然后返回错误信息
113
            if (!$httpRes['isSuccess']) {
114
                if ($uploadOption->checkMutipartParas()) {
115
                    $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_CANCEL;      //取消分片任务的API
116
                    $uploadOption->optionType = UpOptionType::BLOCK_CANCEL_UPLOAD;  //取消分片任务时的Option类型
117
                    $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption); // 不判断取消分片任务返回的结果
118
                }
119
                return $httpRes;
120
                //              $message = isset( $httpRes ['message'] ) ? $httpRes ['message'] : null;
121
                //              $code = isset( $httpRes ['code'] ) ? $httpRes ['code'] : null;
122
                //              $requestId = isset( $httpRes ['requestId'] ) ? $httpRes ['requestId'] : null;
123
                //              return $this->errorResponse ( $code, "fail upload block file:" . $message, $requestId );
124
            }
125
            // 保存 块编号partNumber 和 标记ETag,用于分片完成时的参数设置
126
            $uploadOption->addPartNumberAndETag($httpRes['partNumber'], $httpRes['eTag']);
127
        }
128
        // 分片上传完成
129
        $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_COMPLETE;            //完成分片上传任务的API
130
        $uploadOption->optionType = UpOptionType::BLOCK_COMPLETE_UPLOAD;        //完成分片上传任务时的Option类型
131
        $uploadOption->setMd5(md5_file($filePath));                         //文件Md5
132
        return $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
133
    }
134
135
    /**上传字符串/二进制数据
136
     * @param string $data
137
     *          文件数据
138
     * @param UploadPolicy $uploadPolicy
139
     *          上传策略
140
     * @param UploadOption $uploadOption
141
     *          上传选项
142
     * @return array
143
     */
144
    public function uploadData($data, UploadPolicy $uploadPolicy, UploadOption $uploadOption = null)
145
    {
146
        if (empty($uploadOption)) {
147
            $uploadOption = new UploadOption();     //如果用户没有传递UploadOption,则生成一个默认的
148
        }
149
        // UploadPolicy 和 UploadOption检查
150
        list($isValid, $message) = $this->checkUploadInfo($uploadPolicy, $uploadOption);
151
        if (!$isValid) {
152
            return $this->errorResponse("ErrorUploadInfo", "error upload policy or option:" . $message);
153
        }
154
        $dataSize = strlen($data);
155
        // 文件大于设定的分片大小(默认2M),则进行分片上传uploadSuperfile()
156
        if ($dataSize > ($uploadOption->blockSize)) {
157
            return $this->uploadSuperData($data, $uploadPolicy, $uploadOption);
158
        }
159
        // 文件不大于设定的分片大小(默认2M),则直接上传uploadMiniFile()
160
        $uploadOption->setContent($data);
161
        $url = $this->upload_host . Conf::UPLOAD_API_UPLOAD;        //普通上传的API
162
        return $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
163
    }
164
165
    /**
166
     * 分片上传大文件数据
167
     * @param string $data 文件数据
168
     * @param UploadPolicy $uploadPolicy 上传策略
169
     * @param UploadOption $uploadOption 上传选项
170
     * @return array
171
     */
172
    protected function uploadSuperData($data, UploadPolicy $uploadPolicy, UploadOption $uploadOption = null)
173
    {
174
        $dataSize = strlen($data);          // 文件大小
175
        $blockSize = $uploadOption->blockSize;  // 文件分片大小
176
        $blockNum = intval(ceil($dataSize / $blockSize)); // 文件分片后的块数
177
        for ($i = 0; $i < $blockNum; $i++) {
178
            $currentSize = $blockSize; // 当前文件块的大小
179
            if (($i + 1) === $blockNum) {
180
                $currentSize = ($dataSize - ($blockNum - 1) * $blockSize); // 计算最后一个块的大小
181
            }
182
            $offset = $i * $blockSize; // 当前文件块相对于文件开头的偏移量(块的起始位置)
183
            $blockData = substr($data, $offset, $currentSize); //当前文件块的数据
184
            $uploadOption->setContent($blockData); // 设置待上传的文件块
185
            $httpRes = null;
186
            if (0 == $i) {
187
                // 分片初始化阶段
188
                $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_INIT;        //初始化分片上传的API
189
                $uploadOption->optionType = UpOptionType::BLOCK_INIT_UPLOAD;    //初始化分片时的Option类型
190
                $httpRes = $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
0 ignored issues
show
Bug introduced by
It seems like $uploadOption can also be of type null; however, parameter $uploadOption of AliMedia\Core\UploadClient::sendRequest() does only seem to accept AliMedia\Utils\UploadOption, 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

190
                $httpRes = $this->sendRequest('POST', $url, $uploadPolicy, /** @scrutinizer ignore-type */ $uploadOption);
Loading history...
191
                $uploadId = isset($httpRes['uploadId']) ? $httpRes['uploadId'] : null; // 分片上传ID(OSS用于区分上传的id)
192
                $id = isset($httpRes['id']) ? $httpRes['id'] : null; // 上传唯一ID(多媒体服务用于区分上传的id)
193
                $uploadOption->setUploadId($uploadId);
194
                $uploadOption->setUniqueIdId($id);
195
            } else {
196
                // 分片上传过程中
197
                $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_UPLOAD;      //分片上传过程中的API
198
                $uploadOption->optionType = UpOptionType::BLOCK_RUN_UPLOAD;     //分片上传过程中的Option类型
199
                $uploadOption->setPartNumber($i + 1);                           //
200
                $httpRes = $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
201
            }
202
            // 如果分片上传失败,则取消cancel分片上传任务,然后返回错误信息
203
            if (!$httpRes['isSuccess']) {
204
                if ($uploadOption->checkMutipartParas()) {
205
                    $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_CANCEL;      //取消分片任务的API
206
                    $uploadOption->optionType = UpOptionType::BLOCK_CANCEL_UPLOAD;  //取消分片任务时的Option类型
207
                    $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption); // 不判断取消分片任务返回的结果
208
                }
209
                return $httpRes;
210
            }
211
            // 保存 块编号partNumber 和 标记ETag,用于分片完成时的参数设置
212
            $uploadOption->addPartNumberAndETag($httpRes['partNumber'], $httpRes['eTag']);
213
        }
214
        // 分片上传完成
215
        $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_COMPLETE;            //完成分片上传任务的API
216
        $uploadOption->optionType = UpOptionType::BLOCK_COMPLETE_UPLOAD;        //完成分片上传任务时的Option类型
217
        $uploadOption->setMd5(md5($data));                          //文件Md5
218
        return $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
219
    }
220
221
    /**
222
     * 创建分片上传任务,指定待上传的文件。即初始化分片上传
223
     * @param string $filePath 文件路径
224
     * @param UploadPolicy $uploadPolicy 上传策略
225
     * @param UploadOption $uploadOption 上传选项
226
     * @return array 初始化分片上传的结果
227
     */
228
    public function multipartInit($filePath, UploadPolicy $uploadPolicy, UploadOption $uploadOption)
229
    {
230
        $encodePath = iconv('UTF-8', 'GB2312', $filePath); //中文需要转换成gb2312,file_exist等函数才能识别
231
        if (!file_exists($encodePath)) {
232
            return $this->errorResponse("FileNotExist", "file not exist");
233
        }
234
        if (empty($uploadOption)) {
235
            $uploadOption = new UploadOption();     //如果用户没有传递UploadOption,则生成一个默认的
236
        }
237
        if (empty($uploadOption->name)) {
238
            $uploadOption->name = basename($filePath);        //如果用户没有设置name属性,则使用上传时的文件名
239
        }
240
        $blockData = file_get_contents($encodePath, 0, null, 0, $uploadOption->blockSize);
241
        return $this->multipartInitByData($blockData, $uploadPolicy, $uploadOption);
242
    }
243
244
    /**
245
     * 创建分片上传任务,指定初始化分片任务的数据,即第一块数据
246
     * @param string $blockData 文件数据
247
     * @param UploadPolicy $uploadPolicy 上传策略
248
     * @param UploadOption $uploadOption 上传选项
249
     * @return array 初始化分片上传的结果
250
     */
251
    public function multipartInitByData($blockData, UploadPolicy $uploadPolicy, UploadOption $uploadOption)
252
    {
253
        if (empty($uploadOption)) {
254
            $uploadOption = new UploadOption();     //如果用户没有传递UploadOption,则生成一个默认的
255
        }
256
        // UploadPolicy 和 UploadOption检查
257
        list($isValid, $message) = $this->checkUploadInfo($uploadPolicy, $uploadOption);
258
        if (!$isValid) {
259
            return $this->errorResponse("ErrorUploadInfo", "error upload policy or option:" . $message);
260
        }
261
        // 数据大小不等于设定的分片大小(默认2M),则无法完成初始化
262
        $dataSize = strlen($blockData);         // 数据文件大小
263
        if ($dataSize != ($uploadOption->blockSize)) {
264
            return $this->errorResponse("MultipartInitError", "UploadOption's blockSize is not equal to data's size");
265
        }
266
        $uploadOption->setContent($blockData); // 设置待上传的文件块
267
        $uploadOption->optionType = UpOptionType::BLOCK_INIT_UPLOAD;    //初始化分片时的Option类型
268
        $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_INIT;        //初始化分片上传的API
269
        $httpRes = $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
270
        //若成功返回,则保存初始化成功的uploadId、id 以及 partNumber、eTag
271
        $uploadId = isset($httpRes['uploadId']) ? $httpRes['uploadId'] : null; // 分片上传ID(OSS用于区分上传的id)
272
        $id = isset($httpRes['id']) ? $httpRes['id'] : null; // 上传唯一ID(多媒体服务用于区分上传的id)
273
        $uploadOption->setUploadId($uploadId);
274
        $uploadOption->setUniqueIdId($id);
275
        if (isset($httpRes['partNumber']) && isset($httpRes['eTag'])) {
276
            $uploadOption->addPartNumberAndETag($httpRes['partNumber'], $httpRes['eTag']);
277
        }
278
        return $httpRes;
279
    }
280
281
    /**分片上传,指定待上传的文件。需要指定UploadOption中文件块编号
282
     * @param string $filePath 文件路径
283
     * @param UploadPolicy $uploadPolicy 上传策略
284
     * @param UploadOption $uploadOption 上传选项
285
     * @return array 初始化分片上传的结果
286
     */
287
    public function multipartUpload($filePath, UploadPolicy $uploadPolicy, UploadOption $uploadOption)
288
    {
289
        $encodePath = iconv('UTF-8', 'GB2312', $filePath); //中文需要转换成gb2312,file_exist等函数才能识别
290
        if (!file_exists($encodePath)) {
291
            return $this->errorResponse("FileNotExist", "file not exist");
292
        }
293
        $fileSize = filesize($encodePath);      // 文件大小
294
        $blockSize = $uploadOption->blockSize;  // 文件分片大小
295
        $blockNum = intval(ceil($fileSize / $blockSize)); // 文件分片后的块数
296
        $currentSize = $blockSize; // 当前文件块的大小
297
        if ($uploadOption->getPartNumber() == $blockNum) {
298
            $currentSize = ($fileSize - ($blockNum - 1) * $blockSize); // 计算最后一个块的大小
299
        }
300
        $offset = ($uploadOption->getPartNumber() - 1) * $blockSize; // 当前文件块相对于文件开头的偏移量(块的起始位置)
301
        $blockData = file_get_contents($encodePath, 0, null, $offset, $currentSize);
302
        return $this->multipartUploadByData($blockData, $uploadPolicy, $uploadOption);
303
    }
304
305
    /**
306
     * 分片上传,指定待上传的数据。需要指定UploadOption中文件块编号
307
     * @param string $filePath 文件路径
308
     * @param UploadPolicy $uploadPolicy 上传策略
309
     * @param UploadOption $uploadOption 上传选项
310
     * @return array 分片上传的结果
311
     */
312
    public function multipartUploadByData($blockData, UploadPolicy $uploadPolicy, UploadOption $uploadOption)
313
    {
314
        $partNumber = $uploadOption->getPartNumber(); //php 5.3的版本使用empty()传递函数返回值会报错。所以为了兼容,增加临时变量
315
        // 检查分片上传所需的参数是否设置正确
316
        if (!$uploadOption->checkMutipartParas() || empty($partNumber)) {
317
            return $this->errorResponse("MultipartUploadError", "multipart upload's parameters(id,uploadId,partNumber) error");
318
        }
319
        $uploadOption->setContent($blockData); // 设置待上传的文件块
320
        $uploadOption->optionType = UpOptionType::BLOCK_RUN_UPLOAD;     //分片上传过程中的Option类型
321
        $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_UPLOAD;      //分片上传过程中的API
322
        $httpRes = $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
323
        if (isset($httpRes['partNumber']) && isset($httpRes['eTag'])) {
324
            $uploadOption->addPartNumberAndETag($httpRes['partNumber'], $httpRes['eTag']);
325
        }
326
        return $httpRes;
327
    }
328
329
    /**
330
     * 完成分片上传任务。需要指定UploadOption中整个文件的md5值
331
     * @param UploadPolicy $uploadPolicy 上传策略
332
     * @param UploadOption $uploadOption 上传选项
333
     * @return array 分片上传完成的结果
334
     */
335
    public function multipartComplete(UploadPolicy $uploadPolicy, UploadOption $uploadOption)
336
    {
337
 // 检查分片上传所需的参数是否设置正确
338
        $fileMd5 = $uploadOption->getMd5(); //php 5.3的版本使用empty()传递函数返回值会报错。所以为了兼容,增加临时变量
339
        if (!$uploadOption->checkMutipartParas() || empty($fileMd5)) {
340
            return $this->errorResponse("MultipartCompleteError", "multipart upload's parameters(id,uploadId,md5) error");
341
        }
342
        $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_COMPLETE;            //完成分片上传任务的API
343
        $uploadOption->optionType = UpOptionType::BLOCK_COMPLETE_UPLOAD;        //完成分片上传任务时的Option类型
344
        return $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
345
    }
346
347
    /**
348
     * 取消分片上传任务。需要保证UploadOption中有分片任务的uploadId和id
349
     * @param UploadPolicy $uploadPolicy 上传策略
350
     * @param UploadOption $uploadOption 上传选项
351
     * @return array 分片上传完成的结果
352
     */
353
    public function multipartCancel(UploadPolicy $uploadPolicy, UploadOption $uploadOption)
354
    {
355
        if (!$uploadOption->checkMutipartParas()) {
356
            return $this->errorResponse("MultipartCancelError", "multipart upload's parameters(id,uploadId) error");
357
        }
358
        $url = $this->upload_host . Conf::UPLOAD_API_BLOCK_CANCEL;      //取消分片任务的API
359
        $uploadOption->optionType = UpOptionType::BLOCK_CANCEL_UPLOAD;  //取消分片任务时的Option类型
360
        return $this->sendRequest('POST', $url, $uploadPolicy, $uploadOption);
361
    }
362
363
    /**
364
     * 调用curl利用http上传数据
365
     * @param string $method
366
     * @param string $url
367
     * @param UploadPolicy $uploadPolicy
368
     * @param UploadOption $uploadOption
369
     * @return array (isSuccess, ...)
370
     */
371
    protected function sendRequest($method, $url, UploadPolicy $uploadPolicy, UploadOption $uploadOption)
372
    {
373
        $success = false;
374
        $http_code = 0;
375
        $result = array();
376
        /**
377
         * @var resource $ch
378
         */
379
        $ch = curl_init();
380
        try {
381
            //构建Http请求头和请求体
382
            $_headers = array('Expect:');
383
            $token = $this->_getUploadToken($uploadPolicy);
0 ignored issues
show
Bug introduced by
The method _getUploadToken() does not exist on AliMedia\Core\UploadClient. Did you maybe mean getUploadToken()? ( Ignorable by Annotation )

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

383
            /** @scrutinizer ignore-call */ 
384
            $token = $this->_getUploadToken($uploadPolicy);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
384
            array_push($_headers, "Authorization: {$token}");
385
            array_push($_headers, "User-Agent: {$this->getUserAgent()}");
386
            $length = 0;
387
            if (!empty($uploadOption)) {
388
                list($contentType, $httpBody) = $this->buildMultipartForm($uploadOption);
389
                $length = @strlen($httpBody);
390
                array_push($_headers, "Content-Type: {$contentType}");
391
                curl_setopt($ch, CURLOPT_POSTFIELDS, $httpBody);            //请求体
392
            }
393
            array_push($_headers, "Content-Length: {$length}");
394
            curl_setopt($ch, CURLOPT_HEADER, 1);                            //设置头部
395
            curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);                //请求头
396
            curl_setopt($ch, CURLOPT_TIMEOUT, $uploadOption->timeout);  //持续时长
397
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);               //连接超时时长
398
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //成功,只返回结果,不自动输出任何内容。如果失败返回FALSE
399
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
400
            curl_setopt($ch, CURLOPT_URL, $url);
401
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);           //自定义请求
402
            //设置请求方式(GET或POST等)
403
            if ($method == 'PUT' || $method == 'POST') {
404
                curl_setopt($ch, CURLOPT_POST, 1);
405
            } else {
406
                curl_setopt($ch, CURLOPT_POST, 0);
407
            }
408
            //执行上传,然后获取服务端返回,决定是否重试
409
            $response = curl_exec($ch);
410
            if ($response === false && $uploadOption->httpReTry != 0) {
411
                //如果执行curl失败,且需要重试,则进行重试
412
                $this->recordCurlErrorLog($ch); //记录最近一次curl执行错误日志
413
                $response = curl_exec($ch);
414
            }
415
            if ($response === false) {
416
                $this->recordCurlErrorLog($ch); //记录最近一次curl执行错误日志
417
                $result = $this->errorResponse("curl error", "curl request failed");
418
                $result['errno'] = curl_errno($ch); //错误码
419
            } else {
420
                //解析返回结果,并判断是否上传成功
421
                $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
422
                $success = ($http_code == 200) ? true : false;                  //判断是否上传成功
423
                $resStr = explode("\r\n\r\n", $response, 2);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type true; however, parameter $string of explode() 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

423
                $resStr = explode("\r\n\r\n", /** @scrutinizer ignore-type */ $response, 2);
Loading history...
424
                $resBody = isset($resStr[1]) ? $resStr[1] : '';
425
                $resArray = json_decode($resBody, true);                        //解析得到结果
426
                $result = (empty($resArray) ? $result : $resArray);
427
            }
428
        } catch (Exception $e) {
429
            $result = $this->errorResponse("HTTPRequestException#" . $e->getLine(), $e->getMessage());
430
        }
431
432
        curl_close($ch); //PHP5.3中不支持finally关键字。因此,为了兼容,这里取消finally
433
        if (!$success) {
434
            throw new UploadException($result['message'], $http_code);
435
        }
436
        $result['isSuccess'] = $success;
437
        return $result;
438
    }
439
440
    /**
441
     * uploadPolicy和uploadOption 合法性检查
442
     * @param UploadPolicy $uploadPolicy 上传策略
443
     * @param UploadOption $uploadOption 上传选项
444
     * @return array($isValid, $message)
445
     */
446
    protected function checkUploadInfo(UploadPolicy $uploadPolicy, UploadOption $uploadOption)
447
    {
448
        $isValid = true;
449
        $message = null;
450
        // 1:判断是否设置空间名
451
        if (empty($uploadPolicy->bucket) && empty($uploadPolicy->namespace)) {
452
            $isValid = false;
453
            $message = 'namespace or bucket is empty';
454
        } elseif (empty($uploadPolicy->name)) {
455
            // 2:优先使用uploadPolicy中的name,如果为空,则使用uploadOption中的name
456
            if (empty($uploadOption->name)) {
457
                $isValid = false;
458
                $message = "file's name is empty"; // 如果uploadPolicy和uploadOption中的文件名name都为空,则返回错误信息
459
            }
460
        }
461
        if (true === $isValid) {
462
            // 3:优先使用uploadPolicy中的dir
463
            if (!empty($uploadPolicy->dir)) {
464
                if (strpos($uploadPolicy->dir, '/') !== 0) {
465
                    $uploadPolicy->dir = '/' . $uploadPolicy->dir; //如果dir不为空,且其前面没有以"/"开头,则为其添加
466
                }
467
            }
468
            // 4:如果uploadPolicy中的dir为空,则使用uploadOption中的dir
469
            if (!empty($uploadOption->dir)) {
470
                if (strpos($uploadOption->dir, '/') !== 0) {
471
                    $uploadOption->dir = '/' . $uploadOption->dir; //如果dir不为空,且其前面没有以"/"开头,则为其添加
472
                }
473
            }
474
            // 5:判断用户设置的文件分块大小,是否在指定的范围内。如果不在,则设置为默认Conf::BLOCK_DEFF_SIZE = 2M
475
            if (($uploadOption->blockSize > Conf::BLOCK_MAX_SIZE) || ($uploadOption->blockSize < Conf::BLOCK_MIN_SIZE)) {
476
                $uploadOption->blockSize = Conf::BLOCK_DEFF_SIZE;
477
            }
478
        }
479
        return array($isValid, $message);
480
    }
481
482
    /**
483
     * 构建Http请求的Body
484
     * @param UploadOption $uploadOption
485
     * @return array (contentType,httpBody)
486
     */
487
    protected function buildMultipartForm(UploadOption $uploadOption)
488
    {
489
        $bodyArray = array();
490
        $mimeBoundary = md5(microtime());
491
        $paraArray = $uploadOption->getParaArray();
492
        foreach ($paraArray as $name => $val) {
493
            if ($name != 'content') {
494
                array_push($bodyArray, '--' . $mimeBoundary);
495
                array_push($bodyArray, "Content-Disposition: form-data; name=\"$name\"");
496
                array_push($bodyArray, 'Content-Type: text/plain; charset=UTF-8');
497
                array_push($bodyArray, '');
498
                array_push($bodyArray, $val);
499
            }
500
        }
501
        if (isset($paraArray['content'])) {
502
            array_push($bodyArray, '--' . $mimeBoundary);
503
            $fileName = empty($uploadOption->name) ? "temp" : $uploadOption->name;
504
            array_push($bodyArray, "Content-Disposition: form-data; name=\"content\"; filename=\"{$fileName}\"");
505
            array_push($bodyArray, "Content-Type: application/octet-stream");
506
            array_push($bodyArray, '');
507
            array_push($bodyArray, $paraArray['content']);
508
        }
509
510
        array_push($bodyArray, '--' . $mimeBoundary . '--');
511
        array_push($bodyArray, '');
512
513
        $httpBody = implode("\r\n", $bodyArray);
514
        $contentType = 'multipart/form-data; boundary=' . $mimeBoundary;
515
        return array(
516
            $contentType,
517
            $httpBody
518
        );
519
    }
520
521
    /**
522
     * UserAgent用户代理
523
     */
524
    protected function getUserAgent()
525
    {
526
        if ($this->type == "TOP") {
527
            return "ALIMEDIASDK_PHP_TAE/" . Conf::SDK_VERSION;
528
        } else {
529
            return "ALIMEDIASDK_PHP_CLOUD/" . Conf::SDK_VERSION;
530
        }
531
    }
532
533
    /**
534
     * 生成上传凭证
535
     * @param UploadPolicy $uploadPolicy
536
     * @return string 上传时的凭证token
537
     */
538
    public function getUploadToken(UploadPolicy $uploadPolicy)
539
    {
540
        $encodedPolicy = EncodeUtils::encodeWithURLSafeBase64(json_encode($uploadPolicy->toArray()));
541
        $signed = hash_hmac('sha1', $encodedPolicy, $this->sk);
542
        $tempStr = $this->ak . ":" . $encodedPolicy . ":" . $signed;
543
        $token = "UPLOAD_AK_" . $this->type . " " . EncodeUtils::encodeWithURLSafeBase64($tempStr);
544
545
        return $token;
546
    }
547
548
    /**
549
     * 反馈错误信息
550
     */
551
    protected function errorResponse($code = "UnknownError", $message = "unkonown error", $requestId = null)
552
    {
553
        return array(
554
            "isSuccess" => false,
555
            "code" => $code,
556
            "message" => $message,
557
            "requestId" => $requestId
558
        );
559
    }
560
561
    /**
562
     * 记录curl错误日志
563
     * @param curl-handle $ch curl句柄
0 ignored issues
show
Documentation Bug introduced by
The doc comment curl-handle at position 0 could not be parsed: Unknown type name 'curl-handle' at position 0 in curl-handle.
Loading history...
564
     */
565
    protected function recordCurlErrorLog($ch)
566
    {
567
        if (AlibabaImage::$run_level == Conf::RUN_LEVEL_DEBUG) {
0 ignored issues
show
Bug introduced by
The type AliMedia\Core\AlibabaImage was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
568
            $errno = curl_errno($ch); //错误码
569
            $info  = curl_getinfo($ch); //curl连接资源句柄的信息
570
            $info['errno'] = $errno; //添加到连接句柄信息中
571
            $content = date("Y-m-d H:i:s") . json_encode($info) . "\n";
572
            $logPath = dirname(__FILE__) . "/" . Conf::CURL_ERR_LOG;
573
            $this->putContentToFile($content, $logPath);
574
        }
575
    }
576
577
    /**
578
     * 将信息追加写到文件
579
     * @param string $message 日志内容。
580
     * @return void
581
     */
582
    protected function putContentToFile($content, $filepath)
583
    {
584
        if (!file_exists($filepath)) {
585
            $handle = fopen($filepath, 'w');
586
            fclose($handle);
0 ignored issues
show
Bug introduced by
It seems like $handle can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, 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

586
            fclose(/** @scrutinizer ignore-type */ $handle);
Loading history...
587
        }
588
        file_put_contents($filepath, $content, FILE_APPEND);
589
    }
590
}
591