How to use alicloud oss to upload large files in pieces

Posted by ariliquin on Tue, 09 Jun 2020 05:43:46 +0200

How to use alicloud oss to upload large files in pieces

It's very easy to upload large files, but there are various problems in doing it. I just made one. Now record the process

demand

The company's new project needs to do a large file upload function, which saves some engineering project models and other things online. The G-files can't be saved on its own server at any time. Use Alibaba cloud's oss service. During this period, I experienced the following methods
Method 1: upload the file from the client to the server. The server then uploads to oss in pieces, which has been implemented,
Disadvantages:
1: The file occupies the server bandwidth during the upload process.
2: Large files uploaded by users may not be deleted in time. They become garbage files on the server and occupy the system disk. You need to write another scheduled task script to clear.
Advantage: sensitive data is not exposed.

Method 2: upload directly on the web, which has been realized.
Disadvantages: temporary key and secret will be exposed to the client, with certain risks.
Advantages: it does not occupy server resources and directly interacts with oss.

Method 1: save and upload at the back end

Using webuploader plug-in to upload fragments to oss
Plug in content first

<script src="/public/others/jquery.js"></script>
<script src="/public/webuploader/webuploader.js"></script>
<link rel ="slylesheet" type="text/css" href="/public/webuploader/webuploader.css">

html code part

<div class="demo">
    <div id="uploadfile">
        <!--Used to store file information-->
        <div id="the_2655" class="uploader-list"></div>
        <div class="form-group form-inline">
            <div id="pick_2655" style="float:left">Select file</div>  
            <button id="Btn_2655" class="btn btn-default" style="padding: 5px 10px;border-radius: 3px;">Start upload</button>
        </div>
    </div>
</div>

js part

//Upload file function
//ids unique ID
//folder file save directory
function uploadfiles(ids,folder) {
    $(function(){
        var $list = $("#the_"+ids);
            $btn = $("#Btn_"+ids);
        var uploader = WebUploader.create({
          resize: false, // Uncompressed image
          swf: '__PUBLIC__/ueditor/third-party/webuploader/uploader.swf', // swf file path
          server: '{:url("admin/upload/uploadFile")}', // File receiving server.
          pick: "#pick_"+ids, // Button to select a file. Optional
          chunked: true, //Do you want to slice large file uploads
          chunkSize:5*1024*1024, //Slice upload, 2M for each slice, 5M by default
          //fileSizeLimit: 6*1024* 1024 * 1024, / / the total size limit of all files is 6G
          fileSingleSizeLimit: 10*1024* 1024 * 1024,    // Single file size limit 5 G
          formData: {
                folder:folder  //Custom parameters
          }
          //auto: false / / select whether to upload the file automatically
         // Chunkretry: 2, / / if an error occurs in a partition due to network problems, the number of automatic retransmissions is allowed
          //runtimeOrder: 'html5,flash',
          // accept: {
          //   title: 'Images',
          //   extensions: 'gif,jpg,jpeg,bmp,png',
          //   mimeTypes: 'image/*'
          // }
        });
        // When a file is added to the queue
        uploader.on( 'fileQueued', function( file ) {
            $list.append( '<div id="' + file.id + '" class="item">' +
                '<h4 class="info">' + file.name + '</h4>' +
                '<p class="state">Waiting to upload...</p>' +
            '</div>' );
        });
        // Create progress bar to display in real time during file upload.
        uploader.on( 'uploadProgress', function( file, percentage ) {
            var $li = $( '#'+file.id ),
                $percent = $li.find('.progress .progress-bar');
 
            // Avoid duplicate creation
            if ( !$percent.length ) {
                $percent = $('<div class="progress progress-striped active">' +
                  '<div class="progress-bar" role="progressbar" style="width: 0%">' +
                  '</div>' +
                '</div>').appendTo( $li ).find('.progress-bar');
            }
 
            $li.find('p.state').text('Uploading');
 
            $percent.css( 'width', percentage * 100 + '%' );
        });
        // File uploaded successfully
        uploader.on( 'uploadSuccess', function( file,response) {
            $( '#'+file.id ).find('p.state').text('Uploaded');
            $list.append('<input type="hidden" name="'+ids+'" value="'+response.filePath+'" />');
            //alert(response.filePath);
        });
 
        // File upload failed, display upload error
        uploader.on( 'uploadError', function( file ) {
            $( '#'+file.id ).find('p.state').text('Upload error');
        });
        // Finish uploading
        uploader.on( 'uploadComplete', function( file ) {
            $( '#'+file.id ).find('.progress').fadeOut();
        });
 
        $btn.on('click', function () {
            if ($(this).hasClass('disabled')) {
                return false;
            }
            uploader.upload();
            // if (state === 'ready') {
            //     uploader.upload();
            // } else if (state === 'paused') {
            //     uploader.upload();
            // } else if (state === 'uploading') {
            //     uploader.stop();
            // }
        });
    });
}

