控制器
/**
* 阿里OSS后臺簽名并進行上傳回調(diào)
* Class UploadController
* @package App\Http\Controllers
*/
class UploadController extends Controller
{
/**
* 返回OSS的簽名驗證
* @return JSON 簽名信息
*/
public function getGetkey(Request $request)
{
//初始化一下必要的請求數(shù)據(jù)
$id = env('ACCESSKEYID'); //AccessKeyId
$key = env('ACCESSKEYSECRET'); //AccessKeySecret
$host = 'http://outside-leader.oss-cn-qingdao.aliyuncs.com'; //OSS庫地址
$callbackUrl = url('upload/callback'); //上傳回調(diào)的地址
//上傳回調(diào)的參數(shù),callbackUrl地址,callbackBody回調(diào)接收的參數(shù),callbackBodyType通過POST調(diào)用的回調(diào)函數(shù),所以要設(shè)置這個頭
$callback_param = array(
'callbackUrl' => $callbackUrl,
'callbackBody' => 'filename=${object}&size=${size}&mimeType =${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
'callbackBodyType' => "application/x-www-form-urlencoded"
);
$callback_string = json_encode($callback_param); //轉(zhuǎn)換成json格式
$base64_callback_body = base64_encode($callback_string); //要返回的回調(diào)函數(shù)參數(shù)信息
//設(shè)置過期時間
$now = time();
$expire = 30; //設(shè)置該policy超時時間是30s. 即這個policy過了這個有效時間泥从,將不能訪問
$end = $now + $expire;
$expiration = $this->gmt_iso8601($end); //進行時間格式的轉(zhuǎn)換
$dir = $request['dir']; //上傳目錄設(shè)置
//處理上傳限制條件
//最大文件大小.用戶可以自己設(shè)置
$condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
$conditions[] = $condition; //設(shè)定文件大小
//表示用戶上傳的數(shù)據(jù),必須是以$dir開始, 不然上傳會失敗,這一步不是必須項,只是為了安全起見,防止用戶通過policy上傳到別人的目錄
$start = array(0 => 'starts-with', 1 => '$key', 2 => $dir);
$conditions[] = $start; //必須以設(shè)定的目錄開頭,防止上傳錯誤
$arr = array('expiration' => $expiration, 'conditions' => $conditions);
$policy = json_encode($arr);
$base64_policy = base64_encode($policy); //要返回的上傳限制參數(shù)
//簽名信息
$string_to_sign = $base64_policy;
$signature = base64_encode(hash_hmac('sha1', $string_to_sign, $key, true)); //要返回的簽名信息
//設(shè)置返回信息
$response = array(
'accessid' => $id, //accessid
'host' => $host, //上傳地址
'policy' => $base64_policy, //上傳文件限制
'signature' => $signature, //簽名信息
'expire' => $end, //失效時間
'callback' => $base64_callback_body, //上傳回調(diào)參數(shù)
'dir' => $dir //上傳的目錄
);
return response()->json($response); //返回信息
}
//格式化時間,格式為2016-07-07T23:48:43Z
function gmt_iso8601($time)
{
$dtStr = date("c", $time);
$pos = strpos($dtStr, '+');
$expiration = substr($dtStr, 0, $pos);
return $expiration . "Z";
}
//測試用的回調(diào)函數(shù)
public function postCallback(Request $request)
{
// 1.獲取OSS的簽名header和公鑰url header
$authorizationBase64 = "";
$pubKeyUrlBase64 = "";
if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
$authorizationBase64 = $_SERVER['HTTP_AUTHORIZATION'];
}
if (isset($_SERVER['HTTP_X_OSS_PUB_KEY_URL'])) {
$pubKeyUrlBase64 = $_SERVER['HTTP_X_OSS_PUB_KEY_URL'];
}
if ($authorizationBase64 == '' || $pubKeyUrlBase64 == '') {
header("http/1.1 403 Forbidden");
exit();
}
// 2.獲取OSS的簽名
$authorization = base64_decode($authorizationBase64); //OSS簽名
// 3.獲取公鑰
$pubKeyUrl = base64_decode($pubKeyUrlBase64); //公鑰的URL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $pubKeyUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
$pubKey = curl_exec($ch);
if ($pubKey == "") {
exit(); //header("http/1.1 403 Forbidden");
}
// 4.獲取回調(diào)body,上傳的圖片的相關(guān)信息都在這里
$body = file_get_contents('php://input');
// 5.拼接待簽名字符串
$authStr = '';
$path = $_SERVER['REQUEST_URI'];
$pos = strpos($path, '?');
if ($pos === false) {
$authStr = urldecode($path) . "\n" . $body;
} else {
$authStr = urldecode(substr($path, 0, $pos)) . substr($path, $pos, strlen($path) - $pos) . "\n" . $body;
}
// 6.驗證簽名
$ok = openssl_verify($authStr, $authorization, $pubKey, OPENSSL_ALGO_MD5);
if ($ok == 1) {
header("Content-Type: application/json");
$data = array("Status" => "Ok");
return response()->json($data);
} else {
exit(); //header("http/1.1 403 Forbidden");
}
}
}
前臺html
<!DOCTYPE html>
<html>
<head>
<title>阿里OSS</title>
<meta charset="utf-8"/>
</head>
<body>
<form name=theform>
<input type="radio" name="myradio" value="local_name" checked=true/> 上傳文件名字保持本地文件名字
<input type="radio" name="myradio" value="random_name"/> 上傳文件名字是隨機文件名, 后綴保留
</form>
<h4>您所選擇的文件列表:</h4>
<div id="ossfile">你的瀏覽器不支持flash,Silverlight或者HTML5杨拐!</div>
<br/>
<div id="container">
<a id="selectfiles" href="javascript:void(0);" class='btn'>選擇文件</a>
<a id="postfiles" href="javascript:void(0);" class='btn'>開始上傳</a>
</div>
<pre id="console"></pre>
<p> </p>
<script type="text/javascript" src="{{ asset('assets/plupload/js/plupload.full.min.js') }}"></script>
<script>
var expire = 0; //初始化過期時間
/**
* 發(fā)送ajax請求的函數(shù)
* @returns Json 服務(wù)器返回的簽名
*/
function send_request() {
var xmlhttp = null;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
if (xmlhttp != null) {
var serverUrl = '{{ url('upload/key?dir=') }}';
xmlhttp.open("GET", serverUrl, false);
xmlhttp.send(null);
return xmlhttp.responseText;
} else {
alert("Your browser does not support XMLHTTP.");
}
}
/**
* 選擇服務(wù)器端保存文件名的方式
*/
function check_object_radio() {
var tt = document.getElementsByName('myradio');
for (var i = 0; i < tt.length; i++) {
if (tt[i].checked) {
g_object_name_type = tt[i].value;
break;
}
}
}
/**
* 從服務(wù)器獲取簽名之后,定義全局變量
* @returns {boolean}
*/
function get_signature() {
//可以判斷當前expire是否超過了當前時間,如果超過了當前時間,就重新取一下.3s 做為緩沖
now = timestamp = Date.parse(new Date()) / 1000;
if (expire < now + 3) {
body = send_request(); //發(fā)送ajax請求
var obj = eval("(" + body + ")");
//定義全局變量,值為服務(wù)器返回來的值
host = obj['host'];
policyBase64 = obj['policy'];
accessid = obj['accessid'];
signature = obj['signature'];
expire = parseInt(obj['expire']);
callbackbody = obj['callback'];
key = obj['dir'];
return true;
}
return false;
}
/**
* 生成隨機文件名,不一定能唯一
* @param len 名字的長度
* @returns {string}
*/
function random_string(len) {
len = len || 32;
var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
var maxPos = chars.length;
var pwd = '';
for (i = 0; i < len; i++) {
pwd += chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
}
/**
*
* @param filename
* @returns {string}
*/
function get_suffix(filename) {
pos = filename.lastIndexOf('.');
suffix = '';
if (pos != -1) {
suffix = filename.substring(pos)
}
return suffix;
}
/**
* 根據(jù)選擇文件名的方式處理文件名
* @param filename
* @returns {string}
*/
function calculate_object_name(filename) {
if (g_object_name_type == 'local_name') {
g_object_name += "${filename}"
}
else if (g_object_name_type == 'random_name') {
suffix = get_suffix(filename);
g_object_name = key + random_string(10) + suffix
}
return '';
}
//獲取上傳文件的名字
function get_uploaded_object_name(filename) {
if (g_object_name_type == 'local_name') {
tmp_name = g_object_name;
tmp_name = tmp_name.replace("${filename}", filename);
return tmp_name;
}
else if (g_object_name_type == 'random_name') {
return g_object_name;
}
}
//設(shè)置文件上傳到OSS需要的參數(shù)
function set_upload_param(up, filename, ret) {
if (ret == false) { //如果沒有簽名,去請求請求簽名
ret = get_signature()
}
g_object_name = key; //
if (filename != '') {
suffix = get_suffix(filename);
calculate_object_name(filename)
}
new_multipart_params = {
'key': g_object_name,
'policy': policyBase64,
'OSSAccessKeyId': accessid,
'success_action_status': '200', //讓服務(wù)端返回200,不然奕筐,默認會返回204
'callback': callbackbody,
'signature': signature
};
up.setOption({
'url': host,
'multipart_params': new_multipart_params
});
up.start();
}
//文件上傳對象
var uploader = new plupload.Uploader({
runtimes: 'html5,flash,silverlight,html4', //設(shè)置支持上傳的協(xié)議
browse_button: 'selectfiles',
//multi_selection: false, //是否允許多文件上傳
container: document.getElementById('container'),
flash_swf_url: '{{ asset('plupload/js/Moxie.swf') }}',
silverlight_xap_url: '{{ asset('plupload/js/Moxie.xap') }}',
url: 'http://oss.aliyuncs.com',
//文件過濾規(guī)則
filters: {
mime_types: [ //只允許上傳圖片和zip文件
{title: "Image files", extensions: "jpg,gif,png,bmp"},
{title: "Zip files", extensions: "zip,rar"}
],
max_file_size: '3mb', //最大只能上傳3mb的文件
prevent_duplicates: true //不允許選取重復文件
},
//執(zhí)行上傳的對象
init: {
//一初始化就執(zhí)行的函數(shù)
PostInit: function () {
document.getElementById('ossfile').innerHTML = '';
document.getElementById('postfiles').onclick = function () {
set_upload_param(uploader, '', false);
return false;
};
},
//一選擇文件就執(zhí)行的函數(shù)
FilesAdded: function (up, files) {
plupload.each(files, function (file) {
document.getElementById('ossfile').innerHTML += '<div id="' + file.id + '">' + file.name + ' (' + plupload.formatSize(file.size) + ')<b></b>'
+ '<div class="progress"><div class="progress-bar" style="width: 0%"></div></div>'
+ '</div>';
});
},
//上傳之前執(zhí)行的函數(shù)
BeforeUpload: function (up, file) {
check_object_radio(); //選擇文件名
set_upload_param(up, file.name, true); //設(shè)置上傳參數(shù)
},
//上傳進度條
UploadProgress: function (up, file) {
var d = document.getElementById(file.id);
d.getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
var prog = d.getElementsByTagName('div')[0];
var progBar = prog.getElementsByTagName('div')[0]
progBar.style.width = 2 * file.percent + 'px';
progBar.setAttribute('aria-valuenow', file.percent);
},
//執(zhí)行文件上傳
FileUploaded: function (up, file, info) {
if (info.status == 200) {
document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = 'upload to oss success, object name:' + get_uploaded_object_name(file.name) + ' 回調(diào)服務(wù)器返回的內(nèi)容是:' + info.response;
}
else if (info.status == 203) {
document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '上傳到OSS成功,但是oss訪問用戶設(shè)置的上傳回調(diào)服務(wù)器失敗渊胸,失敗原因是:' + info.response;
}
else {
document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = info.response;
}
},
//報錯信息
Error: function (up, err) {
if (err.code == -600) {
document.getElementById('console').appendChild(document.createTextNode("\n選擇的文件太大了,可以根據(jù)應(yīng)用情況,在upload.js 設(shè)置一下上傳的最大大小"));
}
else if (err.code == -601) {
document.getElementById('console').appendChild(document.createTextNode("\n選擇的文件后綴不對,可以根據(jù)應(yīng)用情況接剩,在upload.js進行設(shè)置可允許的上傳文件類型"));
}
else if (err.code == -602) {
document.getElementById('console').appendChild(document.createTextNode("\n這個文件已經(jīng)上傳過一遍了"));
}
else {
document.getElementById('console').appendChild(document.createTextNode("\nError xml:" + err.response));
}
}
}
});
uploader.init();
</script>
</body>
</html>
/