阿里云服务端签名验证:
YII2框架的
/**
* Class AliOss
* @package common\components
*/
class AliyunOss extends Component
{
public $accessKeyId;
public $accessKeySecret;
public $endpoint;
public $bucket;
public $objectBasePath;
/**
* @var OssClient client
*/
public $client = null;
/**
* init
* @throws \Exception
* 2019/3/26 17:07
*/
public function init()
{
$this->validateConfig();
$this->objectBasePath = YII_ENV.'/'.trim($this->objectBasePath, '/');
if ($this->client === null) {
$this->client = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);
}
}
/**
* validateConfig
* @throws Exception
* 2019/3/26 17:07
*/
protected function validateConfig()
{
if (!$this->objectBasePath) {
throw new Exception("请设置objectBasePath");
}
if (!$this->accessKeyId) {
throw new Exception("请设置accessKeyId");
}
if (!$this->accessKeySecret) {
throw new Exception("请设置accessKeySecret");
}
if (!$this->endpoint) {
throw new Exception("请设置endpoint");
}
if (!$this->bucket) {
throw new Exception("请设置bucket");
}
}
/**
* close
* 2019/3/26 18:06
*/
public function close()
{
if ($this->client !== null) {
Yii::trace('Closing OssClient', __METHOD__);
$this->client = null;
}
}
/**
* uploadFile
* @param string $object oss object名称
* @param string $localFile 本地文件
*
* @return |null
* @throws Exception
* 2019/3/26 17:15
*/
public function uploadFile($object, $localFile)
{
$object = $this->formatObject($object);
try {
if ($this->client->uploadFile($this->bucket, $object, $localFile)) {
return $object;
}
return false;
} catch (OssException $e) {
throw new Exception($e->getMessage(), $e->getCode(), $e);
}
}
/**
* uploadFiles
* @param $files
*
* @return array
* @throws \Exception
* 2019/3/26 17:20
*/
public function uploadFiles($files)
{
$res = [];
foreach ($files as $object => $localFile) {
$res[$object] = $this->uploadFile($object, $localFile);
}
return $res;
}
/**
* 下载oss object到本地
* downloadObject
* @param string $object oss object
* @param string $savePath 保存到本地的路径
*
* @return string
* 2019/3/27 14:14
*/
public function downloadObject($object, $savePath)
{
$options = array(
OssClient::OSS_FILE_DOWNLOAD => $savePath,
);
$object = $this->formatObject($object);
return $this->client->getObject($this->bucket, $object, $options);
}
/**
* 删除oss图片
* deleteFile
* @param $object
*
* @return array|bool
* 2019/3/27 14:32
*/
public function deleteFile($object)
{
if (is_array($object)) {
$res = [];
foreach ($object as $obj) {
if (!$this->deleteFile($obj)) {
$res['fail']++;
}
$res['success']++;
}
return $res;
}
$object = $this->formatObject($object);
if ($this->client->deleteObject($this->bucket, $object)) {
return true;
}
return false;
}
/**
* 通过multipart上传文件
* multiuploadFile
* @param $object
* @param $localFile
*
* @return |null
* @throws Exception
* 2019/3/26 17:25
*/
public function multiuploadFile($object, $localFile)
{
$object = $this->formatObject($object);
$options = array();
try {
return $this->client->multiuploadFile($this->bucket, $object, $localFile, $options);
} catch (OssException $e) {
throw new Exception($e->getMessage(), $e->getCode(), $e);
}
}
/**
* 获取视频封面图
* @param $video string 视频路径
* @param $second int 截取时间输入其它默认为0
* @param $width int 宽度px $height int 高度px
* @return string 图片相对路径
*/
public function getVideoImg($video, $second = 5, $width = 720, $height = 400)
{
$second = $second ? $second : 5;
$width = $width ? $width : 720;
$height = $height ? $height : 400;
$imgUrl = "?x-oss-process=video/snapshot,t_". $second*1000 . ",f_png,w_".$width.",h_".$height;
return $video.$imgUrl;
}
/**
* formatObject
* @param $object
*
* @return string
* 2019/3/26 17:57
*/
public function formatObject($object)
{
$object = trim($object, '/');
$res = yii\helpers\StringHelper::startsWith($object, $this->objectBasePath);
if (!$res) {
$object = $this->objectBasePath.'/'.$object;
}
return trim($object, '/');
}
/**
* PostObject签名policy
*
* @param array $policy_condition policy规则
* @param array $callback_params 回调配置
* @param int $expire policy超时时间,即这个policy过了这个有效时间,将不能访问。默认30s
* @link https://help.aliyun.com/document_detail/31927.html?spm=a2c4g.11186623.6.1567.b8e97d2dMSThOz 签名并回调上传文档
* @link https://help.aliyun.com/document_detail/91771.html?spm=a2c4g.11186623.2.15.21967eae5edmiX#concept-nhs-ldt-2fb 签名并回调上传文档
* @link http://docs-aliyun.cn-hangzhou.oss.aliyun-inc.com/assets/attach/92590/APP_zh/1539603337889/aliyun-oss-appserver-php-master.zip?spm=a2c4g.11186623.2.14.6b5e4c07xtvc9D&file=aliyun-oss-appserver-php-master.zip php签名官方demo
* @link https://help.aliyun.com/document_detail/31988.html?spm=a2c4g.11186623.2.22.21967eaeMXpMOk#section-d5z-1ww-wdb policy写法
* @link https://help.aliyun.com/document_detail/31989.html?spm=a2c4g.11186623.2.22.58dd4c07J5iEMJ#section-btz-phx-wdb callback写法
* @return array
*/
public function signPolicy(array $policy_condition = [],array $callback_params = [],int $expire = 30)
{
//用户上传文件时指定的前缀。
$objectDir = $this->formatObject($this->objectBasePath)."/";
if(!$policy_condition) {
//最大文件大小.用户可以自己设置,单位字节
$length_condition = ['content-length-range', 0, 1048576000];
// 表示用户上传的数据,必须是以$dir开始,不然上传会失败,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录。
$start_condition = ['starts-with', '$key', $objectDir];
$policy_condition = [$length_condition,$start_condition];
}
//设置该policy超时时间. 即这个policy过了这个有效时间,将不能访问。
$end = time() + $expire;
$policy_array = [
'expiration'=>DateTimeHelper::gmt($end),
'conditions'=>$policy_condition
];
$base64_policy = base64_encode(json_encode($policy_array));
$signature = base64_encode(hash_hmac('sha1', $base64_policy, $this->accessKeySecret, true));
$result = [];
$result['accessid'] = $this->accessKeyId;
$result['host'] = $this->getBucketHost();
$result['policy'] = $base64_policy;
$result['signature'] = $signature;
$result['expire'] = $end;
$result['dir'] = $objectDir;
if($callback_params){
$result['callback'] = base64_encode(json_encode($callback_params));
}
return $result;
}
/**
* 获取带bucket的host
* @return string
*/
private function getBucketHost()
{
$ret_endpoint = null;
$endpoint = $this->endpoint;
if (strpos($endpoint, 'http://') === 0) {
$http = "http://";
$ret_endpoint = substr($endpoint, strlen('http://'));
} elseif (strpos($endpoint, 'https://') === 0) {
$http = "https://";
$ret_endpoint = substr($endpoint, strlen('https://'));
} else {
$ret_endpoint = $endpoint;
$http = "https";
}
return $http.$this->bucket.'.'.$ret_endpoint;
}
/**
* 复制fromObject到新的toObject
* @param string|array $fromObject 源object
* @param string|array $toObject 目标object
* @param string|null $fromBucket 源bucket
* @param string|null $toBucket 目标bucket
* @param null $options
*
* @return array|bool
* @throws OssException
*/
public function copyFile($fromObject,$toObject,$fromBucket = NULL,$toBucket = NULL,$options = NULL)
{
if (is_array($fromObject)) {
$res = [];
foreach ($fromObject as $k=>$obj) {
if (!$this->copyFile($obj,$toObject[$k],$fromBucket,$toBucket,$options)) {
$res['fail']++;
}
$res['success']++;
}
return $res;
}
$fromBucket = $fromBucket ?? $this->bucket;
$toBucket = $toBucket ?? $this->bucket;
if ($this->client->copyObject($fromBucket,$fromObject,$toBucket,$toObject,$options)) {
return true;
}
return false;
}
/**
* 移动fromObject到新的toObject,并删除fromObject
* @param string|array $fromObject 源object
* @param string|array $toObject 目标object
* @param string|null $fromBucket 源bucket
* @param string|null $toBucket 目标bucket
* @param null $options
*
* @return array|bool
* @throws OssException
*/
public function moveFile($fromObject,$toObject,$fromBucket = NULL,$toBucket = NULL,$options = NULL)
{
if (is_array($fromObject)) {
$res = [];
foreach ($fromObject as $k=>$obj) {
if (!$this->copyFile($obj,$toObject[$k],$fromBucket,$toBucket,$options)) {
$res['fail']++;
}
$res['success']++;
}
return $res;
}
$fromBucket = $fromBucket ?? $this->bucket;
$toBucket = $toBucket ?? $this->bucket;
if ($this->client->copyObject($fromBucket,$fromObject,$toBucket,$toObject,$options)) {
if ($this->client->deleteObject($fromBucket, $fromObject)) {
return true;
}
return true;
}
return false;
}
laravel框架的
<?php
namespace App\Utils;
use Illuminate\Support\Facades\Log;
use OSS\OssClient;
use OSS\Core\OssException;
use OSS\Model\RefererConfig;
class OssUtil
{
private static $_instance;
protected $ossClient;
protected $bucket;
protected $endpoint;
protected $ossConfig;
public function __construct($bucket = null){
$this->ossConfig = config('oss');
$this->ossClient = new OssClient($this->ossConfig['accessKeyId'],$this->ossConfig['accessKeySecret'],$this->ossConfig['endpoint']);
if($bucket){
$this->bucket = $bucket;
}else{
$this->bucket = $this->ossConfig['default_bucket'];
}
$this->endpoint = $this->ossConfig['endpoint'];
if(!empty($ossConfig['bucket_white_list'])){
$this->setBucketReferer($this->ossConfig['default_bucket'], $this->ossConfig['bucket_white_list']);
}
$this->ossClient->setTimeout(3600);
$this->ossClient->setUseSSL(false);
}
public static function getInstance($options = null)
{
if (is_null(self::$_instance)) {
self::$_instance = new static($options);
}
return self::$_instance;
}
//生成oss对象
public function getOssClient(){
return $this->ossClient;
}
//获取bucket
public function getBucket(){
return $this->bucket;
}
//获取bucket地域
public function getEndpoint(){
return $this->endpoint;
}
//获得当次请求使用的协议头
public function getScheme(){
return $this->ossClient->isUseSSL() ? 'https://' : 'http://';
}
//获取签名
public function getSign($dir, $size)
{
$dir = config('oss.object') . $dir;
//$host的格式为https://bucketname.endpointx
$host = $this->getScheme() . $this->bucket . '.' . $this->endpoint;
//回调地址
$callbackUrl = str_replace('_', '', url('/api/ossCallback', [], true));
$callbackparam = array('callbackUrl'=>$callbackUrl,
'callbackBody'=>'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}&format=${imageInfo.format}',
'callbackBodyType'=>"application/x-www-form-urlencoded");
$callbackString = json_encode($callbackparam);
$base64CallbackBody = base64_encode($callbackString);
$now = time();
$expire = 60; //设置该policy超时时间. 即这个policy过了这个有效时间,将不能访问。
$end = $now + $expire;
$expiration = $this->gmtIso8601($end);
//最大文件大小.用户可以自己设置
$condition = array(0=>'content-length-range', 1=>0, 2=>$size);
$conditions[] = $condition;
// 表示用户上传的数据,必须是以$dir开始,不然上传会失败,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录。
$start = array(0=>'starts-with', 1=>'$key', 2=>$dir);
$conditions[] = $start;
$arr = array('expiration'=>$expiration,'conditions'=>$conditions);
$policy = json_encode($arr);
$base64Policy = base64_encode($policy);
$stringToSign = $base64Policy;
$signature = base64_encode(hash_hmac('sha1', $stringToSign, $this->ossConfig['accessKeySecret'], true));
$response = array();
$response['accessid'] = $this->ossConfig['accessKeyId'];
$response['host'] = $host;
$response['policy'] = $base64Policy;
$response['signature'] = $signature;
$response['expire'] = $end;
$response['callback'] = $base64CallbackBody;
$response['dir'] = $dir; // 这个参数是设置用户上传文件时指定的前缀。
return $response;
}
/**
* 文件上传
* @param $object string 上传的object
* @param $filePath string 本地路径
* @return array
*/
public function uploadFile($object,$filePath){
try{
$this->ossClient->uploadFile($this->bucket,$object,$filePath);
return ['status'=>200,'url'=>$object];
}catch(OssException $e){
Log::channel('daily')->info('上传oss失败',['file'=>$filePath]);
return ['status'=>0];
}
}
/**
* 文件保存
* @param $object string 文件的object
* @param $filePath string 本地路径
* @return array
*/
public function downLoadFile($object,$filePath){
try{
$options = [OssClient::OSS_FILE_DOWNLOAD => $filePath];
$result = $this->ossClient->getObject($this->bucket,$object,$options);
return ['status'=>200,$result];
}catch(OssException $e){
Log::channel('daily')->info('下载失败',[$e->getMessage()]);
return ['status'=>0];
}
}
//设置白名单
private function setBucketReferer($bucket, $whiteList)
{
$refererConfig = new RefererConfig();
$refererConfig->setAllowEmptyReferer(true);
$whiteList = explode(',', $whiteList);
foreach ($whiteList as $key => $value) {
$refererConfig->addReferer($value);
}
try {
$this->ossClient->putBucketReferer($bucket, $refererConfig);
return true;
} catch (OssException $e) {
return false;
}
}
private function gmtIso8601($time)
{
$dtStr = date('c', $time);
$mydatetime = new \DateTime($dtStr);
$expiration = $mydatetime->format(\DateTime::ISO8601);
$pos = strpos($expiration, '+');
$expiration = substr($expiration, 0, $pos);
return $expiration."Z";
}
}
网友评论