Note that the file size of each slice in the demo is 5M, and the maximum limit parameter in the ini file of PHP is greater than 5M, so the upload can be successful. If you want to modify it, go to Baidu.

php part

/**
     * Upload file function, if upload fails to print$_ FILES array, view error message
     * Value: 0; no error occurred, file upload succeeded.
     * Value: 1; the uploaded file exceeds php.ini  Medium upload_ max_ The value limited by the filesize option.
     * Value: 2; the size of the uploaded file exceeds the max in the HTML form_ FILE_ The value specified by the size option.
     * Value: 3; only part of the file is uploaded.
     * Value: 4; no files uploaded.
     * date:2018.4.18    from:zhix.net
     */
    public function uploadFile(){
        header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
        header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
        header("Content-type: text/html; charset=gbk32");
        header("Cache-Control: no-store, no-cache, must-revalidate");
        header("Cache-Control: post-check=0, pre-check=0", false);
        header("Pragma: no-cache");
        $folder = input('folder');
        if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
            exit; // finish preflight CORS requests here
        }
        if ( !empty($_REQUEST[ 'debug' ]) ) {
            $random = rand(0, intval($_REQUEST[ 'debug' ]) );
            if ( $random === 0 ) {
                header("HTTP/1.0 500 Internal Server Error");
                exit;
            }
        }
        // header("HTTP/1.0 500 Internal Server Error");
        // exit;
        // 5 minutes execution time
        set_time_limit(5 * 60);
        // Uncomment this one to fake upload time
         usleep(5000);
        // Settings
        $targetDir = './Public'.DIRECTORY_SEPARATOR.'file_material_tmp';            //Store temporary directory of slices
        if($folder){
            $uploadDir = './Public'.DIRECTORY_SEPARATOR.'file_material'.DIRECTORY_SEPARATOR.$folder.DIRECTORY_SEPARATOR.date('Ymd');
        }else{
            $uploadDir = './Public'.DIRECTORY_SEPARATOR.'file_material'.DIRECTORY_SEPARATOR.date('Ymd');    //Partition and merge storage directory
        }
 
        $cleanupTargetDir = true; // Remove old files
        $maxFileAge = 5 * 3600; // Temp file age in seconds
 
        // Create target dir
        if (!file_exists($targetDir)) {
            mkdir($targetDir,0777,true);
        }
        // Create target dir
        if (!file_exists($uploadDir)) {
            mkdir($uploadDir,0777,true);
        }
        // Get a file name
        if (isset($_REQUEST["name"])) {
            $fileName = $_REQUEST["name"];
        } elseif (!empty($_FILES)) {
            $fileName = $_FILES["file"]["name"];
        } else {
            $fileName = uniqid("file_");
        }
        $oldName = $fileName;
 
        $fileName = iconv('UTF-8','gb2312',$fileName);
        $filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
        // $uploadPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;
        // Chunking might be enabled
        $chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
        $chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 1;
        // Remove old temp files
        if ($cleanupTargetDir) {
            if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory111."}, "id" : "id"}');
            }
            while (($file = readdir($dir)) !== false) {
                $tmpfilePath = $targetDir . DIRECTORY_SEPARATOR . $file;
                // If temp file is current file proceed to the next
                if ($tmpfilePath == "{$filePath}_{$chunk}.part" || $tmpfilePath == "{$filePath}_{$chunk}.parttmp") {
                    continue;
                }
                // Remove temp file if it is older than the max age and is not the current file
                if (preg_match('/\.(part|parttmp)$/', $file) && (filemtime($tmpfilePath) < time() - $maxFileAge)) {
                    unlink($tmpfilePath);
                }
            }
            closedir($dir);
        }
        // Open temp file
        if (!$out = fopen("{$filePath}_{$chunk}.parttmp", "wb")) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream222."}, "id" : "id"}');
        }
        if (!empty($_FILES)) {
            if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file333."}, "id" : "id"}');
            }
            // Read binary input stream and append it to temp file
            if (!$in = fopen($_FILES["file"]["tmp_name"], "rb")) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream444."}, "id" : "id"}');
            }
        } else {
            if (!$in = fopen("php://input", "rb")) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream555."}, "id" : "id"}');
            }
        }
        while ($buff = fread($in, 4096)) {
            fwrite($out, $buff);
        }
        fclose($out);
        fclose($in);
        rename("{$filePath}_{$chunk}.parttmp", "{$filePath}_{$chunk}.part");
        $index = 0;
        $done = true;
        for( $index = 0; $index < $chunks; $index++ ) {
            if ( !file_exists("{$filePath}_{$index}.part") ) {
                $done = false;
                break;
            }
        }
 
        if ($done) {
            $pathInfo = pathinfo($fileName);
            $hashStr = substr(md5($pathInfo['basename']),8,16);
            $hashName = time() . $hashStr . '.' .$pathInfo['extension'];
            $uploadPath = $uploadDir . DIRECTORY_SEPARATOR .$hashName;
            if (!$out = fopen($uploadPath, "wb")) {
                die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream666."}, "id" : "id"}');
            }
            //flock($hander,LOCK_EX) document lock
            if ( flock($out, LOCK_EX) ) {
                for( $index = 0; $index < $chunks; $index++ ) {
                    if (!$in = fopen("{$filePath}_{$index}.part", "rb")) {
                        break;
                    }
                    while ($buff = fread($in, 4096)) {
                        fwrite($out, $buff);
                    }
                    fclose($in);
                    unlink("{$filePath}_{$index}.part");
                }
                flock($out, LOCK_UN);
            }
            fclose($out);
            $response = [
                'success'=>true,
                'oldName'=>$oldName,
                'filePath'=>$uploadPath,
//                'fileSize'=>$data['size'],
                'fileSuffixes'=>$pathInfo['extension'],          //File suffix
//                'file_id'=>$data['id'],
            ];
            return json($response);
        }
 
        // Return Success JSON-RPC response
        die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');
    }   

