微信小程序:阿里云OSS直传实践-PHP实现服务端签名

简介: 微信小程序:阿里云OSS直传实践-PHP实现服务端签名

目录

文档

1、阿里云OSS上传方式

1.1、Web端Browser.js SDK直传(不推荐)

该方法会将AccessKey ID和AccessKey Secret直接保存在浏览器端,存在极高的风险

1.2、Web端上传服务端再上传至OSS

这种方式上传速度慢

image.png

1.3、服务端签名后Web端直传(推荐)

该方式安全性和上传速度都不错,本文采用此方式上传

image.png

2、PHP服务端生成签名

本例服务端签名生成代码通过官网给出的示例修改而来,基于ThinkPHP框架

使用了第三方库 ramsey/uuid 生成文件名

安装

composer require ramsey/uuid

官网给的示例有callback 参数,如果是前端使用签名直接传OSS是不需要这个参数的

结合官网给的Node.js示例,改造PHP代码

AliOssService.php

<?php
namespace app\service;
use Ramsey\Uuid\Uuid;
/**
 * Class AliOssService
 * @package app\service
 *
 * 微信小程序直传实践
 * @see https://help.aliyun.com/document_detail/92883.html
 */
class AliOssService
{
    // 配置oss参数
    private const AccessKeyId = '<AccessKeyId>';
    private const AccessKeySecret = '<AccessKeySecret>';
    private const Host = 'https://<region>.oss-cn-beijing.aliyuncs.com';
    // 签名有效期 单位: 秒
    private const Expire = 3 * 60;
    // 允许上传的文件最大和最小范围 单位:字节
    private const ContentLengthMin = 0;
    private const ContentLengthMax = 20 * 1024 * 1024;
    /**
     * 获取服务端签名方式上传参数
     * @param $params array
     *   ext string 扩展名 eg: jpg
     *   dirname string 上传目录 eg: image
     * @return array
     * @throws \Exception
     */
    public static function getUploadParams($params)
    {
        // 接收参数
        $ext     = $params['ext'];
        $dirname = $params['dirname'];
        // 文件路径和文件名
        $dir = self::getDirname($dirname);
        $key = $dir . self::getFilename($ext);
        // 过期时间
        $expiration = self::getExpireTime(self::Expire);
        // 参数设置
        // 附录:Post Policy
        // https://help.aliyun.com/document_detail/31988.htm#section-d5z-1ww-wdb
        $policyParams = [
            'expiration' => $expiration,
            'conditions' => [
                // 指定前缀
                ['starts-with', '$key', $dir],
                // 限制上传文件大小。单位:字节
                ['content-length-range', self::ContentLengthMin, self::ContentLengthMax]
            ]
        ];
        $policyBase64 = self::getPolicyBase64($policyParams);
        $signature = self::getSignature($policyBase64, self::AccessKeySecret);
        return [
            'accessKeyId' => self::AccessKeyId,
            'host'        => self::Host,
            'policy'      => $policyBase64,
            'signature'   => $signature,
            'expire'      => $expiration,
            'key'         => $key,
            'url'         => self::Host . '/' . $key
        ];
    }
    /**
     * 获取参数base64
     * @param $policyParams array
     * @return string
     */
    public static function getPolicyBase64($policyParams)
    {
        return base64_encode(json_encode($policyParams));
    }
    /**
     * 获取签名
     * @param $policyBase64 string
     * @param $accessKeySecret string
     * @return string
     */
    public static function getSignature($policyBase64, $accessKeySecret)
    {
        return base64_encode(hash_hmac('sha1', $policyBase64, $accessKeySecret, true));
    }
    /**
     * 获取过期时间
     * @param $time int 单位: 秒
     * @return mixed
     */
    public static function getExpireTime($time)
    {
        return str_replace('+00:00', '.000Z', gmdate('c', time() + $time));
    }
    /**
     * 获取按照月份分隔的文件夹路径
     * @param $dirname string eg: image/video
     * @return string eg: image/2022-10/
     */
    public static function getDirname($dirname)
    {
        return $dirname . '/' . date('Y-m') . '/';
    }
    /**
     * 获取一个随机的文件名
     * @param $ext string eg: jpg
     * @return string eg: a4030d9f-c4a2-4f1a-8e33-80e017e572d5.jpg
     * @throws \Exception
     */
    public static function getFilename($ext)
    {
        $uuid = Uuid::uuid4()->toString();
        return $uuid . '.' . $ext;
    }
}

AliOssController.php

<?php
namespace app\controller;
use app\BaseController;
use app\exception\AppException;
use app\service\AliOssService;
class AliOssController extends BaseController
{
    public function getUploadParams()
    {
        $ext     = input('ext');
        $dirname = input('dirname', 'image');
        // 参数校验
        if (!$ext) {
            throw new AppException('ext is empty');
        }
        if (!in_array($dirname, ['image', 'video'], true)) {
            throw new AppException('dirname: only allow image or video');
        }
        $result = AliOssService::getUploadParams([
            'ext'     => $ext,
            'dirname' => $dirname,
        ]);
        return $result;
    }
}

AppException.php

<?php
namespace app\exception;
use Exception;
/**
 * 自定义的业务异常
 * Class AppException
 * @package app\exception
 */
class AppException extends Exception
{
}

3、微信小程序客户端

参考官网给出的示例实现

思路:

客户端拿到文件名后缀后,传给服务端,获取签名和文件名等必要的上传参数,让更多的工作在服务端完成

oss-upload-file.js

