zoukankan      html  css  js  c++  java
  • 服务器端支持断点上传

    将up.php拷贝到网站根目录,根目录创建uploads文件夹用于存储上传文件,配置权限.

    一,普通文件上传(完成上传返回201)
    
    curl -F "action=upload" -F "Filedata=@a.file" -v "http://127.0.0.1/up.php"
    * About to connect() to 127.0.0.1 port 80 (#0)
    *   Trying 127.0.0.1... connected
    > POST /up.php HTTP/1.1
    > User-Agent: curl/7.23.1 (x86_64-unknown-linux-gnu) libcurl/7.23.1 OpenSSL/0.9.8h zlib/1.2.3
    > Host: 127.0.0.1
    > Accept: */*
    > Content-Length: 21810
    > Expect: 100-continue
    > Content-Type: multipart/form-data; boundary=----------------------------e0b0c03a69b3
    >
    < HTTP/1.1 100 Continue
    < HTTP/1.1 201 Created
    < Server: ngx_openresty
    < Date: Mon, 14 Oct 2013 02:09:55 GMT
    < Content-Type: text/html
    < Transfer-Encoding: chunked
    < Connection: keep-alive
    <
    * Connection #0 to host 127.0.0.1 left intact
    Upload OK* Closing connection #0
    
    二,指定分片上传(未完成上传返回202并返回下一个需要上传分片信息,上传完毕返回201,上传错误返回500,对此客户端可以查询上传状态)
    
    curl -F "action=upload" -F "Filedata=@a.file" -H "Range: bytes=30720-52226/52227" -v "http://127.0.0.1/up.php"
    * About to connect() to 127.0.0.1 port 80 (#0)
    *   Trying 127.0.0.1... connected
    > POST /up.php HTTP/1.1
    > User-Agent: curl/7.23.1 (x86_64-unknown-linux-gnu) libcurl/7.23.1 OpenSSL/0.9.8h zlib/1.2.3
    > Host: 127.0.0.1
    > Accept: */*
    > Range: bytes=30720-52226/52227
    > Content-Length: 21810
    > Expect: 100-continue
    > Content-Type: multipart/form-data; boundary=----------------------------ae9de390286d
    >
    < HTTP/1.1 100 Continue
    < HTTP/1.1 202 Accepted
    < Server: ngx_openresty
    < Date: Mon, 14 Oct 2013 02:14:41 GMT
    < Content-Type: text/html
    < Transfer-Encoding: chunked
    < Connection: keep-alive
    < Range: bytes=0-30719/52227
    <
    * Connection #0 to host 127.0.0.1 left intact
    Upload Continue* Closing connection #0
    
    三,查询文件上传状态(上传完毕返回201,不存在此文件返回404,未上传完毕返回202并下一个需要上传的分片范围)
    
    curl -I -H "Filename: a.file" "http://127.0.0.1/up.php"
    HTTP/1.1 202 Accepted
    Server: ngx_openresty
    Date: Mon, 14 Oct 2013 02:16:25 GMT
    Content-Type: text/html
    Connection: keep-alive
    Range: bytes=0-30719/52227
    
    四,对于大文件和超大文件可以通过多次分片上传实现
    
    curl -F "action=upload" -F "Filedata=@big.file" -H "Range: bytes=0-102399/1024000000" -v "http://127.0.0.1/up.php"
    curl -F "action=upload" -F "Filedata=@big.file" -H "Range: bytes=102400-204799/1024000000" -v "http://127.0.0.1/up.php"
    curl -F "action=upload" -F "Filedata=@big.file" -H "Range: bytes=204800-303599/1024000000" -v "http://127.0.0.1/up.php"
    ...
    
    五,对读写分片信息加文件锁还可实现多线程上传

    up.php源代码如下

    <?php
    //up.php
    
    // Define a folder to upload
    $targetFolder = '/uploads'; // Relative to the root
    
    function array_sort($arr) {
        $karr = array();
        for($i=0;$i<count($arr);$i++){
            $karr[$arr[$i][0]] = $arr[$i][1];
        }
        ksort($karr);
        $arr = array();
        foreach($karr as $k => $v){
            $arr[] = array($k,$v);
        }
        return $arr;
    }
    /**
    * Update range of uploaded segments of file
    */
    function updateRange($rangefile, $start, $end, $totalsize){
        if(file_exists($rangefile)){
            $data = json_decode(file_get_contents($rangefile));
        }
        
        if(is_null($data) or is_null($data->range) or count($data->range) == 0) {
            $data->range = array(array($start, $end));//create a record if not exists
            $data->totalsize = $totalsize;
        } else {
            $range = array_sort($data->range);
            $c = count($range);
            for($i=0;$i<$c;$i++){
                if($range[$i][0] > $end + 1) {// insert before $i
                    $range[] = array($start,$end);
                    break;
                } else if($range[$i][1] + 1< $start){
                    if($i == $c - 1){// insert end of all
                        $range[] = array($start,$end);
                        break;
                    } else {
                        continue;
                    }
                } else{
                    $range[$i][0] = $range[$i][0] < $start?$range[$i][0]:$start;
                    for($j = $i;$j < $c;$j ++){
                        if($j == $c - 1){
                            $range[$i][1] = $range[$j][1] > $end?$range[$j][1]:$end;
                            if($i < $j){//combine segments
                                unset($range[$j]);
                            }
                            break;
                        } else {
                            if($range[$j+1][0] > $end + 1){
                                $range[$i][1] = $range[$j][1] > $end?$range[$j][1]:$end;
                                if($j > $i){//combine segments
                                    unset($range[$j]);
                                }
                                break;
                            }else{
                                if($j > $i){//combine segments
                                    unset($range[$j]);
                                } else {
                                    continue;
                                }
                            }
                        }
                    }
                    break;
                }
            }
            $data->range = $range;
        }
        //save status
        file_put_contents($rangefile,json_encode($data));
    }
    
    /**
    * Lookup Next Range for upload
    */
    function lookupRange($rangefile){
        if(file_exists($rangefile)){
            $data = json_decode(file_get_contents($rangefile));
        }else{
            return array("Not Found","","");
        }
        if(is_null($data) or is_null($data->range) or count($data->range) == 0) {
            return array("Not Found","","");
        } else {
            $range = array_sort($data->range);
            $c = count($range);
            if($c == 1 && $range[0][0] == 0 && $range[0][1]+1 == $data->totalsize){
                return array("Created","","");
            }
            $start = 0;
            $end = $data->totalsize-1;
            for($i=0;$i<$c;$i++){
                if($range[$i][0]<=$start){
                    $start = $range[$i][1];
                    if($i+1<$c){
                        $end = $range[$i+1][0]-1;
                    }
                } else{
                    $end = $range[$i][0]-1;
                }
                break;
            }
            return array($start,$end,$data->totalsize);
        }
    }
    
    if(!is_null(@$_SERVER['REQUEST_METHOD']) && @$_SERVER['REQUEST_METHOD'] == "HEAD"){
        if(is_null($_SERVER["HTTP_FILENAME"])){
            header("HTTP/1.0 400 Bad Request");
            exit(-1);
        }
        $filename = $_SERVER["HTTP_FILENAME"];
        list($start,$end,$size) = lookupRange(rtrim($_SERVER['DOCUMENT_ROOT'] . $targetFolder,'/')."/".$filename.".range");
    
        if("Not Found" === $start){
            header("HTTP/1.0 404 File Not Found");
        } else if("Created" === $start){
            header("HTTP/1.0 201 Created");
        } else{ 
            header("HTTP/1.0 202 Accepted");
            header("Range: bytes=$start-$end/$size");
        }
        exit(-1);
    }
    
    if(!is_null(@$_SERVER['REQUEST_METHOD']) && @$_SERVER['REQUEST_METHOD'] != "POST"){
        header("HTTP/1.0 400 Bad Request");
        exit(-1);
    }
    
    if (!empty($_FILES)) {
        $tempFile = $_FILES['Filedata']['tmp_name'];
        $targetPath = $_SERVER['DOCUMENT_ROOT'] . $targetFolder;
        $targetFile = rtrim($targetPath,'/') . '/' . $_FILES['Filedata']['name'];
    
        if(is_null($_SERVER["HTTP_RANGE"])){
            move_uploaded_file($tempFile,iconv("UTF-8","gb2312", $targetFile));
            $size = $_FILES['Filedata']['size'];
            updateRange($targetFile.".range",0,$size-1,$size);
            header("HTTP/1.0 201 Created");
            echo "Upload OK";
        } else {
            $pos = $_SERVER["HTTP_RANGE"];
            $range = ltrim($pos, "bytes=");
            list($start,$end,$size) = split('[-/]',$range);
            $pos = $start;
            $r_fp = fopen($tempFile, 'r');
            if(file_exists($targetFile)){
                $w_fp = fopen($targetFile, 'r+');
            }else{
                $w_fp = fopen($targetFile, 'w+');
            }
            while($data = fread($r_fp, 4092)){
                flock($w_fp,LOCK_EX);
                fseek($w_fp, $pos, SEEK_SET);
                fwrite($w_fp, $data);
                flock($w_fp,LOCK_UN);
                $pos += strlen($data);
            }
    
            fclose($r_fp);
            fclose($w_fp);
            updateRange($targetFile.".range",$start,$end,$size);
            list($start,$end,$size) = lookupRange($targetFile.".range");
    
            if("Not Found" === $start){
                header("HTTP/1.0 500 Internal Server Error");
                echo "Upload Failed";
            } else if("Created" === $start){
                header("HTTP/1.0 201 Created");
                echo "Upload OK";
            } else {
                header("HTTP/1.0 202 Accepted");
                header("Range: bytes=$start-$end/$size");
                echo "Upload Continue";
            }
        }
    }
    ?>
  • 相关阅读:
    nginx 阻止ip访问
    mysql sql语句性能分析
    SWFUpload demo
    XSHELL win7 和 linux 系统之间文件互传
    基于HTTP协议的轻量级开源简单队列服务:HTTPSQS
    The following packages have been kept back
    php 错误日志记录
    TWIG 分页宏(基于 bootstrap)
    gitconfig 全局配置文件。
    简单的图片异步上传代码
  • 原文地址:https://www.cnblogs.com/ciaos/p/3367027.html
Copyright © 2011-2022 走看看