The back end receives fragmentation and composes files. Pay attention to several points
1: The header of the method should be limited by utf8, as follows, otherwise the file name will be garbled in Chinese
2: The return path is an absolute path, which you can intercept according to the needs of the project.

    header("Content-type: text/html; charset=utf-8");

File upload:

<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\OssClient;
use OSS\Core\OssException;

// Alicloud primary account AccessKey has access to all APIs, which is very risky. It is strongly recommended that you create and use RAM account for API access or daily operation and maintenance. Please log in https://ram.console.aliyun.com  Create a RAM account.
$accessKeyId = "<yourAccessKeyId>";
$accessKeySecret = "<yourAccessKeySecret>";
// The Endpoint takes Hangzhou as an example. Please fill in other regions according to the actual situation.
$endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
$object = "<yourObjectName>";
$file = "<yourLocalFile>";

$options = array(
    OssClient::OSS_CHECK_MD5 => true,
    OssClient::OSS_PART_SIZE => 1,
);
try{
    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);

    $ossClient->multiuploadFile($bucket, $object, $file, $options);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . ":  OK" . "\n");

Pay attention to the multiuploadFile method, which is the specific encapsulation method of piecemeal upload. Alicloud piecemeal upload is to upload a specific file. Alicloud does not admit every piece of your own, so do not try to upload the piecemeal file yourself.
Refer to the link for specific usage:
Alicloud php oss fragment upload description document

