目录
文档
1、阿里云OSS上传方式
1.1、Web端Browser.js SDK直传(不推荐)
该方法会将AccessKey ID和AccessKey Secret直接保存在浏览器端,存在极高的风险
1.2、Web端上传服务端再上传至OSS
这种方式上传速度慢
1.3、服务端签名后Web端直传(推荐)
该方式安全性和上传速度都不错,本文采用此方式上传
2、PHP服务端生成签名
本例服务端签名生成代码通过官网给出的示例修改而来,基于ThinkPHP框架
使用了第三方库 ramsey/uuid
生成文件名
安装
composer require ramsey/uuid
官网给的示例有callback
参数,如果是前端使用签名直接传OSS是不需要这个参数的
结合官网给的Node.js示例,改造PHP代码
AliOssService.php
namespace app\service;use Ramsey\Uuid\Uuid;class AliOssService{ // 配置oss参数 private const AccessKeyId = '' ; private const AccessKeySecret = '' ; private const Host = 'https://.oss-cn-beijing.aliyuncs.com' ; // 签名有效期 单位: 秒 private const Expire = 3 * 60; // 允许上传的文件最大和最小范围 单位:字节 private const ContentLengthMin = 0; private const ContentLengthMax = 20 * 1024 * 1024; 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 $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 ]; } public static function getPolicyBase64($policyParams) { return base64_encode(json_encode($policyParams)); } public static function getSignature($policyBase64, $accessKeySecret) { return base64_encode(hash_hmac('sha1', $policyBase64, $accessKeySecret, true)); } public static function getExpireTime($time) { return str_replace('+00:00', '.000Z', gmdate('c', time() + $time)); } public static function getDirname($dirname) { return $dirname . '/' . date('Y-m') . '/'; } public static function getFilename($ext) { $uuid = Uuid::uuid4()->toString(); return $uuid . '.' . $ext; }}
AliOssController.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
namespace app\exception;use Exception;class AppException extends Exception{}
3、微信小程序客户端
参考官网给出的示例实现
思路:
客户端拿到文件名后缀后,传给服务端,获取签名和文件名等必要的上传参数,让更多的工作在服务端完成
oss-upload-file.js
// 获取文件扩展名function getFilePathExtention(filePath) { return filePath.split('.').slice(-1)[0];}// 上传到阿里云ossfunction 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;}