如何将图片视频上传至阿里云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'])) : '';
        $duration = isset($_POST['duration']) ? intval($_POST['duration']) : 0;
        $uid = $this->uid;
        $usertype = $this->usertype;
        if(!$uid){
            return jsonErr('请先登录');
        }

        if(empty($usertype)){
            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));
            }
            if($duration > 60){
                return jsonErr("视频时长过长,建议60秒以内");
            }

        } 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']);
        }
    }

临时签名上传

###
前端代码
###

<script src="https://gosspublic.alicdn.com/aliyun-oss-sdk-6.20.0.min.js"></script>

<div class="drawerModLis">
                    <div class="drawerModTite">
                        <span>视频封面</span>
                    </div>
                    <div class="drawerModInpt">
                        <el-upload
                                class="upload-demo"
                                action=""
                                :on-change="handleImageChange"
                                :file-list="imageList"
                                :auto-upload="false">
                            <el-button slot="trigger" size="small" type="primary">选取图片</el-button>
                        </el-upload>
                    </div>
                    <div class="drawerModTips">
                        <div v-if="info.image">
                            <el-link type="primary" :href="info.image" target="_blank">查看封面</el-link>
                        </div>
                    </div>
                </div>
                <div class="drawerModLis">
                    <div class="drawerModTite">
                        <span>视频文件</span>
                    </div>
                    <div class="drawerModInpt">
                        <el-upload
                                class="upload-demo"
                                action=""
                                :on-change="handleVideoChange"
                                :file-list="videoList"
                                :auto-upload="false">
                            <el-button slot="trigger" size="small" type="primary">选取视频</el-button>
                        </el-upload>
                    </div>
                    <div class="drawerModTips">
                        <div v-if="info.video">
                            <el-link type="primary" :href="info.video" target="_blank">查看视频</el-link>
                        </div>
                    </div>
                </div>

async saveOss(){
                let _this = this;
                const formData = new FormData();
                let params = _this.info;
                let baseUrl = localStorage.getItem("baseUrl") + '?';
                Object.keys(params).forEach((key) => {
                    formData.append(key, params[key]);
                });
                if (_this.imageList.length > 0 || _this.videoList.length > 0) {
                    const response = await fetch(baseUrl + 'c=shipin&a=getsts', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify({uid: _this.info.uid, usertype: _this.info.usertype})
                    });
                    if (!response.ok) {
                        message.error("获取临时凭证失败");
                        return false;
                    }
                    const res = await response.json();

                    if (res.error == 0) {
                        const client = new OSS({
                            bucket: res.data.Bucket,
                            region: res.data.Region,
                            accessKeyId: res.data.AccessKeyId,
                            accessKeySecret: res.data.AccessKeySecret,
                            stsToken: res.data.SecurityToken,
                        });
                        if(_this.imageList.length > 0){
                            const uid = _this.info.uid;
                            const time = _this.getNowTime();
                            const ext =  _this.getFileExt(_this.imageList[0].name);
                            const object = `${uid}/${time}.${ext}`;
                            try {
                                await client.put(object, _this.imageList[0].raw);
                                formData.append('imageFile', res.data.Host + '/' + object);
                            } catch (e) {
                                message.error(e);
                                return false;
                            }
                        }
                        if(_this.videoList.length > 0){
                            startLoading()
                            const uid = _this.info.uid;
                            const time = _this.getNowTime();
                            const ext =  _this.getFileExt(_this.videoList[0].name);
                            const object = `${uid}/${time}.${ext}`;
                            try {
                                await client.put(object, _this.videoList[0].raw);
                                formData.append('videoFile', res.data.Host + '/' + object);
                                endLoading()
                            } catch (e) {
                                message.error(e);
                                return false;
                            }
                        }
                    } else {
                        message.error(res.msg);
                        return false;
                    }
                }

                httpPost('c=shipin&a=add', formData).then(function (result) {
                    var res = result.data
                    if (res.error == 0) {
                        message.success(res.msg, function () {
                            _this.getList();
                            _this.draweradd = false;
                            _this.imageList = [];
                            _this.videoList = [];
                        })
                    } else {
                        message.error(res.msg);
                    }

                }).catch(function (e) {
                    console.log(e)
                })
            },

###
后端代码
###
public function getsts_action()
    {

        // 获取原始的 POST 数据(适用于 application/json)
        $data = json_decode(file_get_contents('php://input'), true);
        $uid = isset($data['uid']) ? intval($data['uid']) : 0;
        $usertype = isset($data['usertype']) ? intval($data['usertype']) : 0;

        $ossModel = $this->MODEL('alioss');
        $res = $ossModel->getSTS();
        if($res['code'] === true){
            $this->render_json(0, '', $res['msg']);
        }else{
            $this->render_json(1, $res['msg']);
        }
    }

阿里云代码

<?php

//ini_set('display_errors', 1);
//ini_set('display_startup_errors', 1);
//error_reporting(E_ALL);


require_once __DIR__ . '/aliyunsdk/vendor/autoload.php';

