ddvphp/ddv-file

ddv-file php library

0.0.1 2017-07-25 02:57 UTC

This package is not auto-updated.

Last update: 2020-10-17 06:48:33 UTC


README

Installation - 安装

composer require ddvphp/ddv-file
  • [客户端] 代指 IOS 安卓 Html5 flash
  • [device_type] 目前允许 ios android html5 htmlswf html4 wxmp
  • 微信公众平台的浏览器一定要使用wxmp,不建议使用html5
  • 否则会导致部分手机上传失败,因为微信浏览器的限制导致分块的计算公式不一样

一、客户端使用

1、获取分块大小

首先客户端[IOS 安卓 Html5 flash]获取文件大小, 调用一下接口,获取到分块大小以及总分块数

  • ==服务户端计算规则==
  • 定义 $part_size_min = 400*1024;
  • 定义 $part_size_max = 15*1024*1024;
  • 计算 $part_size = ceil(max($file_size/1000 , $part_size_min))
  • 判断 $part_size如果大于$part_size_max抛出异常 暂时不能上传大于15G的文件
  • 计算 $part_sum = ceil($file_size/$part_size)
  • 判断 $part_sum如果大于1000抛出异常 可以等于 1000 暂时不能上传大于15G的文件
  • 因为我们的服务器目前设定最大接受上传15G 另外分块太大也给移动端带来压力
  • 分块大小计算 是 取大原则 向上去整
  • ==服务户端计算规则==
请求地址:v1_0/upload/filePartSize
使用说明:获取分块大小
需要登录:
请求方法:GET
数据形式:x-www-form-urlencodedform-data

发送以下信息到服务器

属性 类型 是否必填 说明
fileSize int 文件大小。
fileType string 可以参考**Mime 类型列表** 未知类型为 application/octet-stream
deviceType string 设备类型 ios android html5 htmlswf html4 wxmp

样板数据

{
  "fileSize"   :    "46650955",
  "fileType"   :    "audio/mp3",
  "deviceType" :    "html5"
}

返回结果

属性 类型 是否必填 说明
partSize int 切片大小。
partSum int 切片总块数。

样板数据

"partSize"      :"409600",
"partSum"           :114

2、获取文件id

  • 前端读流方式计算文件的相关信息
  • partSize的大小进行流式读取文件
  • 计算文件的总内容的md5fileMd5
  • 计算文件的总内容的sha1fileSha1
  • 计算文件的总内容的crc32fileCrc32
  • 计算当前每一块的流的二进制md5hex值 并且拼接为partMd5Str
  • 比如第一块md50fdf5be93cd24aeeaccb046406c3a643
  • 比如第二块md5986f5be93cd24ae9accb047776c3a332
  • 比如第三块md585658be93cd24aeeaccb046406c3a757
  • 使用partMd5Str = partMd5Str + {上一块md5}
  • 那么partMd5Str0fdf5be93cd24aeeaccb046406c3a643986f5be93cd24ae9accb047776c3a33285658be93cd24aeeaccb046406c3a757
  • partMd5Str随着分块累计不停变长,但是不会超过 1000*32=32000字节
  • 最后 得到 md5sha1crc32
  • 还有 filePartMd5Lower = md5(partMd5Str[转小写]) + '-' + partSum
  • 还有 filePartMd5Upper = md5(partMd5Str[转大写]) + '-' + partSum
  • 得到 filePartMd5Lower4CF26963D7C141DEFBC985382538B43F-3
  • 得到 filePartMd5UpperBB49107DFF0A0054DC67D94B1FFC5A24-3
请求地址:v1_0/upload/fileId
使用说明:获取分块大小
需要登录:
请求方法:GET
数据形式:x-www-form-urlencodedform-data

发送以下信息到服务器

属性 类型 是否必填 说明
fileMd5 string 文件md5[Hex][大写Hex结果]。
fileSha1 string 文件sha1[Hex][大写Hex结果]。
fileCrc32 string 文件crc32[Hex][大写Hex结果]。
filePartMd5Lower string 多块小写md5的md5[大写Hex结果]。
filePartMd5Upper string 多块大写md5的md5[大写Hex结果]。
fileName string 文件名称[带扩展名]。
fileSize int 文件大小[字节数]。
fileType string 可以参考**Mime 类型列表** 未知类型为 application/octet-stream
lastModified int|float 文件最后修改时间[时间戳,到秒,可以带小数]。
manageType string 权限类型[admin|user]。
directory string 目录[默认common/other]。
deviceType string 设备类型 ios android html5 htmlswf html4
authType string .......具体看后台应用的业务需要

样板数据

"fileCrc32"       :"5434bd00",
"fileMd5"         :"0fdf5be93cd24aeeaccb046406c3a643",
"fileSha1"          :"4b0e042ee37cc8947bd6e4a5ef6bbc53a85ba7f9",
"filePartMd5Lower"   :"4CF26963D7C141DEFBC985382538B43F-3",
"filePartMd5Upper"   :"BB49107DFF0A0054DC67D94B1FFC5A24-3",
"fileName"          :"1.mp3",
"fileSize"          :"46650955",
"fileType"          :"audio/mp3",
"lastModified"        :"1449682232.043",
"manageType"        :"admin",
"directory"         :"common/other",
"deviceType"        :"html5"

