| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 | <?phpnamespace Qiniu\Storage;use Qiniu\Config;use Qiniu\Http\Client;use Qiniu\Http\Error;/** * 断点续上传类, 该类主要实现了断点续上传中的分块上传, * 以及相应地创建块和创建文件过程. * * @link http://developer.qiniu.com/docs/v6/api/reference/up/mkblk.html * @link http://developer.qiniu.com/docs/v6/api/reference/up/mkfile.html */final class ResumeUploader{    private $upToken;    private $key;    private $inputStream;    private $size;    private $params;    private $mime;    private $contexts;    private $host;    private $currentUrl;    private $config;    /**     * 上传二进制流到七牛     *     * @param $upToken    上传凭证     * @param $key        上传文件名     * @param $inputStream 上传二进制流     * @param $size       上传流的大小     * @param $params     自定义变量     * @param $mime       上传数据的mimeType     *     * @link http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar     */    public function __construct(        $upToken,        $key,        $inputStream,        $size,        $params,        $mime,        $config    ) {        $this->upToken = $upToken;        $this->key = $key;        $this->inputStream = $inputStream;        $this->size = $size;        $this->params = $params;        $this->mime = $mime;        $this->contexts = array();        $this->config = $config;        list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken);        if ($err != null) {            return array(null, $err);        }        $upHost = $config->getUpHost($accessKey, $bucket);        if ($err != null) {            throw new \Exception($err->message(), 1);        }        $this->host = $upHost;    }    /**     * 上传操作     */    public function upload($fname)    {        $uploaded = 0;        while ($uploaded < $this->size) {            $blockSize = $this->blockSize($uploaded);            $data = fread($this->inputStream, $blockSize);            if ($data === false) {                throw new \Exception("file read failed", 1);            }            $crc = \Qiniu\crc32_data($data);            $response = $this->makeBlock($data, $blockSize);            $ret = null;            if ($response->ok() && $response->json() != null) {                $ret = $response->json();            }            if ($response->statusCode < 0) {                list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($this->upToken);                if ($err != null) {                    return array(null, $err);                }                $upHostBackup = $this->config->getUpBackupHost($accessKey, $bucket);                $this->host = $upHostBackup;            }            if ($response->needRetry() || !isset($ret['crc32']) || $crc != $ret['crc32']) {                $response = $this->makeBlock($data, $blockSize);                $ret = $response->json();            }            if (!$response->ok() || !isset($ret['crc32']) || $crc != $ret['crc32']) {                return array(null, new Error($this->currentUrl, $response));            }            array_push($this->contexts, $ret['ctx']);            $uploaded += $blockSize;        }        return $this->makeFile($fname);    }    /**     * 创建块     */    private function makeBlock($block, $blockSize)    {        $url = $this->host . '/mkblk/' . $blockSize;        return $this->post($url, $block);    }    private function fileUrl($fname)    {        $url = $this->host . '/mkfile/' . $this->size;        $url .= '/mimeType/' . \Qiniu\base64_urlSafeEncode($this->mime);        if ($this->key != null) {            $url .= '/key/' . \Qiniu\base64_urlSafeEncode($this->key);        }        $url .= '/fname/' . \Qiniu\base64_urlSafeEncode($fname);        if (!empty($this->params)) {            foreach ($this->params as $key => $value) {                $val = \Qiniu\base64_urlSafeEncode($value);                $url .= "/$key/$val";            }        }        return $url;    }    /**     * 创建文件     */    private function makeFile($fname)    {        $url = $this->fileUrl($fname);        $body = implode(',', $this->contexts);        $response = $this->post($url, $body);        if ($response->needRetry()) {            $response = $this->post($url, $body);        }        if (!$response->ok()) {            return array(null, new Error($this->currentUrl, $response));        }        return array($response->json(), null);    }    private function post($url, $data)    {        $this->currentUrl = $url;        $headers = array('Authorization' => 'UpToken ' . $this->upToken);        return Client::post($url, $data, $headers);    }    private function blockSize($uploaded)    {        if ($this->size < $uploaded + Config::BLOCK_SIZE) {            return $this->size - $uploaded;        }        return Config::BLOCK_SIZE;    }}
 |