Skip to content

OSS

使用阿里云 OSS 保存静态文件,可以减少网站服务器压力,并可加快网页显示。阿里云也提供了比较系统的 OSS 学习路径 便于学习使用。下面斑马兽快速带你使用 OSS。

服务配置

首先访问阿里云 OSS 服务,并添加 Bucket。

  • 如果公开访问的网站静态文件可以设置权限为「公共读」,
  • 建议 oss 使用 private 私有模式,结合 CDN 保存静态资源,这样费用更低,速度也快

程序编码

下面来安装阿里云提供的PHP SDK快速将 OSS 功能集成到你的项目中

安装配置

composer require aliyuncs/oss-sdk-php

创建 App\Services\OssService oss 服务文件,修改App\ProvidersAppServiceProvider 将服务文件注册到项目中

class AppServiceProvider extends ServiceProvider
{
    public $singletons = [
        "oss" => OssService::class
    ];
    ...
}

上传服务

接下来实现 OssService 代码,用于 OSS 上传文件与创建 bucket

<?php

namespace App\Services;

use Illuminate\Support\Facades\Auth;
use OSS\OssClient;
use OSS\Core\OssException;
use OSS\Credentials\StaticCredentialsProvider;

//阿里云OSS服务
class OssService
{
    protected $ossProvider;
    protected $ossClient;
    protected $bucket;

    public function __construct()
    {
        $this->init();
    }

    //初始化OSS实例
    private function init()
    {
        //阿里云 bucket
        $this->bucket = config('bm.admin.aliyun_oss_bucket');
        //阿里云OSS Provider用于生成 ossclient 配置
        $this->ossProvider = new StaticCredentialsProvider(config('bm.admin.aliyun_key'), config('bm.admin.aliyun_secret'));
        $config = array(
            "provider" => $this->ossProvider,
            "endpoint" => config('bm.admin.aliyun_oss_endpoint'),
        );
        //生成oss客户端用于使用 oss 功能
        $this->ossClient =  new OssClient($config);
    }

    /**
     * 上传文件到 oss
     *
     * @param string $object oss 保存的文件路径
     * @param string $content 文件内容
     * @param array $options 上传选项
     */
    public function upload(string $object, string $content, array $options = [])
    {
        $file = request('file');
        try {
            //上传文件到 oss
            $response = $this->ossClient->putObject($this->bucket, $object, $content, $options);
            // oss 返回的链接
            $url = $response['oss-request-url'];
            //如果配置了 cdn 域名,则返回 cdn 链接
            if (config('bm.admin.aliyun_cdn_domain')) {
                $url = config('bm.admin.aliyun_cdn_domain') . preg_replace('/https?:\/\/.+?(?=\/)/is', '', $response['oss-request-url']);;
            }
            //将上传文件信息保存到数据库
            return Auth::user()->uploads()->create([
                'url' => $url,
                'name' => $file->getClientOriginalName(),
                'size' => $file->getSize(),
                'extension' => $file->getClientOriginalExtension(),
                'mime' => $file->getMimeType()
            ]);
        } catch (OssException $e) {
            abort(400, $e->getMessage());
        }
    }

    //创建OSS储存块
    public function createBucket()
    {
        try {
            $this->ossClient->createBucket(config('bm.admin.aliyun_oss_bucket'));
        } catch (OssException $e) {
            abort(400, 'OSS bucket创建失败!' . $e->getMessage());
        }
    }

    /**
     * cdn资源签名
     * @param string $path 文件地址
     */
    public function cdnSign(string $path)
    {
        //如果你使用 oss 桌面端软件复制的链接,需要把OSSAccessKeyId字符串删除掉
        // $path = preg_replace('/\?OSSAccessKeyId=.+/i', '', $path);
        if (empty($path)) return;
        $domain = config('bm.admin.aliyun_cdn_domain');
        $key = config('bm.admin.aliyun_cdn_key');
        $filename = preg_replace('/https?:\/\/.+?(?=\/)/is', '', $path);
        $time = strtotime("+20 minutes");
        $sstring = $filename . "-" . $time . "-0-0-" . $key;
        $auth_key = "auth_key=" . $time . "-0-0-" . md5($sstring);
        return $domain .  $filename . "?" . $auth_key;
    }
}

控制器

下面是在控制器中使用 oss 处理视频上传

//更新视频
class UpdateVideoController extends Controller  implements HasMiddleware
{
    public static function middleware()
    {
        return [new Middleware('auth:sanctum', except: [])];
    }
		...
		
    //上传视频
    public function uploadVideo(Request $request, Chapter $chapter)
    {
        $size = config('bm.admin.upload_file_size') * 1024;
        $request->validate(['file' => ['required', 'file', "max:{$size}"]]);
        return app('oss')->upload($this->dir . '/' . $this->file->hashName(), file_get_contents($this->file));
    }
}

前端组件

文件上传的前端组件,我已经写了文档,你可以在文档库中查看。