如何将图片视频上传至阿里云OSS服务器实例
####
前端代码
####
<uni-section title="图片" type="line">
<view style="padding: 0 20rpx;">
<uni-file-picker v-model="imageFile" mode="list" ref="image" limit="1" file-mediatype="image" :auto-upload="false" @select="selectImage">
<button class="mini-btn" type="primary" size="mini">选择图片</button>
</uni-file-picker>
</view>
</uni-section>
<uni-section title="视频" type="line">
<view style="padding: 0 20rpx;">
<uni-file-picker v-model="videoFile" ref="video" limit="1" file-mediatype="video" :auto-upload="false" @select="selectVideo">
<button class="mini-btn" type="primary" size="mini">选择视频</button>
</uni-file-picker>
</view>
</uni-section>
<script setup>
const image= ref()
const imageObject = reactive({
extname: "",
size: "",
fileType: ""
})
const imageFile = ref()
const imageSrc = ref()
const video = ref()
const videoObject = reactive({
extname: "",
size: "",
fileType: ""
})
const videoFile = ref()
const videoSrc = ref()
const selectImage = (e) => {
image.value = e.tempFilePaths[0]
imageObject.extname = e.tempFiles[0].extname
imageObject.size = e.tempFiles[0].size
imageObject.fileType = e.tempFiles[0].fileType
}
const selectVideo = (e) => {
video.value = e.tempFilePaths[0]
videoObject.extname = e.tempFiles[0].extname
videoObject.size = e.tempFiles[0].size
videoObject.fileType = e.tempFiles[0].fileType
}
const uploadImageToOss = async () => {
if(!image.value){
uni.showToast({
title: "请选择图片",
icon: "none"
})
return false
}
let res = await apiGetSignUrl({extname: imageObject.extname, size: imageObject.size, fileType: imageObject.fileType})
if(res.errcode != 9){
uni.showToast({
title: res.msg,
icon: "none"
})
return false;
}
try {
// 读取文件为 ArrayBuffer
const buffer = await getArrayBufferFromFile(image.value);
// 发起 PUT 请求上传文件
const result = await uni.request({
url: res.data.signUrl,
method: 'PUT',
header: {
'Content-Type': res.data.contentType
},
dataType: 'arraybuffer', // 必须指定为 arraybuffer
data: buffer
});
imageSrc.value = res.data.url;
return true;
} catch (e) {
uni.showToast({
title: e,
icon: "none"
})
return false;
}
}
const uploadVideoToOss = async () => {
if(!video.value){
uni.showToast({
title: "请选择视频",
icon: "none"
})
return false
}
uni.showLoading({
title: '上传视频中...',
mask: true
})
try{
let res = await apiGetSignUrl({extname: videoObject.extname, size: videoObject.size, fileType: videoObject.fileType})
if(res.errcode == 9){
// 读取文件为 ArrayBuffer
const buffer = await getArrayBufferFromFile(video.value);
// 发起 PUT 请求上传文件
const result = await uni.request({
url: res.data.signUrl,
method: 'PUT',
header: {
'Content-Type': res.data.contentType
},
dataType: 'arraybuffer', // 必须指定为 arraybuffer
data: buffer
});
videoSrc.value = res.data.url;
return true;
}else{
uni.showToast({
title: res.msg,
icon: "none"
})
return false;
}
}catch(e){
uni.showToast({
title: e,
icon: "none"
})
return false;
}finally{
uni.hideLoading()
}
}
</script>
// 获取文件的 ArrayBuffer
export function getArrayBufferFromFile(filePath) {
return new Promise((resolve, reject) => {
// #ifdef APP-VUE || MP-WEIXIN || MP-ALIPAY
// 小程序 / App 使用 uni.getFileSystemManager()
try {
const fs = uni.getFileSystemManager();
fs.readFile({
filePath: filePath,
success: res => {
resolve(res.data); // ArrayBuffer
},
fail: err => {
reject(err);
}
});
} catch (e) {
reject(e);
}
// #endif
// #ifdef H5
// H5 平台使用 fetch + blob + arrayBuffer
fetch(filePath)
.then(response => {
if (!response.ok) throw new Error("HTTP 请求失败");
return response.arrayBuffer();
})
.then(buffer => {
resolve(buffer);
})
.catch(err => {
reject(err);
});
// #endif
});
}
####
后端代码
####
function getsignurl_action()
{
$extname = isset($_POST['extname']) ? strtolower(strval($_POST['extname'])) : '';
$size = isset($_POST['size']) ? intval($_POST['size']) : 0;
$fileType = isset($_POST['fileType']) ? strtolower(strval($_POST['fileType'])) : '';
$uid = '';
if(!$uid){
return jsonErr('请先登录');
}
if($fileType === 'image'){
$allowedTypes = ['jpg', 'jpeg', 'png', 'gif'];
if (!in_array($extname, $allowedTypes)) {
return jsonErr("不允许的文件类型. 允许的类型为: " . implode(", ", $allowedTypes));
}
$maxSize = 2000000;
if ($size > $maxSize) {
return jsonErr("文件过大. 最大允许大小为: " . ($maxSize / 1000000) . "MB");
}
} elseif ($fileType === 'video'){
$allowedTypes = ['mp4', 'avi', 'mov', 'mkv', 'flv', 'webm'];
if (!in_array($extname, $allowedTypes)) {
return jsonErr("不允许的文件类型. 允许的类型为: " . implode(", ", $allowedTypes));
}
$maxSize = 50000000;
if ($size > $maxSize) {
return jsonErr("文件过大. 最大允许大小为: " . ($maxSize / 1000000) . "MB");
}
} else{
return jsonErr('格式错误');
}
$ossModel = $this->MODEL('alioss');
$res = $ossModel->getUploadFileSignUrl($uid, $extname);
if($res['code'] === true){
return jsonSuc($res['msg']);
}else{
return jsonErr($res['msg']);
}
}
function getUploadFileSignUrl($uid, $extname)
{
$contentType = $this->getMimeType($extname);
$time = time();
$object = "${uid}/${time}.${extname}";
try {
$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, false);
// 生成签名URL。
$signedUrl = $ossClient->signUrl($bucket, $object, $timeout = 3600, "PUT", array('Content-Type' => $contentType));
return array(
'code' => true,
'msg' => array(
'contentType' => $contentType,
'url' => $this->host . '/' . $object,
'signUrl' => $signedUrl
)
);
} catch (OssException $e) {
return array(
'code' => false,
'msg' => $e->getMessage()
);
}
}
function getMimeType($ext)
{
$types = [
// 图片
'png' => 'image/png',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'webp' => 'image/webp',
'svg' => 'image/svg+xml',
// 视频
'mp4' => 'video/mp4',
'avi' => 'video/x-msvideo',
'mov' => 'video/quicktime',
'webm' => 'video/webm',
'mkv' => 'video/x-matroska',
'flv' => 'video/x-flv',
];
return $types[$ext];
}