thinkphp8.0上传图片到阿里云对象存储(oss)

发布于:2025-04-06 ⋅ 阅读:(11) ⋅ 点赞:(0)

1、开通oss,并获取accessKeyId、accessKeySecret

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>服务端生成签名上传文件到OSS</title>
</head>
<body>
<div class="container">
    <form>
        <div class="mb-3">
            <label for="file" class="form-label">选择文件:</label>
            <input type="file" class="form-control" id="file" name="file" required />
        </div>
        <button type="submit" class="btn btn-primary">上传</button>
    </form>
</div>

<script type="text/javascript">
    document.addEventListener('DOMContentLoaded', function () {
        const form = document.querySelector("form");
        const fileInput = document.querySelector("#file");

        form.addEventListener("submit", (event) => {
            event.preventDefault();

            const file = fileInput.files[0];

            if (!file) {
                alert('请选择一个文件再上传。');
                return;
            }

            const filename = file.name;

            fetch("/index/demo/index/", { method: "GET" })
                .then((response) => {
                    if (!response.ok) {
                        throw new Error("获取签名失败");
                    }
                    return response.json();
                })
                .then((data) => {
                    let formData = new FormData();
                    formData.append("success_action_status", "200");
                    formData.append("policy", data.policy);
                    formData.append("x-oss-signature", data.signature);
                    formData.append("x-oss-signature-version", "OSS4-HMAC-SHA256");
                    formData.append("x-oss-credential", data.x_oss_credential);
                    formData.append("x-oss-date", data.x_oss_date);
                    formData.append("key", data.dir + file.name); // 文件名
                    formData.append("x-oss-security-token", data.security_token);
                    formData.append("file", file); // file 必须为最后一个表单域

                    return fetch(data.host, {
                        method: "POST",
                        body: formData
                    });
                })
                .then((response) => {
                    if (response.ok) {
                        console.log("上传成功");
                        alert("文件已上传");
                    } else {
                        console.log("上传失败", response);
                        alert("上传失败,请稍后再试");
                    }
                })
                .catch((error) => {
                    console.error("发生错误:", error);
                });
        });
    });
</script>
</body>
</html>

2、后端php8.3\thinkphp8.1

composer require alibabacloud/oss-v2
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Sts\Sts;
use think\response\Json;

class Demo
{
    private function hmacsha256($key, $data): string
    {
        return hash_hmac('sha256', $data, $key, true);
    }
    public function index(): Json
    {
        $bucket = 'mj-quwei'; // 替换为您的Bucket名称
        $region_id = 'cn-shanghai'; // 替换为您的Bucket所在地域
        $host = 'https://mj-quwei.oss-cn-shanghai.aliyuncs.com'; // 替换为您的Bucket域名
        $expire_time = 3600; // 过期时间,单位为秒
        $upload_dir = 'demo'; // 上传文件的前缀
        AlibabaCloud::accessKeyClient('你的accessKeyId','你的accessKeySecret')
            ->regionId('cn-shanghai')
            ->asDefaultClient();
        // 创建STS请求。
        $request = Sts::v20150401()->assumeRole();
        // 发起STS请求并获取结果。
        // 将<YOUR_ROLE_SESSION_NAME>设置为自定义的会话名称,例如oss-role-session。
        // 将<YOUR_ROLE_ARN>替换为拥有上传文件到指定OSS Bucket权限的RAM角色的ARN。
        $result = $request
            ->withRoleSessionName('oss-role-session')
            ->withDurationSeconds(3600)
            ->withRoleArn('acs:ram::1241287589505885:role/oss-web-upload')
            ->request();
        // 获取STS请求结果中的凭证信息。
        $tokenData = $result->get('Credentials');
        // 构建返回的JSON数据。
        $tempAccessKeyId = $tokenData['AccessKeyId'];
        $tempAccessKeySecret = $tokenData['AccessKeySecret'];
        $securityToken = $tokenData['SecurityToken'];

        $now = time();
        $dtObj = gmdate('Ymd\THis\Z', $now);
        $dtObj1 = gmdate('Ymd', $now);
        $dtObjPlus3h = gmdate('Y-m-d\TH:i:s.u\Z', strtotime('+3 hours', $now));

        // 构建Policy
        $policy = [
            "expiration" => $dtObjPlus3h,
            "conditions" => [
                ["x-oss-signature-version" => "OSS4-HMAC-SHA256"],
                ["x-oss-credential" => "{$tempAccessKeyId}/{$dtObj1}/cn-shanghai/oss/aliyun_v4_request"],
                ["x-oss-security-token" => $securityToken],
                ["x-oss-date" => $dtObj],
            ]
        ];

        $policyStr = json_encode($policy);

        // 构造待签名字符串
        $stringToSign = base64_encode($policyStr);

        // 计算SigningKey
        $dateKey = $this->hmacsha256(('aliyun_v4' . $tempAccessKeySecret), $dtObj1);
        $dateRegionKey = $this->hmacsha256($dateKey, 'cn-shanghai');
        $dateRegionServiceKey = $this->hmacsha256($dateRegionKey, 'oss');
        $signingKey = $this->hmacsha256($dateRegionServiceKey, 'aliyun_v4_request');

        // 计算Signature
        $result = $this->hmacsha256($signingKey, $stringToSign);
        $signature = bin2hex($result);

        // 返回签名数据
        $responseData = [
            'policy' => $stringToSign,
            'x_oss_signature_version' => "OSS4-HMAC-SHA256",
            'x_oss_credential' => "{$tempAccessKeyId}/{$dtObj1}/cn-shanghai/oss/aliyun_v4_request",
            'x_oss_date' => $dtObj,
            'signature' => $signature,
            'host' => $host,
            'dir' => $upload_dir,
            'security_token' => $securityToken
        ];
        return json($responseData);
    }

    public function demo()
    {
        return view('/index');
    }
}