如何将图片视频上传至阿里云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];
}

,