Upload the result reference document.

Method 2, web front-end direct transmission

The problem with web direct delivery is that STS temporary authorized access
You need to understand this thing
Specifically, Alibaba cloud creates a sub account with the permission of oss. The sub account with the permission of oss is equivalent to a new RAM role. Through this sub account and the id and secret generated when the role is created, a temporary token can be obtained. Through this token, the front end can perform some operations without the permission of the general account. The specific process of creating a sub account can be seen in the above link. The permissions given can be used by the front end according to your actual situation.

A detour

Alicloud provides an interface document for obtaining STS temporary authorization,
Alibaba cloud acquires sts

Note that version 2015-04-01 here fails to work. The error is as follows:

sts.aliyuncs.comInvalidVersionSpecified parameter Version is not valid.

The reply to the work order is as follows:

I'm dnmd. Why can't you hang here? Whose time is wasted?

Attachment: method of requesting interface:

class STS
{
    protected $url = 'https://sts.aliyuncs.com';
    protected $accessKeySecret = '1234567890qwertyuioasdfghj';
    protected $accessKeyId = 'LT11234567898';
    protected $roleArn = 'acs:ram::$accountID:role/$roleName';//Specify the role's ARN, role policy permission
    protected $roleSessionName = 'client1';//User defined parameters. This parameter is used to distinguish different token s and can be used for user level access audit. Format: ^ [a-zA-Z0-9 \@\-_ + $
    protected $durationSeconds = '1800';//Specified expiration time
    protected $type = 'xxx';//Get different permissions when calling conveniently

    public function __construct($type)
    {
        $this->type = $type;
        $this->setRoleArn();
    }

    public function sts()
    {
        $action = 'AssumeRole';//Get token through role-playing interface
        date_default_timezone_set('UTC');
        $param = array(
            'Format'           => 'JSON',
            'Version'          => '2015-04-01',
            'AccessKeyId'      => $this->accessKeyId,
            'SignatureMethod'  => 'HMAC-SHA1',
            'SignatureVersion' => '1.0',
            'SignatureNonce'   => $this->getRandChar(8),
            'Action'           => $action,
            'RoleArn'          => $this->roleArn,
            'RoleSessionName'  => $this->roleSessionName,
            'DurationSeconds'  => $this->durationSeconds,
            'Timestamp'        => date('Y-m-d') . 'T' . date('H:i:s') . 'Z'
            //'policy' = [1jeemaa1] / / this parameter can limit the permissions of the generated STS token. If not specified, the returned token has all the permissions of the specified role.
        );
        $param['Signature'] = $this->computeSignature($param, 'POST');
        $res = CurlHandle::httpPost($this->url, $param);//curl post request
        if ($res) {
            return self::_render($res);
        } else {
            return [];
        }
    }

    private static function _render($res)
    {
        $res = json_decode($res, true);
        if (empty($res['Credentials'])) {
            return [];
        } else {
            return [
                'accessKeySecret' => $res['Credentials']['AccessKeySecret'] ?? '',
                'accessKeyId'     => $res['Credentials']['AccessKeyId'] ?? '',
                'expiration'      => $res['Credentials']['Expiration'] ?? '',
                'securityToken'   => $res['Credentials']['SecurityToken'] ?? '',
            ];
        }
    }

    protected function computeSignature($parameters, $setMethod)
    {
        ksort($parameters);
        $canonicalizedQueryString = '';
        foreach ($parameters as $key => $value) {
            $canonicalizedQueryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($value);
        }
        $stringToSign = $setMethod . '&%2F&' . $this->percentencode(substr($canonicalizedQueryString, 1));
        $signature = $this->getSignature($stringToSign, $this->accessKeySecret . '&');

        return $signature;
    }

    public function getSignature($source, $accessSecret)
    {
        return base64_encode(hash_hmac('sha1', $source, $accessSecret, true));
    }

