PHP 使用 OSS上传文件

安装阿里云 OSS SDK

在网站根目录下执行以下 Composer 命令,安装阿里云 OSS 官方 SDK:

composer require aliyuncs/oss-sdk-php

安装完成后,会在网站根目录的 vendor 文件夹下生成 aliyuncs 目录,包含 SDK 核心文件。

获取 OSS 访问凭证

1. 必备参数说明

上传文件前需准备以下 4 个核心参数,可在阿里云 OSS 控制台获取:

  • Endpoint:OSS 地域节点(如香港节点 oss-cn-hongkong.aliyuncs.com

  • AccessKeyId:访问密钥 ID

  • AccessKeySecret:访问密钥密钥

  • Bucket:存储空间名称(需提前在 OSS 控制台创建)

2. 参数获取路径

登录 阿里云 OSS 控制台 → 进入目标存储空间 → 查看「概览」获取 Endpoint 和 Bucket 名称;访问 AccessKey 管理控制台 生成/查看 AccessKeyId 和 AccessKeySecret。

完整实现代码

1. 前端上传页面(upload.html)

提供文件选择和提交功能,支持 multipart/form-data 格式上传:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>OSS 图片上传示例</title>
</head>
<body>
    <form action="oss-image/upload-image.json" method="post" enctype="multipart/form-data">
        <label for="file">选择文件:</label>
        <input type="file" name="image" id="file" accept="image/*"><br>
        <input type="submit" name="submit" value="上传文件">
    </form>
</body>
</html>

注:accept="image/*" 限制仅上传图片文件,可根据需求删除该属性支持所有文件类型。

2. 控制器(OssImageController.php)

接收前端请求,转发至 Service 层处理(控制层与业务层分离):

<?php
declare(strict_types = 1);

namespace app\controllers;

use app\services\OssImageService;
use yii\web\Controller;

class OssImageController extends Controller
{
    /**
     * OSS 文件上传接口
     * @return array 上传结果(含文件URL)
     * @throws \OSS\Core\OssException
     */
    public function actionUploadImage()
    {
        // 直接调用 Service 层上传逻辑,返回标准化响应
        return $this->asJson(OssImageService::service()->uploadImage());
    }
}

3. 业务逻辑层(OssImageService.php)

核心上传逻辑处理,包含文件命名、格式转换、上传执行:

<?php
declare(strict_types = 1);

namespace app\services;

use app\extensions\AliOss;
use OSS\Core\OssException;

class OssImageService extends BaseService
{
    /**
     * 执行 OSS 文件上传
     * @return array 上传结果数据
     * @throws OssException
     */
    public function uploadImage()
    {
        // 1. 验证文件是否上传成功
        if (empty($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
            throw new \RuntimeException('文件上传失败,请检查文件大小和格式');
        }

        // 2. 获取 OSS 客户端实例和存储空间名称
        $ossClient = AliOss::getOssClient();
        $bucketName = AliOss::getBucketName();

        // 3. 处理文件信息
        $originalFileName = $_FILES['image']['name']; // 原始文件名
        $tmpFilePath = $_FILES['image']['tmp_name']; // 服务器临时文件路径
        $fileExt = $this->getExtension($originalFileName); // 文件扩展名

        // 4. 构建 OSS 存储路径(按日期分类,避免文件名重复)
        $ossDir = 'test/' . date('Y-m-d') . '/'; // 存储目录:test/年-月-日/
        $ossFileName = date('Hi') . mt_rand(10000, 99999); // 文件名:时分+5位随机数
        $ossObject = $ossDir . $ossFileName . '.' . $fileExt; // 完整 OSS 对象路径

        // 5. 执行文件上传
        $uploadResult = $ossClient->uploadFile($bucketName, $ossObject, $tmpFilePath);

        // 6. 处理返回 URL(HTTP 转 HTTPS,提升安全性)
        $ossUrl = $uploadResult['oss-request-url'];
        if (strpos($ossUrl, 'http://') === 0) {
            $ossUrl = str_replace('http://', 'https://', $ossUrl);
        }

        // 7. 组装返回数据
        return [
            'status' => 1,
            'msg' => '上传成功',
            'data' => [
                'file_url' => $ossUrl, // 文件访问 URL
                'file_name' => basename($ossUrl), // 文件名
                'original_name' => $originalFileName, // 原始文件名(新增)
                'file_size' => $_FILES['image']['size'] // 文件大小(新增)
            ]
        ];
    }

    /**
     * 获取文件扩展名(兼容各种文件名格式)
     * @param string $fileName 原始文件名
     * @return string 扩展名(小写)
     */
    private function getExtension(string $fileName): string
    {
        $ext = pathinfo($fileName, PATHINFO_EXTENSION);
        return strtolower($ext);
    }
}

4. OSS 配置封装(AliOss.php)

集中管理 OSS 配置参数,便于维护:

<?php
declare(strict_types = 1);

namespace app\extensions;

use OSS\OssClient;
use OSS\Core\OssException;

class AliOss
{
    // 配置参数(建议移至环境变量或配置文件,避免硬编码)
    const ENDPOINT = 'oss-cn-hongkong.aliyuncs.com';
    const ACCESS_KEY_ID = 'LSDFskkdDDSSdkfg';
    const ACCESS_KEY_SECRET = 'LT9cG3JkGKffRPalgk4n33lk8Ll41d';
    const BUCKET = 'hk-server';

    /**
     * 获取 OSS 客户端实例
     * @return OssClient|null OSS 客户端对象
     */
    public static function getOssClient()
    {
        try {
            // 初始化 OSS 客户端(false 表示不开启 CNAME)
            return new OssClient(
                self::ACCESS_KEY_ID,
                self::ACCESS_KEY_SECRET,
                self::ENDPOINT,
                false
            );
        } catch (OssException $e) {
            // 异常日志记录(建议替换为项目日志组件)
            error_log('OSS 客户端初始化失败:' . $e->getMessage());
            return null;
        }
    }

    /**
     * 获取存储空间名称
     * @return string Bucket 名称
     */
    public static function getBucketName(): string
    {
        return self::BUCKET;
    }
}

上传结果与使用说明

1. 接口返回格式

上传成功后,前端将收到以下 JSON 响应:

{
    "status": 1,
    "msg": "上传成功",
    "data": {
        "file_url": "https://hk-server.oss-cn-hongkong.aliyuncs.com/test/2018-08-22/211753008.jpg",
        "file_name": "211753008.jpg",
        "original_name": "IMG_2023.jpg",
        "file_size": 204800
    }
}

2. 后续操作建议

  1. 前端接收 file_url 后,需调用额外接口将文件信息(URL、原始文件名、分类、上传人等)存储到本地数据库,便于后续管理;

  2. 直接访问返回的 file_url 即可查看/下载文件,同时可在阿里云 OSS 控制台的对应 Bucket 中找到上传的文件。

常见问题排查

1. 访问密钥错误

  • 错误提示:The OSS Access Key Id you provided does not exist in our records

  • 解决方案:重新生成 AccessKeyId 和 AccessKeySecret,确保配置文件中的参数与控制台一致。

2. 文件上传失败

  • 可能原因:

    1. 临时文件路径权限不足(检查服务器 tmp 目录权限);

    2. 文件大小超过 PHP 配置限制(调整 php.ini 中的 upload_max_filesizepost_max_size);

    3. OSS 存储空间权限设置不当(需确保 AccessKey 拥有上传权限)。

3. 其他错误

参考 阿里云 OSS 官方错误排查文档,根据错误码定位问题。

后续优化方向

1. 安全优化

将 AccessKey 等敏感信息移至.env环境变量或配置文件,避免硬编码在代码中;

2. 文件验证

增加文件类型、大小、后缀名验证,防止恶意文件上传;

3. 异常处理

完善异常捕获和日志记录,便于问题排查;

4. 性能优化

大文件建议使用分片上传,避免单次上传超时;

5. 权限控制

OSS 存储空间建议设置合理的访问权限,必要时使用 URL 签名过期机制。