php阿里云oss文件上传

php的文件上传

文件上传

php的文件上传放在了$_FILES数组里,单文件和多文件上传的区别在于$_FILES['userfile']['name']是否为数组,
不熟悉的可以读一下官方文档 单文件上传 多文件上传

阿里云oss web直传实践

这里采用的是服务端签名后上传,没有使用回调。

阿里云提供了一个php和前端的示例,不过有点坑人,前端采用的是plupload插件,这种demo应该使用原生js更合适啊,毕竟上传的js插件各不相同。
使用jquery的ajax上传时,始终上传失败,于是用fiddler抓包demo,才知道了上传给oss的详细参数格式。

吐槽完毕,下面才是正式上菜。

  • 服务端生成policy,这里使用php
    下面的代码是从官方demo修改而来,可以通过Facade模式增加静态方法,方便调用。
    注意dir目录不能使用"/"开始。下面的签名算法来自阿里云的demo。
<?php
class OssPolicy
{

    private $oss_bucket ;
    private $oss_host;
    private $oss_appid;
    private $oss_appsecret;
    private $oss_expire ;//过期时间
    /**
     * OssPolicy constructor.
     * @param $bucket 阿里云oss的bucket
     * @param $host 对应bucket的host
     * @param $appId app_id
     * @param $appSecret app_secret
     * @param int $expire 过期时间
     */
    public function __construct($bucket,$host,$appId,$appSecret,$expire=900) {
        $this->oss_expire = $expire;
        $this->oss_bucket = $bucket;
        $this->oss_host = $host;
        $this->oss_appid = $appId;
        $this->oss_appsecret = $appSecret;
    }

    private function gmt_iso8601($time) {
        $dtStr = date("c", $time); //格式为2016-12-27T09:10:11+08:00
        $mydatetime = new DateTime($dtStr);
        $expiration = $mydatetime->format(DateTime::ISO8601); //格式为2016-12-27T09:12:32+0800
        $pos = strpos($expiration, '+');
        $expiration = substr($expiration, 0, $pos);//格式为2016-12-27T09:12:32
        return $expiration."Z";
    }

    /**
     * @function getPolicy 获取policy
     * @author 
     * @version 1.0
     * @date
     * @param $dir 上传目录
     * @param $maxSize 最大文件大小 单位M
     * @param int $expireTime 过期时间
     * @return $array policy
     */
    public function getPolicy($dir,$maxSize=100,$expireTime=null){
        $expireTime = isset($expireTime) ? $expireTime : $this->oss_expire;
        $end = time() + $expireTime;
        $expiration = $this->gmt_iso8601($end);

        $conditions = [];
        $conditions[] = array(0=>'content-length-range', 1=>0, 2=>1024*1024*$maxSize); // 最大文件大小.用户可以自己设置 100M

        $start = array(0=>'starts-with', 1=>'$key', 2=>$dir); //表示用户上传的数据,必须是以$dir开始, 不然上传会失败,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录
        $conditions[] = $start;

        $arr = array('expiration'=>$expiration,'conditions'=>$conditions);
        $policy = json_encode($arr);
        $base64_policy = base64_encode($policy);
        $string_to_sign = $base64_policy;
        $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $this->oss_appsecret, true));

        $response = array();
        $response['accessid'] = $this->oss_appid;
        $response['host'] = $this->oss_host;
        $response['policy'] = $base64_policy;
        $response['signature'] = $signature;
        $response['expire'] = $end;
        $response['bucket'] = $this->oss_bucket;
        $response['dir'] = $dir;  //这个参数是设置用户上传指定的前缀

        return $response;
    }
}
  • 前端
    过程 想后端请求policy,上传到阿里云,成功后通知后端
    不要问我代码为啥这么乱,我不生产代码,我只是代码的搬运工(从阿里云demo里搬出来,稍加修改)
    在用表单提交时,注册一下提交处理的函数,取出文件,然后OssUpload()即可。
oss_accessid = ''
oss_accessoss_key = ''
oss_host = ''
oss_policyBase64 = ''
oss_signature = ''
oss_callbackbody = ''
oss_filename = ''
oss_key = ''
oss_expire = 0
g_object_name = ''
g_object_name_type = 'local_name'
OSS_FILE_NAME_TYPE_LOCAL = "local_name"
OSS_FILE_NAME_TYPE_RANDOM = "random_name"

oss_now = oss_timestamp = Date.parse(new Date()) / 1000;

//向服务端请求policy
function send_request() {
    
}
//生成签名
function get_oss_signature() {
    //可以判断当前oss_expire是否超过了当前时间,如果超过了当前时间,就重新取一下.3s 做为缓冲
    oss_now = oss_timestamp = Date.parse(new Date()) / 1000;
    if (oss_expire < oss_now + 3) {
        body = send_request()
        var obj = eval("(" + body + ")");
        oss_host = obj['host']
        oss_policyBase64 = obj['policy']
        oss_accessid = obj['accessid']
        oss_signature = obj['signature']
        oss_expire = parseInt(obj['expire'])
        oss_callbackbody = obj['callback']
        oss_key = obj['dir']

    }

}

//随机字符串
function random_string(len) {
    len = len || 32;
    var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
    var maxPos = chars.length;
    var str = '';
    for (i = 0; i < len; i++) {
        str += chars.charAt(Math.floor(Math.random() * maxPos));
    }
    return str;
}
//获取文件名后缀
function get_suffix(filename) {
    pos = filename.lastIndexOf('.')
    suffix = ''
    if (pos != -1) {
        suffix = filename.substring(pos)
    }
    return suffix;
}
//根据文件名类型 临时文件还是原始文件名,返回文件名
function calculate_object_name(filename) {
    if (g_object_name_type == 'local_name') {
        g_object_name = oss_key + "${filename}"
    }
    else if (g_object_name_type == 'random_name') {
        suffix = get_suffix(filename)
        g_object_name = oss_key + random_string(10) + suffix
    }
    return ''
}

//把policy填充到Formdata里
function set_upload_param(file) {

    get_oss_signature()
    if (file) {

        calculate_object_name(file.name);
        var res = {
            'key': g_object_name,
            'policy': oss_policyBase64,
            'OSSAccessKeyId': oss_accessid,
            'success_action_status': '200', //让服务端返回200,不然,默认会返回204
//                'callback': oss_callbackbody,
            'signature': oss_signature,
        };

        var form_data = new FormData();
        for ( var key in res ) {
            form_data.append(key, res[key]);
        }
        form_data.append("file",file);

        return res;
    }

    return false;

}

//上传到阿里云 callBack 是用来在上传成功后通知服务端
function OssUpload( file,fileNameType,callBack) {
    g_object_name_type = fileNameType;
    var form_data = set_upload_param(file.name);
    
    if(!form_data){
        alert("form_data error")
        return
    }
    var fileFullName = oss_host+form_data.get("key");
   
    $.ajax({
        url: oss_host,
        data: form_data,
        processData: false,
        cache: false,
        async: false,
        type:'POST',
        contentType: false,//这个就是了
        success: function (data, textStatus, request) {
           
            //textStatus === "success" 表示成功
            if(typeof callBack === "function") {
                callBack(fileFullName,form_data.get("policy"),textStatus);
            }

        },
        error : function(responseStr) {
          
            if(typeof callBack === "function") {
                callBack(fileFullName,form_data.get("policy"),responseStr.responseText);
            }
        }
    });
}
posted @ 2017-04-05 18:44  半山th  阅读(13523)  评论(2编辑  收藏  举报