    protected function percentEncode($str)
    {
        $res = urlencode($str);
        $res = preg_replace('/\+/', '%20', $res);
        $res = preg_replace('/\*/', '%2A', $res);
        $res = preg_replace('/%7E/', '~', $res);
        return $res;
    }

    public function getRandChar($length)
    {
        $str = null;
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($strPol) - 1;

        for ($i = 0; $i < $length; $i++) {
            $str .= $strPol[rand(0, $max)];//rand($min,$max) generates a random integer between min and Max
        }

        return $str;
    }

    protected function setRoleArn()
    {
        if ($this->type == '123') {//Different strategies are used according to the input parameters. Of course, there are other ways of writing that are compatible with more strategies
            $this->roleArn = 'acs:ram::123456789098:role/=$roleName';
        }
    }
}

The right light

You still need to use the sdk. However, this sdk is the sdk of this module that Alibaba cloud has already packaged, which is 10000 times better than the one you downloaded from github. If you want to use tp, you can put it under vendor. If you want to use laravel, you can use it normally.
SDK download link of STS

Import project after download

Simple token request method,
1: Note that the expiration time is 3600s by default,
2: Accesskeysecret and accesskeyid are the parameters of the sub account you created, not the total account.

<?php
namespace app\services;
 
class StsService
{
    protected $url = 'https://sts.aliyuncs.com';
    protected $accessKeySecret;
    protected $accessKeyId;
    protected $roleArn;//Specify the role's ARN, role policy permission
    protected $roleSessionName = 'client';//User defined parameters. This parameter is used to distinguish different token s and can be used for user level access audit. Format: ^ [a-zA-Z0-9 \@\-_ + $
    protected $durationSeconds = '3600';//Specified expiration time
 
 
    public function __construct()
    {
        $this->accessKeySecret = config('oss_sts_accessKeySecret');
        $this->accessKeyId = config('oss_sts_accessKeyId');
        $this->roleArn = config('oss_sts_roleArn');
    }
 
 
    public function getStsOuah()
    {
 
        require_once VENDOR_PATH.'aliyuncs/sts-server/aliyun-php-sdk-core/Config.php';
 
        $iClientProfile = \DefaultProfile::getProfile("cn-hangzhou", $this->accessKeyId, $this->accessKeySecret);
 
        $client = new \DefaultAcsClient($iClientProfile);
 
        $request = new \Sts\Request\V20150401\AssumeRoleRequest();
 
        $request->setRoleSessionName("client_name");
 
        $request->setRoleArn($this->roleArn);
 
//        $request->setPolicy(VENDOR_PATH.'aliyuncs/sts-server/policy/bucket_write_policy.txt');
 
        $request->setDurationSeconds($this->durationSeconds);
 
        $response = $client->doAction($request);
 
        $rows = array();
 
        $body = $response->getBody();
 
        $content = json_decode($body);
 
        if ($response->getStatus() == 200){
            $rows['statusCode'] = 200;
            $rows['accessKeyId'] = $content->Credentials->AccessKeyId;
            $rows['accessKeySecret'] = $content->Credentials->AccessKeySecret;
            $rows['expiration'] = $content->Credentials->Expiration;
            $rows['securityToken'] = $content->Credentials->SecurityToken;
        }else{
            $rows['statusCode'] = 500;
            $rows['errorCode'] = $content->Code;
            $rows['errorMessage'] = $content->Message;
        }
 
        return $rows;
    }
 
}

The returned data needs to be passed to the front end

   Array