返回结果

属性 类型 是否必填 说明
fileId string 文件id。
fileCrc32 string 文件crc32。
fileMd5 string 文件md5。
fileSha1 string 文件sha1。
url string 文件如果成功上传后的url。
path string 文件如果成功上传后的path。
isUploadEnd boolean 是否已经成功上传。

样板数据

"fileId"          :"1",
"fileCrc32"         :"5434bd00",
"fileMd5"       :"0fdf5be93cd24aeeaccb046406c3a643",
"fileSha1"        :"4b0e042ee37cc8947bd6e4a5ef6bbc53a85ba7f9",
"path"            :"/fafssdf/df/as/fas/s.jpg",
"url"           :"http://www.xxxx.x.com/fafssdf/df/as/fas/s.jpg",
"isUploadEnd"           :false

如果 isUploadEnd 已经成功上传就跳过下列所有步骤

3、获取成功上传的信息

请求地址:v1_0/upload/filePartInfo
使用说明:获取成功上传的信息
需要登录:
请求方法:GET
数据形式:x-www-form-urlencodedform-data

发送以下信息到服务器

属性 类型 是否必填 说明
fileId string 文件id。
fileMd5 string 文件md5[Hex][大写Hex结果]。
fileSha1 string 文件sha1[Hex][大写Hex结果]。
fileCrc32 string 文件crc32[Hex][大写Hex结果]。

样板数据

"fileId"          :"1",
"fileCrc32"     :"5434bd00",
"fileMd5"       :"0fdf5be93cd24aeeaccb046406c3a643",
"fileSha1"        :"4b0e042ee37cc8947bd6e4a5ef6bbc53a85ba7f9"

服务器返回

属性 类型 是否必填 说明
fileSize int 文件大小。
partSize int 分块大小。
partSum string 总的分块个数。
doneParts array 成功上传的数组。
isUploadEnd boolean 是否已经成功上传。

样板数据

"fileSize"      :"46650955",
"partSize"      :"46651",
"partSum"           :1000,
"doneParts"         :[1,3,6,8],
"isUploadEnd"       :false

客户端从1开始循环到{partSum}切块 执行4、获取分块签名的步骤 跳过doneParts的成功上传块

服务在这个时候建立uploadid 并且查询成功上传的块信息 如果是第一次产生的uploadid 块信息doneParts为空数组 如果有uploadid就查询阿里云或者百度云的done_parts信息

注意 如果 isUploadEnd已经成功上传就跳过下列所有步骤

4、获取分块签名

请求地址:v1_0/upload/filePartMd5
使用说明:获取成功上传的信息
需要登录:
请求方法:GET
数据形式:x-www-form-urlencodedform-data

发送以下信息到服务器

属性 类型 是否必填 说明
fileId string 文件id。
fileMd5 string 文件md5[Hex][大写Hex结果]。
fileSha1 string 文件sha1[Hex][大写Hex结果]。
fileCrc32 string 文件crc32[Hex][大写Hex结果]。
partNumber int 当前分块的序号,第几块。
partLength int 当前分块的字节数,分块的大小或者最后一块大小。
md5Base64 string 文件的md5的二进制值进行base64参考这个说明
deviceType string 设备类型[ios android html5 htmlswf html4]。
isHeaderArray string 是否传回数组头[默认:flase]。

样板数据

"fileId"               :"1",
"fileCrc32"            :"5434bd00",
"fileMd5"              :"0fdf5be93cd24aeeaccb046406c3a643",
"fileSha1"             :"4b0e042ee37cc8947bd6e4a5ef6bbc53a85ba7f9",
"partNumber"           :"1",
"partLength"           :"30",
"md5Base64"            :"MDE1Mjg4ZDViMGFmZjBiYzExOTQ0NDhlODFmZDU1NTQ=",
"deviceType"           :"html5"

服务器返回

属性 类型 是否必填 说明
url string 分块数据请求发送地址。
method string 分块数据请求发送方式。
headers array 分块数据请求头。

样板数据

{
  "data":{
    "url":"http://xxxx.x.x.x.x.x.x/caomdsfas/fda/dfa/dsa",
    "method":"PUT",
    "headers":{
        "Content-Type":"application/octet-stream",
        "Content-Md5":"MDE1Mjg4ZDViMGFmZjBiYzExOTQ0NDhlODFmZDU1NTQ="
     },
    "headers_array":[
        ["Content-Type","application/octet-stream"],
        ["Content-Md5","MDE1Mjg4ZDViMGFmZjBiYzExOTQ0NDhlODFmZDU1NTQ="]
     ]
  }
}

因为头的key的特殊性 传参可以带 isHeaderArray = true 来得到数组头

5、获取成功上传的信息

请求地址:v1_0/upload/complete
使用说明:获取成功上传的信息
需要登录:
请求方法:POST
数据形式:x-www-form-urlencodedform-data

发送以下信息到服务器