// 获取文件扩展名
function getFilePathExtention(filePath) {
  return filePath.split('.').slice(-1)[0];
}
// 上传到阿里云oss
function uploadFileAsync(config, filePath) {
  console.log(config);
  return new Promise((resolve, reject) => {
    wx.uploadFile({
      url: config.host, // 开发者服务器的URL。
      filePath: filePath,
      name: 'file', // 必须填file。
      formData: {
        key: config.key,
        policy: config.policy,
        OSSAccessKeyId: config.accessKeyId,
        signature: config.signature,
        // 'x-oss-security-token': securityToken // 使用STS签名时必传。
      },
      success: (res) => {
        console.log(res);
        if (res.statusCode === 204) {
          resolve();
        } else {
          reject('上传失败');
        }
      },
      fail: (err) => {
        // console.log(err);
        reject(err);
      },
    });
  });
}
// 上传文件
export async function uploadFile(filePath, dirname = 'image') {
  console.log(filePath);
  let ext = getFilePathExtention(filePath);
   // 改方法通过接口获取服务端生成的上传签名 
   const resParams = await Http.AliOssGetUploadParams({
    ext,
    dirname,
  });
  //   console.log(resParams.data);
  //   let objectName = resParams.data.uuid + '.' + getFilePathExtention(filePath);
  await uploadFileAsync(resParams.data, filePath);
  //   console.log(res);
  return resParams;
}


相关实践学习
对象存储OSS快速上手——如何使用ossbrowser
本实验是对象存储OSS入门级实验。通过本实验,用户可学会如何用对象OSS的插件,进行简单的数据存、查、删等操作。
相关文章
|
PHP 对象存储 Docker
阿里云云效产品使用问题之PHP和LAMP项目部署回滚不生效,该怎么办
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
消息中间件 监控 数据挖掘
【有奖实践】轻量消息队列(原 MNS)订阅 OSS 事件实时处理文件变动
当你需要对对象存储 OSS(Object Storage Service)中的文件变动进行实时处理、同步、监听、业务触发、日志记录等操作时,你可以通过设置 OSS 的事件通知规则,自定义关注的文件,并将 OSS 事件推送到轻量消息队列(原 MNS)的队列或主题中,开发者的服务即可及时收到相关通知,并通过消费消息进行后续的业务处理。
504 109
|
弹性计算 人工智能 数据管理
AI场景下的对象存储OSS数据管理实践
本文介绍了ECS和OSS的操作流程,分为两大部分。第一部分详细讲解了ECS的登录、密码重置、安全组设置及OSSUTIL工具的安装与配置,通过实验创建并管理存储桶,上传下载文件,确保资源及时释放。第二部分则聚焦于OSSFS工具的应用,演示如何将对象存储挂载为磁盘,进行大文件加载与模型训练,强调环境搭建(如Conda环境)及依赖安装步骤,确保实验结束后正确清理AccessKey和相关资源。整个过程注重操作细节与安全性,帮助用户高效利用云资源完成实验任务。
1407 161
|
存储 小程序 前端开发
【微信小程序 - 工作实战分享】1.微信小程序发送手机短信验证码(阿里云)
【微信小程序 - 工作实战分享】1.微信小程序发送手机短信验证码(阿里云)
1870 0
|
关系型数据库 数据库 对象存储
Dify实践|Dify on DMS+对象存储OSS,实现多副本部署方案
本文介绍了在DMS上部署Dify的详细步骤,用户可选择一键购买资源或基于现有资源部署Dify,需配置RDS PostgreSQL、Redis、AnalyticDB for PostgreSQL等实例,并设置存储路径和资源规格。文中还提供了具体配置参数说明及操作截图,帮助用户顺利完成部署。
|
Java 对象存储
OSS对象存储Header方式JavaV4签名
本文介绍了如何使用Java代码生成阿里云OSS的V4签名授权。通过设置时间、访问密钥等参数,创建签名请求并输出授权信息。包含两张示意图展示流程和关键步骤。
652 1
|
消息中间件 对象存储
轻量消息队列(原 MNS)订阅 OSS 事件实践
使用轻量消息队列订阅OSS事件,实时处理文件变动,赢取ins风U型枕(限量500个)。访问活动页面,完成实操并上传截图即可参与领奖。活动时间:即日起至2025年2月28日16:00。奖品数量有限,先到先得,快来报名吧!
493 2
|
弹性计算 数据管理 应用服务中间件
活动实践 | 借助OSS搭建在线教育视频课程分享网站
本教程指导用户在阿里云ECS实例上搭建在线教育网站,包括重置ECS密码、配置安全组、安装Nginx、创建网站页面、上传数据至OSS、开通OSS传输加速、配置生命周期策略及清理资源等步骤,实现高效、低成本的数据管理和网站运营。
活动实践 | 借助OSS搭建在线教育视频课程分享网站
|
存储 人工智能 开发工具
AI场景下的对象存储OSS数据管理实践
本文介绍了对象存储(OSS)在AI业务中的应用与实践。内容涵盖四个方面:1) 对象存储作为AI数据基石,因其低成本和高弹性成为云上数据存储首选;2) AI场景下的对象存储实践方案,包括数据获取、预处理、训练及推理阶段的具体使用方法;3) 国内主要区域的默认吞吐量提升至100Gbps,优化了大数据量下的带宽需求;4) 常用工具介绍,如OSSutil、ossfs、Python SDK等,帮助用户高效管理数据。重点讲解了OSS在AI训练和推理中的性能优化措施,以及不同工具的特点和应用场景。
1373 10
|
安全 对象存储
OSS对象存储JavaV4签名
本文介绍了如何使用阿里云OSS-SDK生成V4版本的签名URL和Header签名。通过设置时间、访问密钥等参数,代码示例展示了如何创建带有V4签名的请求,适用于安全访问对象存储服务。相关文档链接提供了更多详细信息。
1377 7