(
    [statusCode] => 200
    [accessKeyId] => STS.NT3aC8UXWJydcuuoyreGfvWxJ
    [accessKeySecret] => 59vT1iGHaJtEiyDwpEN9125ZgBJ4eShfUbtnXiGvQirb
    [expiration] => 2020-06-06T06:11:20Z
    [securityToken] => CAIS9QF1q6Ft5B2yfSjIr5eGKvmMuId2/buzYVPEi3k2achKmZLTqDz2IHlPdHlrBOwesv8/lGFY7fwblqJ4T55IQ1Dza8J148z5Be4Lo8yT1fau5Jko1beHewHleTOZsebWZ+LmNqC/Ht6md1HDkAJq3LL+bk/Mdle5MJqP+/UFB5ZtKWveVzddA8pMLQZPsdITMWCrVcygKRn3mGHdfiEK00he8TonsPXhn5fEskSF3QOhlbAvyt6vcsT+Xa5FJ4xiVtq55utye5fa3TRYgxowr/4t3PwfpGuf4orNUwgBuE/fKYnd/thuKh5kYLM6Gr71cwRkHn730xqAARfcIG9I3u0E7TJzfmTvcIIIpogdqzjed27c1JvZAoAxHu+6XgIBgrbcLds0q2InwBPKWF4S0nfKnI9kXPn1CXtKdjQmgLW0cRz0w9/OfbxTIX9lb2HmtWABxvLVAgQtHJRb4o6xxgkQy5pBs3BeHYJ1yY9NZCDu5zW2OGC03MqZ
)

Front end code:
I'm not a professional front-end. Let's make do with the style.

html

<div id="up_wrap"></div>
<div class="form-group">
    <input type="file" id="file" multiple="multiple" />
</div>
<div class="form-group">
    <input type="button" class="btn btn-primary" id="file-button" value="Upload" />
    <input type="button" class="btn btn-primary" id="Continue-button" value="Continue" />
</div>

js