use OSS\Credentials\StaticCredentialsProvider;
use OSS\OssClient;
use OSS\Core\OssException;
use OSS\Http\RequestCore;
use OSS\Http\ResponseCore;

use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use AlibabaCloud\Sts\Sts;

class alioss
{
    protected $accessKeyId;
    protected $accessKeySecret;
    protected $provider;
    protected $endpoint;
    protected $bucket;
    protected $config;
    protected $ossClient;
    protected $options;
    protected $host;
    protected $region;
    protected $ramArn;

    public function __construct()
    {
        $this->accessKeyId = "";
        $this->accessKeySecret = "";
        $this->provider = new StaticCredentialsProvider($this->accessKeyId, $this->accessKeySecret);
        $this->endpoint = "";
        $this->bucket = "";
        $this->host = "";
        $this->region = "";
        $this->ramArn = "";
        $this->config = array(
            "provider" => $this->provider,
            "endpoint" => $this->endpoint,
            "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
            "region"=> $this->region
        );
        $this->options = array(
            OssClient::OSS_HEADERS => array(
                OssClient::OSS_ACL => "public-read"
            )
        );
        $this->ossClient = new OssClient($this->config);
    }

    public function uploadFile($object, $filePath){
        try {
            $this->ossClient->uploadFile($this->bucket, $object, $filePath, $this->options);
            return array(
                'code' => true,
                'msg' => $this->host . '/' . $object
            );
        } catch (OssException $e) {
            return array(
                'code' => false,
                'msg' => $e->getMessage()
            );
        }
    }

    public function multiuploadFile($object, $filePath){
        try {
            $options = array(
                OssClient::OSS_CHECK_MD5 => true,
                OssClient::OSS_PART_SIZE => 5,
                OssClient::OSS_HEADERS => array(
                    OssClient::OSS_ACL => "public-read"
                )
            );
            $this->ossClient->multiuploadFile($this->bucket, $object, $filePath, $options);
            return array(
                'code' => true,
                'msg' => $this->host . '/' . $object
            );
        } catch (OssException $e) {
            return array(
                'code' => false,
                'msg' => $e->getMessage()
            );
        }
    }

    public function deleteFile($object){
        try {
            $this->ossClient->deleteObject($this->bucket, $object);
            return array(
                'code' => true,
                'msg' => ''
            );
        } catch (OssException $e) {
            return array(
                'code' => false,
                'msg' => $e->getMessage()
            );
        }
    }

    public function getUploadFileSignUrl($uid, $extname)
    {
        $contentType = $this->getMimeType($extname);
        $time = time();
        $object = "${uid}/${time}.${extname}";

        try {
            $ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint, false);
            // 生成签名URL。
            $signedUrl = $ossClient->signUrl($this->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()
            );
        }
    }

    public 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];
    }

    public function getSTS()
    {
        // 初始化阿里云客户端。
        AlibabaCloud::accessKeyClient($this->accessKeyId, $this->accessKeySecret)
            ->regionId($this->region)
            ->asDefaultClient();

        try {
            // 创建STS请求。
            $result = Sts::v20150401()
                ->assumeRole()
                // 设置角色ARN。
                ->withRoleArn($this->ramArn)
                // 指定自定义角色会话名称,用来区分不同的令牌。
                ->withRoleSessionName('userUpload')
                // 指定STS临时访问凭证过期时间为3600秒。
                ->withDurationSeconds(900)
                ->request();

            // 获取响应中的凭证信息。
            $credentials = $result['Credentials'];

            return array(
                'code' => true,
                'msg' => array(
                    'AccessKeyId' => $credentials['AccessKeyId'],
                    'AccessKeySecret' => $credentials['AccessKeySecret'],
                    'SecurityToken' => $credentials['SecurityToken'],
                    'Expiration' => $credentials['Expiration'],
                    'Bucket' => $this->bucket,
                    'Region' => 'oss-' . $this->region,
                    'Host' => $this->host
                )
            );
        } catch (ClientException $e) {
            return array(
                'code' => false,
                'msg' => $e->getErrorMessage()
            );
        } catch (ServerException $e) {
            return array(
                'code' => false,
                'msg' => $e->getErrorMessage()
            );
        }
    }

    public function handleUrl($endpoint, $bucket, $object){
        if(filter_var($endpoint, FILTER_VALIDATE_URL)){
            $arr = parse_url($endpoint);
            $scheme = $arr['scheme'];
            $host = $arr['host'];
            $url = $scheme . '://' . $bucket . '.' . $host . '/' . $object;
            return $url;
        }
    }

    public function handlePath($url){
        $parsedUrl = parse_url($url);
        $path = isset($parsedUrl['path']) ? $parsedUrl['path'] : '';

        if ($path !== '' && $path[0] === '/') {
            // 如果路径以斜杠开始,则移除它
            $trimmedPath = substr($path, 1);
        } else {
            // 否则保持原样
            $trimmedPath = $path;
        }

        return $trimmedPath;

    }

}

,