Skip to content

Commit

Permalink
添加阿里云国际短信发送网关 (overtrue#321)
Browse files Browse the repository at this point in the history
  • Loading branch information
curder authored Jan 5, 2022
1 parent e092cef commit 72f66a8
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 0 deletions.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,35 @@ $easySms->send(13188888888, $message);
],
```

### [阿里云国际](https://www.alibabacloud.com/help/zh/doc-detail/160524.html)

短信内容使用 `template` + `data`

```php
'aliyunintl' => [
'access_key_id' => '',
'access_key_secret' => '',
'sign_name' => '',
],
```

发送示例:

```php
use Overtrue\EasySms\PhoneNumber;

$easySms = new EasySms($config);
$phone_number = new PhoneNumber(18888888888, 86);

$easySms->send($phone_number, [
'content' => '您好:先生/女士!您的验证码为${code},有效时间是5分钟,请及时验证。',
'template' => 'SMS_00000001', // 模板ID
'data' => [
"code" => 521410,
],
]);
```

### [云片](https://www.yunpian.com)

短信内容使用 `content`
Expand Down
97 changes: 97 additions & 0 deletions src/Gateways/AliyunIntlGateway.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

namespace Overtrue\EasySms\Gateways;

use Overtrue\EasySms\Contracts\MessageInterface;
use Overtrue\EasySms\Contracts\PhoneNumberInterface;
use Overtrue\EasySms\Exceptions\GatewayErrorException;
use Overtrue\EasySms\Support\Config;
use Overtrue\EasySms\Traits\HasHttpRequest;

/**
* Class AliyunIntlGateway
*
* @package \Overtrue\EasySms\Gateways
*
* @see https://www.alibabacloud.com/help/zh/doc-detail/162279.htm
*/
class AliyunIntlGateway extends Gateway
{
use HasHttpRequest;

const ENDPOINT_URL = 'https://dysmsapi.ap-southeast-1.aliyuncs.com';

const ENDPOINT_ACTION = 'SendMessageWithTemplate';

const ENDPOINT_VERSION = '2018-05-01';

const ENDPOINT_FORMAT = 'JSON';

const ENDPOINT_REGION_ID = 'ap-southeast-1';

const ENDPOINT_SIGNATURE_METHOD = 'HMAC-SHA1';

const ENDPOINT_SIGNATURE_VERSION = '1.0';


/**
* @param \Overtrue\EasySms\Contracts\PhoneNumberInterface $to
* @param \Overtrue\EasySms\Contracts\MessageInterface $message
* @param \Overtrue\EasySms\Support\Config $config
*
* @return array
*
* @throws \Overtrue\EasySms\Exceptions\GatewayErrorException
*
*/
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
{
$data = $message->getData($this);

$signName = !empty($data['sign_name']) ? $data['sign_name'] : $config->get('sign_name');

unset($data['sign_name']);

$params = [
'RegionId' => self::ENDPOINT_REGION_ID,
'AccessKeyId' => $config->get('access_key_id'),
'Format' => self::ENDPOINT_FORMAT,
'SignatureMethod' => self::ENDPOINT_SIGNATURE_METHOD,
'SignatureVersion' => self::ENDPOINT_SIGNATURE_VERSION,
'SignatureNonce' => uniqid('', true),
'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
'Version' => self::ENDPOINT_VERSION,
'To' => !\is_null($to->getIDDCode()) ? (int) $to->getZeroPrefixedNumber() : $to->getNumber(),
'Action' => self::ENDPOINT_ACTION,
'From' => $signName,
'TemplateCode' => $message->getTemplate($this),
'TemplateParam' => json_encode($data, JSON_FORCE_OBJECT),
];

$params['Signature'] = $this->generateSign($params);

$result = $this->get(self::ENDPOINT_URL, $params);

if ('OK' !== $result['ResponseCode']) {
throw new GatewayErrorException($result['ResponseDescription'], $result['ResponseCode'], $result);
}

return $result;
}

/**
* Generate sign
*
* @param array $params
*
* @return string
*/
protected function generateSign(array $params)
{
ksort($params);
$accessKeySecret = $this->config->get('access_key_secret');
$stringToSign = 'GET&%2F&'.urlencode(http_build_query($params, '', '&', PHP_QUERY_RFC3986));

return base64_encode(hash_hmac('sha1', $stringToSign, $accessKeySecret.'&', true));
}
}
86 changes: 86 additions & 0 deletions tests/Gateways/AliyunIntlGatewayTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace Overtrue\EasySms\Tests\Gateways;

use Overtrue\EasySms\Exceptions\GatewayErrorException;
use Overtrue\EasySms\Message;
use Overtrue\EasySms\PhoneNumber;
use Overtrue\EasySms\Support\Config;
use Overtrue\EasySms\Tests\TestCase;
use Overtrue\EasySms\Gateways\AliyunIntlGateway;

/**
* Class AliyunIntlGatewayTest
*
* @package \Overtrue\EasySms\Tests\Gateways
*/
class AliyunIntlGatewayTest extends TestCase
{
/** @test */
public function it_can_sen_sms_by_aliyun_intl_gateway()
{
$config = [
'access_key_id' => 'mock-api-key',
'access_key_secret' => 'mock-api-secret',
'sign_name' => 'mock-api-sign-name',
'template_code' => 'mock-template-code',
];
$gateway = \Mockery::mock(AliyunIntlGateway::class.'[get]', [$config])->shouldAllowMockingProtectedMethods();

$expected = [
'RegionId' => 'ap-southeast-1',
'AccessKeyId' => 'mock-api-key',
'Format' => 'JSON',
'SignatureMethod' => 'HMAC-SHA1',
'SignatureVersion' => '1.0',
// 'SignatureNonce' => uniqid('', true),
// 'Timestamp' => date('Y-m-d\TH:i:s\Z'),
'Version' => '2018-05-01',
'To' => (string) new PhoneNumber(18888888888),
'Action' => 'SendMessageWithTemplate',
'From' => 'mock-api-sign-name',
'TemplateCode' => 'mock-template-code',
'TemplateParam' => json_encode(['code' => '123456']),
];

$gateway->shouldReceive('get')
->with(AliyunIntlGateway::ENDPOINT_URL, \Mockery::on(function ($params) use ($expected) {
if (empty($params['Signature'])) {
return false;
}

unset($params['SignatureNonce'], $params['Timestamp'], $params['Signature']);

ksort($params);
ksort($expected);

return $params == $expected;
}))
->andReturn([
'ResponseCode' => 'OK',
'ResponseDescription' => 'mock-result',
], [
'ResponseCode' => 1234,
'ResponseDescription' => 'mock-err-msg',
])
->twice();

$message = new Message([
'template' => 'mock-template-code',
'data' => ['code' => '123456'],
]);

$config = new Config($config);

$this->assertSame([
'ResponseCode' => 'OK',
'ResponseDescription' => 'mock-result',
], $gateway->send(new PhoneNumber(18888888888), $message, $config));

$this->expectException(GatewayErrorException::class);
$this->expectExceptionCode(1234);
$this->expectExceptionMessage('mock-err-msg');

$gateway->send(new PhoneNumber(18888888888), $message, $config);
}
}

0 comments on commit 72f66a8

Please sign in to comment.