属性 类型 是否必填 说明
fileId string 文件id。
fileMd5 string 文件md5[Hex][大写Hex结果]。
fileSha1 string 文件sha1[Hex][大写Hex结果]。
fileCrc32 string 文件crc32[Hex][大写Hex结果]。

样板数据

{
  "fileId"          :"1",
  "fileCrc32"       :"5434bd00",
  "fileMd5"         :"0fdf5be93cd24aeeaccb046406c3a643",
  "fileSha1"        :"4b0e042ee37cc8947bd6e4a5ef6bbc53a85ba7f9"
}

服务器返回有 空数组代表成功,如果抛出异常就看一下是否为漏切片

二、服务器使用

我们以laravel框架为样本使用

我们以laravel提供一个样本

==服务户端计算规则== 定义 $partSizeMin = 400*1024; 定义 $partSizeMax = 15*1024*1024; 计算 $partSize = ceil(min(fileSize,max(ceil(fileSize/$partSumMax),$partSizeMin))) 判断 $partSize如果大于$partSizeMax抛出异常 暂时不能上传大于15G的文件 计算 $partSum = ceil($fileSize/$partSize) 判断 $partSum如果大于1000抛出异常 可以等于 1000 暂时不能上传大于15G的文件 因为我们的服务器目前设定最大接受上传15G 另外分块太大也给移动端带来压力 分块大小计算 是 取大原则 向上去整 ==服务户端计算规则==

1、路由初配置

Route::group(['prefix'=>'upload'],function(){
    Route::get('filePartSize','Api\UploadController@filePartSize');
    Route::get('fileId','Api\UploadController@fileId');
    Route::get('filePartInfo','Api\UploadController@filePartInfo');
    Route::get('filePartMd5','Api\UploadController@filePartMd5');
    Route::post('complete','Api\UploadController@complete');
});

2、控制器文件Api\UploadController

2.1、 配置初始化

  public function __construct(){
    method_exists(parent::class, '__construct') && parent::__construct();
    $this->fileConfigInit();
  }
  private function fileConfigInit (){
    // 基本配置
    $config = [
      // uid 可以为null和字符串0
      // uid 如果为null 每次获取fileId都会拿到新的id,因为每个文件不确定是那个用户的
      // uid 如果为0 ,插件支持0这个uid,没有登录的用户统一视为0这个用户的
      'uid'=>'0'
      // fileIndex 是一个可选参数,如果配置了,会导致文件系统返回的地址通通是索引地址哦
      // fileIndex 是一个索引标识
      'fileIndex'=>'videolive',
      // 默认不属于uid标识索引文件
      'fileIndexUseUid'=>false,
      // 默认一块最小字节数
      'partSizeMin'=>400*1024,
      // 默认一块最大字节数
      'partSizeMax'=>15*1024*1024,
      // 默认一共可以多少块
      'partSumMax'=>1000
    ];
    // 使用存储驱动,比如阿里云的驱动,也可以pr扩展驱动[感谢]
    $drivers = new \DdvPhp\DdvFile\Drivers\AliyunOssDrivers(config('aliyun.oss'));
    // 数据库模型,目前提供laravel数据模型,也可以pr数据模型[感谢]
    $database = new \DdvPhp\DdvFile\Database\LaravelMysqlDatabase();
    // 实例化文件类
    $this->upload = new \DdvPhp\DdvFile($config, $drivers, $database);
  }

2.2、获取分块大小 接口

  ## 获取分块大小
  public function filePartSize (Request $request){
    return [
      'data' =>
        $this->upload->getPartSize($request->only(['fileSize','fileType','deviceType']))
    ];
  }

2.3、获取文件id 接口

  ## 获取文件id
  public function fileId(Request $request){
    $input = $request->only(
      $this->upload->getFileIdInputKeys([
        // 授权类型
        'authType',
        // 管理类型
        'manageType',
        // 上传目录
        'directory'
      ])
    );
    // 自己的业务逻辑,和权限逻辑
    return [
      'data' =>
        $this->upload->getFileId($input)
    ];
  }

2.3、获取成功上传的信息

  ## 获取成功上传的信息
  public function filePartInfo(Request $request){
    $input = $request->only(
      [
        'fileId',
        'fileMd5',
        'fileSha1',
        'fileCrc32'
      ]
    );
    return [
      'data' =>
        $this->upload->getFilePartInfo($input)
    ];
  }

2.4、获取分块签名

  ## 获取分块签名
  public function filePartMd5 (Request $request){
    $input = $request->only(
      [
        'fileId',
        'fileMd5',
        'fileSha1',
        'fileCrc32',


        'contentMd5',
        'partLength',
        'partNumber'
      ]
    );
    return [
      'data' =>
        $this->upload->getFilePartMd5($input)
    ];

  }

2.5、合并上传文件

  ## 合并上传文件
  public function complete(Request $request){
    $input = $request->only(
      [
        'fileId',
        'fileMd5',
        'fileSha1',
        'fileCrc32'
      ]
    );
    return [
      'data' =>
        $this->upload->complete($input)
    ];
  }