后端代码:
<?php
namespace app\admin\controller\auth;
use app\common\controller\Backend;
use Mts\Request\V20140618 as Mts;
use vod\Request\V20170321 as vod;
use Kms\Request\V20160120 as kms;
use OSS\OssClient;
// require_once VENDOR_PATH . '../extend/sts-server/aliyun-php-sdk-core/Config.php';
use Sts\Request\V20150401 as Sts;
/**
* 规则管理
*
* @icon fa fa-list
* @remark 规则通常对应一个控制器的方法,同时左侧的菜单栏数据也从规则中体现,通常建议通过控制台进行生成规则节点
*/
class Upload extends Backend
{
/**
* @var \app\admin\model\AuthRule
*/
protected $model = null;
protected $rulelist = [];
protected $url = 'https://sts.aliyuncs.com';
//RAM子账号下的accessKey(不要使用主账号创建)否则会报Roles may not be assumed by root accounts.错误
protected $accessKeyId='xxxxx';
protected $accessKeySecret = 'xxxxxxx';
//一定要在OSS存储里设置跨域设置,并且允许所以访问请求,暴露header写
//etag
//x-oss-request-id
//其他写*号,代表所以请求都能访问
protected $roleArn="acs:ram::1968572159217379:role/oss";//指定角色的 ARN ,角色策略权限
protected $roleSessionName = 'client';//用户自定义参数。此参数用来区分不同的 token,可用于用户级别的访问审计。格式:^[a-zA-Z0-9\.@\-_]+$
protected $durationSeconds = '3600';//指定的过期时间
private $accessVideoKeyId = 'xxxx';
private $accessVideoKeySecret = 'xxxxx';
private $regionVideoId = 'cn-beijing'; // 点播服务所在的Region,国内请填cn-shanghai,不要填写别的区域
private $endpointVideo = 'oss-cn-beijing.aliyuncs.com';
private $stsVideo = null;
protected $client = null;
public function _initialize()
{
parent::_initialize();
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax()) {
$form = $this->request->post();
$data = [
'admin_id'=>1,
'uploadtime'=>time(),
'createtime'=>time(),
'updatetime'=>time(),
'filename'=>$form['filename'],
'url'=>$form['fileurl'],
'filesize'=>$form['filesize'],
'mimetype'=>$form['mimetype'],
'imagetype'=>$form['imagetype'],
'storage'=>'cloud'
];
$attachment = model('attachment')->save($data);
$res = ['url'=>$form['fileurl']];
$this->success('上传成功!','',$res);
return json($attachment);
}
return $this->view->fetch();
}
//oss上传
public function alists(){
require_once VENDOR_PATH.'../extend/sts-server/aliyun-php-sdk-core/Config.php';
$iClientProfile = \DefaultProfile::getProfile("cn-beijing", $this->accessKeyId, $this->accessKeySecret);
$client = new \DefaultAcsClient($iClientProfile);
$request = new \Sts\Request\V20150401\AssumeRoleRequest();
$request->setRoleSessionName("client_name");
$request->setRoleArn($this->roleArn);
$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 json_encode($content);
// $rows
print_r($rows);
}
public function video_demand_upload($fileName=''){
if ($this->request->isAjax()) {
$info = [
'title'=>time().'.mp4',
'filename'=>time().'.mp4',
'desc'=>'1',
];
if($fileName){
$info['title'] = $fileName;
$info['filename'] = $fileName;
}
return $this->create_upload_video($info);
}
return $this->view->fetch();
}
/**
* @desc [获取上传地址和凭证/上传到视频点播服务]
* @param [type] $client [description]
* @param array $fileInfo = array();
* @return [type] [description]
*/
private function create_upload_video($fileInfo)
{
require_once VENDOR_PATH . '../extend/aliyun-openapi-php-sdk/aliyun-php-sdk-core/Config.php';
try {
$this->init_vod_client($this->accessVideoKeyId, $this->accessVideoKeySecret);
} catch (\Exception $e) {
print $e->getMessage();
exit();
}
$request = new vod\CreateUploadVideoRequest();
$request->setTitle($fileInfo['title']); // 视频标题(必填参数)
$request->setFileName($fileInfo['filename']); // 视频源文件名称,必须包含扩展名(必填参数)
$request->setDescription($fileInfo['desc']); // 视频源文件描述(可选)
//转码模板ID
$request->setTemplateGroupId("2cab6fbdeac04425d80ee87657f4bb8c");
$request->setAcceptFormat('JSON');
$res = $this->client->getAcsResponse($request);
if(empty($res->VideoId)){
$this->error('上传失败!');
}
model('Videotask')->save(['video_id'=>$res->VideoId]);
return $res;
}
/**
* @desc 刷新视频上传凭证
* @param [type] $client [description]
* @param [type] $videoId [description]
* @return [type] [description]
*/
public function refresh_upload_video($videoId)
{
try {
$this->init_vod_client($this->accessVideoKeyId, $this->accessVideoKeySecret);
} catch (\Exception $e) {
print $e->getMessage();
exit();
}
$request = new vod\RefreshUploadVideoRequest();
$request->setVideoId($videoId);
$request->setAcceptFormat('JSON');
$res = $this->client->getAcsResponse($request);
return json($res);
}
/**
* @desc 初始化客户端
* @param [type] $accessKeyId [description]
* @param [type] $accessKeySecret [description]
* @return [type] [description]
*/
private function init_vod_client($accessKeyId, $accessKeySecret)
{
//初始化视频客户端
$profile = \DefaultProfile::getProfile($this->regionVideoId, $accessKeyId, $accessKeySecret);
$this->client = new \DefaultAcsClient($profile);
//初始化sts授权策略客户端
\DefaultProfile::addEndpoint($this->regionVideoId, $this->regionVideoId, "Sts", $this->endpointVideo);
$iClientProfile = \DefaultProfile::getProfile($this->regionVideoId, $accessKeyId, $accessKeySecret);
$this->stsVideo = new \DefaultAcsClient($iClientProfile);
}
}
html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>APP下载</title>
<script src="/assets/img/app/jquery-3.4.1.min.js" language="javascript"> </script>
<!-- <script src="/assets/libs/jquery/dist/jquery.min.js" language="javascript"> </script> -->
<script src="/assets/libs/aliyun-upload-sdk/aliyun-oss-sdk-6.0.2.min.js"></script>
<!-- <script src="http://gosspublic.alicdn.com/aliyun-oss-sdk-4.4.4.min.js"></script> -->
<!-- <script src="/assets/libs/layui/layui.js"></script> -->
<link rel="stylesheet" href="/assets/libs/layui/css/layui.css" media="all">
</head>
<body>
<div id="up_wrap"></div>
<div class="form-group">
<input type="file" id="file" multiple="multiple" />
</div>
<div class="msg" style="font-size:12px;color:red"></div>
<div class="form-group" style="margin-top:20px">
<!-- <input type="button" class="btn btn-primary" id="file-button" value="上传" /> -->
<!-- <input type="button" class="btn btn-primary" id="Continue-button" value="Continue" /> -->
</div>
<script type="text/javascript">
var appServer = 'auth/upload/alists';//获取ststoken的接口,这边这个地址是我本地的。你们的接口地址自己应该清楚
var bucket = 'xxxx';
var region = 'oss-cn-beijing';//前面新建bucket时选择过的。
var uid = 'client';//用户标识。这个根据自己情况自己定
var Buffer = OSS.Buffer;
//获取授权STSToken,并初始化client
var applyTokenDo = function (func) {
var url = appServer;
return $.get(url).then(function (result) {
var res = JSON.parse(result);
console.log(res);
if(res.Message){
$('.msg').text(res.Message);
return;
}
var creds = res.Credentials;
console.log(creds)
var client = new OSS({
region: region,
stsToken: creds.securityToken,
secure:true,
accessKeyId: creds.AccessKeyId,
accessKeySecret: creds.AccessKeySecret,
stsToken: creds.SecurityToken,
bucket: bucket
});
return func(client);
});
};
//上传文件
var uploadFile = function (client) {
if (upfiles.length < 1)
return;
upfile = upfiles[0];
var file = upfile.file;
// console.log(file)
var size = file.size;
var type = file.type;
// console.log(upfile.name.split('.').splice(-1))
var date = new Date();
var month = date.getMonth()+1;
var month = month < 10 ? '0' + month: month;
var pathName = date.getFullYear()+''+month+''+date .getDate();
var timestamp = (new Date()).valueOf();
// console.log(pathName)
// console.log(timestamp)
//key可以自定义为文件名(例如file.txt)或目录(例如abc/test/file.txt)的形式,实现将文件上传至当前Bucket或Bucket下的指定目录。
// var key = upfile.name;
var fielName = upfile.name.split('.').splice(-1)
var key = 'uploads/'+pathName+'/'+timestamp+'.'+fielName[0];
// console.log(key)
var objkey = key + "_" + uid + ".json";
// console.log(client)
return client.multipartUpload(key, file, {
progress: function (p, cpt, res) {
// console.log("p:", p);
// console.log("cpt:", cpt);
// console.log("res:", res);
if (cpt != undefined) {
var content = JSON.stringify(cpt);
client.put(objkey, new Buffer(content));
}
if(Math.floor(p * 100)==100){
var filePathUrl = "https://xxxxxx.oss-cn-beijing.aliyuncs.com/"+key;
Fast.api.ajax({
url:"auth/upload",
data:{fileurl:filePathUrl,filename:upfile.name,filesize:size,mimetype:type,imagetype:fielName[0]}
}, function(){
//成功的回调
Fast.api.close(filePathUrl)
console.log(111)
}, function(){
//失败的回调
console.log(222)
});
}
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);
});
};
//断点续传文件
var reUploadFile = function (client) {
if (upfiles.length < 1)
return;
upfile = upfiles[0];
var file = upfile.file;
//key可以自定义为文件名(例如file.txt)或目录(例如abc/test/file.txt)的形式,实现将文件上传至当前Bucket或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") { //手动点击暂停上传
return;
}
break;
case -1: //请求错误,自动重新上传
// 重新上传;
return;
case 203: //回调失败
// 前端自己给后台回调;
return;
case 400:
switch (err.code) {
case 'FilePartInterity': //文件Part已改变
case 'FilePartNotExist': //文件Part不存在
case 'FilePartState': //文件Part过时
case 'InvalidPart': //无效的Part
case 'InvalidPartOrder': //无效的part顺序
case 'InvalidArgument': //参数格式错误
// 清空断点;
// 重新上传;
return;
case 'InvalidBucketName': //无效的Bucket名字
case 'InvalidDigest': //无效的摘要
case 'InvalidEncryptionAlgorithmError': //指定的熵编码加密算法错误
case 'InvalidObjectName': //无效的Object名字
case 'InvalidPolicyDocument': //无效的Policy文档
case 'InvalidTargetBucketForLogging': //Logging操作中有无效的目标bucket
case 'MalformedXML': //XML格式非法
case 'RequestIsNotMultiPartContent': //Post请求content-type非法
// 重新授权;
// 继续上传;
return;
case 'RequestTimeout'://请求超时
// 重新上传;
return;
}
break;
case 403: //授权无效,重新授权
case 411: //缺少参数
case 404: //Bucket/Object/Multipart Upload ID 不存在
// 重新授权;
// 继续上传;
return;
case 500: //OSS内部发生错误
// 重新上传;
return;
default:
break;
}
}
//文件上传队列
var upfiles = [];
var upfiles1 = [];
$(function () {
//初始化文件上传队列
$("#file").change(function (e) {
var ufiles = $(this).prop('files');
// console.log(ufiles[0])
var upfiles1 = ufiles[0];
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);
applyTokenDo(uploadFile);
$("#up_wrap").html(htm);
});
//上传
$("#file-button").click(function () {
applyTokenDo(uploadFile);
});
//续传
$("#Continue-button").click(function () {
applyTokenDo(reUploadFile);
})
})
</script>
</body>
</html>
js
define(['jquery', 'bootstrap', 'backend', 'table', 'form','/assets/libs/layui/layui.js'], function ($, undefined, Backend, Table, Form,Layui) {
var Controller = {
index: function () {
// 初始化表格参数配置
layui.use('element', function(){
var $ = layui.jquery
,element = layui.element; //Tab的切换功能,切换事件监听等,需要依赖element模块
//触发事件
var active = {
setPercent: function(){
//设置50%进度
element.progress('demo', '50%')
}
,loading: function(othis){
var DISABLED = 'layui-btn-disabled';
if(othis.hasClass(DISABLED)) return;
//模拟loading
var n = 0, timer = setInterval(function(){
n = n + Math.random()*10|0;
if(n>100){
n = 100;
clearInterval(timer);
othis.removeClass(DISABLED);
}
element.progress('demo', n+'%');
}, 300+Math.random()*1000);
othis.addClass(DISABLED);
}
};
$('.site-demo-active').on('click', function(){
var othis = $(this), type = $(this).data('type');
active[type] ? active[type].call(this, othis) : '';
});
});
},
};
return Controller;
});
如果出现Roles may not be assumed by root accounts.报错则需要创建RAM用户


把创建好的AccessKey填到protected $accessKeyId='xxxxx';
protected $accessKeySecret = 'xxxx';
配置好以后报You are not authorized to do this action. You should be authorized by RAM.的错误需要配置AliyunSTSAssumeRoleAccess 权限
还需要添加跨越
如果文件为私有访问权限,需要单独对访问的文件设置
$config = config('oss');
$bucket = $config['bucket']; //oss中的文件上传空间
try {
$ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret,$this->endpointVideo);
// 设置签名URL的有效期为 3600 秒 (1小时)
$timeout = 3600;
// 生成签名URL
$signedUrl =$ossClient->signUrl($bucket,'uploads/20260313/1773389096488.mp4', $timeout);
echo "签名URL: " . $signedUrl;
} catch (OssException $e) {
printf(__FUNCTION__ . ": FAILED\n");
printf($e->getMessage() . "\n");
return;
}