<script src="http://gosspublic.alicdn.com/aliyun-oss-sdk-6.0.2.min.js"></script>
<script type="text/javascript">
    var appServer = 'http://www.tele.bh/med/home/sts';//Get the interface of ststoken. This is my local address. Your interface address should be clear
    var bucket = 'Your new bucket name';
    var region = 'oss-cn-hangzhou';//Selected when creating a new bucket.
    var uid = 'x';//User ID. It depends on your situation
    var Buffer = OSS.Buffer;
    console.log(OSS);
    //Get the authorization STSToken and initialize the client
    var applyTokenDo = function (func) {
        var url = appServer;
        return $.get(url).then(function (result) {
            var res = JSON.parse(result);
            var creds = res.data.Credentials;
            console.log(creds);
            var client = new OSS({
                region: region,
                accessKeyId: creds.AccessKeyId,
                accessKeySecret: creds.AccessKeySecret,
                stsToken: creds.SecurityToken,
                bucket: bucket
            });
            return func(client);
        });
    };
 
    //Upload file
    var uploadFile = function (client) {
        if (upfiles.length < 1)
            return;
        upfile = upfiles[0];
        var file = upfile.file;
        //key can be customized as a file name (for example file.txt )Or directory (for example, abc/test/file.txt )To upload files to the current Bucket or the specified directory under the Bucket.
        var key = upfile.name;
        var objkey = key + "_" + uid + ".json";
        return client.multipartUpload(key, file, {
            progress: function (p, cpt, res) {
                console.log("p:", p);
                console.log("cpt:", cpt);
                if (cpt != undefined) {
                    var content = JSON.stringify(cpt);
                    client.put(objkey, new Buffer(content));
                }
 
                console.log(Math.floor(p * 100) + '%');
                var bar = document.getElementById('progress-bar_' + upfile.num);
                bar.style.width = Math.floor(p * 100) + '%';
                bar.innerHTML = Math.floor(p * 100) + '%';
 
            }
        }).then(function (res) {
            console.log('upload success: ', res);
            upfiles.shift();
            client.delete(objkey);
            applyTokenDo(uploadFile);
        }).catch(function(err) {
            console.log(err);
            error(err);
        });
    };
 
    //Breakpoint resume file
    var reUploadFile = function (client) {
        if (upfiles.length < 1)
            return;
        upfile = upfiles[0];
        var file = upfile.file;
        //key can be customized as a file name (for example file.txt )Or directory (for example, abc/test/file.txt )To upload files to the current Bucket or the specified directory under the Bucket.
        var key = upfile.name;
        var objkey = key + "_" + uid + ".json";
        return client.get(objkey).then(function (res) {
            var data = JSON.parse(res.content);
            data.file = file;
            return client.multipartUpload(key, file, {
                checkpoint: data,
                progress: function (p, cpt, res) {
                    console.log("p:", p);
                    console.log("cpt:", cpt);
                    if (cpt != undefined) {
                        var content = JSON.stringify(cpt);
                        client.put(objkey, new Buffer(content));
                    }
                    var bar = document.getElementById('progress-bar_' + upfile.num);
                    bar.style.width = Math.floor(p * 100) + '%';
                    bar.innerHTML = Math.floor(p * 100) + '%';
                }
            }).then(function (ret) {
                console.log('upload success:', ret);
                upfiles.shift();
                client.delete(objkey);
                applyTokenDo(uploadFile);
            }).catch(function(err) {
                console.log(err);
                error(err);
            });
        });
    };
 
    function error(err){
        switch (err.status) {
            case 0:
                if (err.name == "cancel") { //Manually click to pause upload
                    return;
                }
                break;
            case -1: //Request error, auto upload again
                // Upload again;
                return;
            case 203: //Callback failed
                // The front end calls back to the back end;
                return;
            case 400:
                switch (err.code) {
                    case 'FilePartInterity': //File Part changed
                    case 'FilePartNotExist': //File Part does not exist
                    case 'FilePartState': //File Part obsolete
                    case 'InvalidPart': //Invalid Part
                    case 'InvalidPartOrder': //Invalid part order
                    case 'InvalidArgument': //Parameter format error
                        // Clear the breakpoint;
                        // Upload again;
                        return;
                    case 'InvalidBucketName': //Invalid Bucket name
                    case 'InvalidDigest': //Invalid summary
                    case 'InvalidEncryptionAlgorithmError': //The specified entropy coding encryption algorithm is wrong
                    case 'InvalidObjectName': //Invalid Object name
                    case 'InvalidPolicyDocument': //Invalid Policy document
                    case 'InvalidTargetBucketForLogging': //Invalid target bucket in Logging operation
                    case 'MalformedXML': //Illegal XML format
                    case 'RequestIsNotMultiPartContent': //Illegal Post request content type
                        // Reauthorization;
                        // Continue to upload;
                        return;
                    case 'RequestTimeout'://request timeout
                        // Upload again;
                        return;
                }
                break;
            case 403: //Invalid authorization, reauthorization
            case 411: //Missing parameter
            case 404: //Bucket/Object/Multipart Upload ID does not exist
                // Reauthorization;
                // Continue to upload;
                return;
            case 500: //OSS internal error
                // Upload again;
                return;
            default:
                break;
        }
    }
    //File upload queue
    var upfiles = [];
 
    $(function () {
        //Initialize file upload queue
        $("#file").change(function (e) {
            var ufiles = $(this).prop('files');
            var htm = "";
            for (var i = 0; i < ufiles.length; i++) {
                htm += "<dl><dt>" + ufiles[i].name + "</dt><dd><div class=\"progress\"><div id=\"progress-bar_" + i + "\" class=\"progress-bar\" role=\"progressbar\" aria-valuenow=\"0\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"min-width: 2em;\">0%</div></div></dd></dl>";
                upfiles.push({
                    num: i,
                    name: ufiles[i].name,
                    file: ufiles[i]
                })
            }
            console.log('upfiles:', upfiles);
            $("#up_wrap").html(htm);
        });
        //upload
        $("#file-button").click(function () {
            applyTokenDo(uploadFile);
        });
        //Sequel
        $("#Continue-button").click(function () {
            applyTokenDo(reUploadFile);
        })
    })
</script>

After the fragment upload is completed, the folder link with uploadId will be returned and uploaded to the backend.
Pay attention to a few points,
1: When setting the permissions of roles, you need to give put and delete permission, otherwise js will report an error.
2: Cross domain access: access control allow origin header is required for role setting to allow cross domain access.

Comprehensive description

The function is not so difficult. The problem is that either the documents provided by Alibaba cloud are not easy to use, or the sdk is difficult to use. I also synthesized several documents from Baidu before I came out. I hope you can avoid detours in the future.

Topics: PHP JSON SDK Fragment