初始上传
This commit is contained in:
20
vendor/overtrue/easy-sms/.editorconfig
vendored
Executable file
20
vendor/overtrue/easy-sms/.editorconfig
vendored
Executable file
@@ -0,0 +1,20 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = false
|
||||
|
||||
[*.{vue,js,scss}]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
768
vendor/overtrue/easy-sms/README.md
vendored
Executable file
768
vendor/overtrue/easy-sms/README.md
vendored
Executable file
@@ -0,0 +1,768 @@
|
||||
<h1 align="center">Easy SMS</h1>
|
||||
|
||||
<p align="center">:calling: 一款满足你的多种发送需求的短信发送组件</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/overtrue/easy-sms"><img src="https://travis-ci.org/overtrue/easy-sms.svg?branch=master" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/easy-sms"><img src="https://poser.pugx.org/overtrue/easy-sms/v/stable.svg" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/easy-sms"><img src="https://poser.pugx.org/overtrue/easy-sms/v/unstable.svg" alt="Latest Unstable Version"></a>
|
||||
<a href="https://scrutinizer-ci.com/g/overtrue/easy-sms/?branch=master"><img src="https://scrutinizer-ci.com/g/overtrue/easy-sms/badges/quality-score.png?b=master" alt="Scrutinizer Code Quality"></a>
|
||||
<a href="https://scrutinizer-ci.com/g/overtrue/easy-sms/?branch=master"><img src="https://scrutinizer-ci.com/g/overtrue/easy-sms/badges/coverage.png?b=master" alt="Code Coverage"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/easy-sms"><img src="https://poser.pugx.org/overtrue/easy-sms/downloads" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/easy-sms"><img src="https://poser.pugx.org/overtrue/easy-sms/license" alt="License"></a>
|
||||
</p>
|
||||
|
||||
|
||||
## 特点
|
||||
|
||||
1. 支持目前市面多家服务商
|
||||
1. 一套写法兼容所有平台
|
||||
1. 简单配置即可灵活增减服务商
|
||||
1. 内置多种服务商轮询策略、支持自定义轮询策略
|
||||
1. 统一的返回值格式,便于日志与监控
|
||||
1. 自动轮询选择可用的服务商
|
||||
1. 更多等你去发现与改进...
|
||||
|
||||
## 平台支持
|
||||
|
||||
- [阿里云](https://www.aliyun.com/)
|
||||
- [云片](https://www.yunpian.com)
|
||||
- [Submail](https://www.mysubmail.com)
|
||||
- [螺丝帽](https://luosimao.com/)
|
||||
- [容联云通讯](http://www.yuntongxun.com)
|
||||
- [互亿无线](http://www.ihuyi.com)
|
||||
- [聚合数据](https://www.juhe.cn)
|
||||
- [SendCloud](http://www.sendcloud.net/)
|
||||
- [百度云](https://cloud.baidu.com/)
|
||||
- [华信短信平台](http://www.ipyy.com/)
|
||||
- [253云通讯(创蓝)](https://www.253.com/)
|
||||
- [融云](http://www.rongcloud.cn)
|
||||
- [天毅无线](http://www.85hu.com/)
|
||||
- [腾讯云 SMS](https://cloud.tencent.com/product/sms)
|
||||
- [阿凡达数据](http://www.avatardata.cn/)
|
||||
- [华为云](https://www.huaweicloud.com/product/msgsms.html)
|
||||
- [网易云信](https://yunxin.163.com/sms)
|
||||
- [云之讯](https://www.ucpaas.com/index.html)
|
||||
- [凯信通](http://www.kingtto.cn/)
|
||||
- [七牛云](https://www.qiniu.com/)
|
||||
- [UE35.net](http://uesms.ue35.cn/)
|
||||
- [Ucloud](https://www.ucloud.cn)
|
||||
- [短信宝](http://www.smsbao.com/)
|
||||
- [Tiniyo](https://tiniyo.com/)
|
||||
- [摩杜云](https://www.moduyun.com/)
|
||||
|
||||
## 环境需求
|
||||
|
||||
- PHP >= 5.6
|
||||
|
||||
## 安装
|
||||
|
||||
```shell
|
||||
$ composer require "overtrue/easy-sms"
|
||||
```
|
||||
|
||||
**For Laravel notification**
|
||||
|
||||
如果你喜欢使用 [Laravel Notification](https://laravel.com/docs/5.8/notifications), 可以考虑直接使用朋友封装的拓展包:
|
||||
|
||||
https://github.com/yl/easysms-notification-channel
|
||||
|
||||
## 使用
|
||||
|
||||
```php
|
||||
use Overtrue\EasySms\EasySms;
|
||||
|
||||
$config = [
|
||||
// HTTP 请求的超时时间(秒)
|
||||
'timeout' => 5.0,
|
||||
|
||||
// 默认发送配置
|
||||
'default' => [
|
||||
// 网关调用策略,默认:顺序调用
|
||||
'strategy' => \Overtrue\EasySms\Strategies\OrderStrategy::class,
|
||||
|
||||
// 默认可用的发送网关
|
||||
'gateways' => [
|
||||
'yunpian', 'aliyun',
|
||||
],
|
||||
],
|
||||
// 可用的网关配置
|
||||
'gateways' => [
|
||||
'errorlog' => [
|
||||
'file' => '/tmp/easy-sms.log',
|
||||
],
|
||||
'yunpian' => [
|
||||
'api_key' => '824f0ff2f71cab52936axxxxxxxxxx',
|
||||
],
|
||||
'aliyun' => [
|
||||
'access_key_id' => '',
|
||||
'access_key_secret' => '',
|
||||
'sign_name' => '',
|
||||
],
|
||||
//...
|
||||
],
|
||||
];
|
||||
|
||||
$easySms = new EasySms($config);
|
||||
|
||||
$easySms->send(13188888888, [
|
||||
'content' => '您的验证码为: 6379',
|
||||
'template' => 'SMS_001',
|
||||
'data' => [
|
||||
'code' => 6379
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
## 短信内容
|
||||
|
||||
由于使用多网关发送,所以一条短信要支持多平台发送,每家的发送方式不一样,但是我们抽象定义了以下公用属性:
|
||||
|
||||
- `content` 文字内容,使用在像云片类似的以文字内容发送的平台
|
||||
- `template` 模板 ID,使用在以模板ID来发送短信的平台
|
||||
- `data` 模板变量,使用在以模板ID来发送短信的平台
|
||||
|
||||
所以,在使用过程中你可以根据所要使用的平台定义发送的内容。
|
||||
|
||||
```php
|
||||
$easySms->send(13188888888, [
|
||||
'content' => '您的验证码为: 6379',
|
||||
'template' => 'SMS_001',
|
||||
'data' => [
|
||||
'code' => 6379
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
你也可以使用闭包来返回对应的值:
|
||||
|
||||
```php
|
||||
$easySms->send(13188888888, [
|
||||
'content' => function($gateway){
|
||||
return '您的验证码为: 6379';
|
||||
},
|
||||
'template' => function($gateway){
|
||||
return 'SMS_001';
|
||||
},
|
||||
'data' => function($gateway){
|
||||
return [
|
||||
'code' => 6379
|
||||
];
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
你可以根据 `$gateway` 参数类型来判断返回值,例如:
|
||||
|
||||
```php
|
||||
$easySms->send(13188888888, [
|
||||
'content' => function($gateway){
|
||||
if ($gateway->getName() == 'yunpian') {
|
||||
return '云片专用验证码:1235';
|
||||
}
|
||||
return '您的验证码为: 6379';
|
||||
},
|
||||
'template' => function($gateway){
|
||||
if ($gateway->getName() == 'aliyun') {
|
||||
return 'TP2818';
|
||||
}
|
||||
return 'SMS_001';
|
||||
},
|
||||
'data' => function($gateway){
|
||||
return [
|
||||
'code' => 6379
|
||||
];
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
## 发送网关
|
||||
|
||||
默认使用 `default` 中的设置来发送,如果某一条短信你想要覆盖默认的设置。在 `send` 方法中使用第三个参数即可:
|
||||
|
||||
```php
|
||||
$easySms->send(13188888888, [
|
||||
'content' => '您的验证码为: 6379',
|
||||
'template' => 'SMS_001',
|
||||
'data' => [
|
||||
'code' => 6379
|
||||
],
|
||||
], ['yunpian', 'juhe']); // 这里的网关配置将会覆盖全局默认值
|
||||
```
|
||||
|
||||
## 返回值
|
||||
|
||||
由于使用多网关发送,所以返回值为一个数组,结构如下:
|
||||
```php
|
||||
[
|
||||
'yunpian' => [
|
||||
'gateway' => 'yunpian',
|
||||
'status' => 'success',
|
||||
'result' => [...] // 平台返回值
|
||||
],
|
||||
'juhe' => [
|
||||
'gateway' => 'juhe',
|
||||
'status' => 'failure',
|
||||
'exception' => \Overtrue\EasySms\Exceptions\GatewayErrorException 对象
|
||||
],
|
||||
//...
|
||||
]
|
||||
```
|
||||
|
||||
如果所选网关列表均发送失败时,将会抛出 `Overtrue\EasySms\Exceptions\NoGatewayAvailableException` 异常,你可以使用 `$e->results` 获取发送结果。
|
||||
|
||||
你也可以使用 `$e` 提供的更多便捷方法:
|
||||
|
||||
```php
|
||||
$e->getResults(); // 返回所有 API 的结果,结构同上
|
||||
$e->getExceptions(); // 返回所有调用异常列表
|
||||
$e->getException($gateway); // 返回指定网关名称的异常对象
|
||||
$e->getLastException(); // 获取最后一个失败的异常对象
|
||||
```
|
||||
|
||||
## 自定义网关
|
||||
|
||||
本拓展已经支持用户自定义网关,你可以很方便的配置即可当成与其它拓展一样的使用:
|
||||
|
||||
```php
|
||||
$config = [
|
||||
...
|
||||
'default' => [
|
||||
'gateways' => [
|
||||
'mygateway', // 配置你的网站到可用的网关列表
|
||||
],
|
||||
],
|
||||
'gateways' => [
|
||||
'mygateway' => [...], // 你网关所需要的参数,如果没有可以不配置
|
||||
],
|
||||
];
|
||||
|
||||
$easySms = new EasySms($config);
|
||||
|
||||
// 注册
|
||||
$easySms->extend('mygateway', function($gatewayConfig){
|
||||
// $gatewayConfig 来自配置文件里的 `gateways.mygateway`
|
||||
return new MyGateway($gatewayConfig);
|
||||
});
|
||||
|
||||
$easySms->send(13188888888, [
|
||||
'content' => '您的验证码为: 6379',
|
||||
'template' => 'SMS_001',
|
||||
'data' => [
|
||||
'code' => 6379
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
## 国际短信
|
||||
|
||||
国际短信与国内短信的区别是号码前面需要加国际码,但是由于各平台对国际号码的写法不一致,所以在发送国际短信的时候有一点区别:
|
||||
|
||||
```php
|
||||
use Overtrue\EasySms\PhoneNumber;
|
||||
|
||||
// 发送到国际码为 31 的国际号码
|
||||
$number = new PhoneNumber(13188888888, 31);
|
||||
|
||||
$easySms->send($number, [
|
||||
'content' => '您的验证码为: 6379',
|
||||
'template' => 'SMS_001',
|
||||
'data' => [
|
||||
'code' => 6379
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
## 定义短信
|
||||
|
||||
你可以根据发送场景的不同,定义不同的短信类,从而实现一处定义多处调用,你可以继承 `Overtrue\EasySms\Message` 来定义短信模型:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Overtrue\EasySms\Message;
|
||||
use Overtrue\EasySms\Contracts\GatewayInterface;
|
||||
use Overtrue\EasySms\Strategies\OrderStrategy;
|
||||
|
||||
class OrderPaidMessage extends Message
|
||||
{
|
||||
protected $order;
|
||||
protected $strategy = OrderStrategy::class; // 定义本短信的网关使用策略,覆盖全局配置中的 `default.strategy`
|
||||
protected $gateways = ['alidayu', 'yunpian', 'juhe']; // 定义本短信的适用平台,覆盖全局配置中的 `default.gateways`
|
||||
|
||||
public function __construct($order)
|
||||
{
|
||||
$this->order = $order;
|
||||
}
|
||||
|
||||
// 定义直接使用内容发送平台的内容
|
||||
public function getContent(GatewayInterface $gateway = null)
|
||||
{
|
||||
return sprintf('您的订单:%s, 已经完成付款', $this->order->no);
|
||||
}
|
||||
|
||||
// 定义使用模板发送方式平台所需要的模板 ID
|
||||
public function getTemplate(GatewayInterface $gateway = null)
|
||||
{
|
||||
return 'SMS_003';
|
||||
}
|
||||
|
||||
// 模板参数
|
||||
public function getData(GatewayInterface $gateway = null)
|
||||
{
|
||||
return [
|
||||
'order_no' => $this->order->no
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 更多自定义方式请参考:[`Overtrue\EasySms\Message`](Overtrue\EasySms\Message;)
|
||||
|
||||
发送自定义短信:
|
||||
|
||||
```php
|
||||
$order = ...;
|
||||
$message = new OrderPaidMessage($order);
|
||||
|
||||
$easySms->send(13188888888, $message);
|
||||
```
|
||||
|
||||
## 各平台配置说明
|
||||
|
||||
### [阿里云](https://www.aliyun.com/)
|
||||
|
||||
短信内容使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'aliyun' => [
|
||||
'access_key_id' => '',
|
||||
'access_key_secret' => '',
|
||||
'sign_name' => '',
|
||||
],
|
||||
```
|
||||
|
||||
### [阿里云Rest](https://www.aliyun.com/)
|
||||
|
||||
短信内容使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'aliyunrest' => [
|
||||
'app_key' => '',
|
||||
'app_secret_key' => '',
|
||||
'sign_name' => '',
|
||||
],
|
||||
```
|
||||
|
||||
### [云片](https://www.yunpian.com)
|
||||
|
||||
短信内容使用 `content`
|
||||
|
||||
```php
|
||||
'yunpian' => [
|
||||
'api_key' => '',
|
||||
'signature' => '【默认签名】', // 内容中无签名时使用
|
||||
],
|
||||
```
|
||||
|
||||
### [Submail](https://www.mysubmail.com)
|
||||
|
||||
短信内容使用 `data`
|
||||
|
||||
```php
|
||||
'submail' => [
|
||||
'app_id' => '',
|
||||
'app_key' => '',
|
||||
'project' => '', // 默认 project,可在发送时 data 中指定
|
||||
],
|
||||
```
|
||||
|
||||
### [螺丝帽](https://luosimao.com/)
|
||||
|
||||
短信内容使用 `content`
|
||||
|
||||
```php
|
||||
'luosimao' => [
|
||||
'api_key' => '',
|
||||
],
|
||||
```
|
||||
|
||||
### [容联云通讯](http://www.yuntongxun.com)
|
||||
|
||||
短信内容使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'yuntongxun' => [
|
||||
'app_id' => '',
|
||||
'account_sid' => '',
|
||||
'account_token' => '',
|
||||
'is_sub_account' => false,
|
||||
],
|
||||
```
|
||||
|
||||
### [互亿无线](http://www.ihuyi.com)
|
||||
|
||||
短信内容使用 `content`
|
||||
|
||||
```php
|
||||
'huyi' => [
|
||||
'api_id' => '',
|
||||
'api_key' => '',
|
||||
'signature' => '',
|
||||
],
|
||||
```
|
||||
|
||||
### [聚合数据](https://www.juhe.cn)
|
||||
|
||||
短信内容使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'juhe' => [
|
||||
'app_key' => '',
|
||||
],
|
||||
```
|
||||
|
||||
### [SendCloud](http://www.sendcloud.net/)
|
||||
|
||||
短信内容使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'sendcloud' => [
|
||||
'sms_user' => '',
|
||||
'sms_key' => '',
|
||||
'timestamp' => false, // 是否启用时间戳
|
||||
],
|
||||
```
|
||||
### [百度云](https://cloud.baidu.com/)
|
||||
|
||||
短信内容使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'baidu' => [
|
||||
'ak' => '',
|
||||
'sk' => '',
|
||||
'invoke_id' => '',
|
||||
'domain' => '',
|
||||
],
|
||||
```
|
||||
|
||||
### [华信短信平台](http://www.ipyy.com/)
|
||||
|
||||
短信内容使用 `content`
|
||||
|
||||
```php
|
||||
'huaxin' => [
|
||||
'user_id' => '',
|
||||
'password' => '',
|
||||
'account' => '',
|
||||
'ip' => '',
|
||||
'ext_no' => '',
|
||||
],
|
||||
```
|
||||
|
||||
### [253云通讯(创蓝)](https://www.253.com/)
|
||||
|
||||
短信内容使用 `content`
|
||||
|
||||
```php
|
||||
'chuanglan' => [
|
||||
'account' => '',
|
||||
'password' => '',
|
||||
|
||||
// 国际短信时必填
|
||||
'intel_account' => '',
|
||||
'intel_password' => '',
|
||||
|
||||
// \Overtrue\EasySms\Gateways\ChuanglanGateway::CHANNEL_VALIDATE_CODE => 验证码通道(默认)
|
||||
// \Overtrue\EasySms\Gateways\ChuanglanGateway::CHANNEL_PROMOTION_CODE => 会员营销通道
|
||||
'channel' => \Overtrue\EasySms\Gateways\ChuanglanGateway::CHANNEL_VALIDATE_CODE,
|
||||
|
||||
// 会员营销通道 特定参数。创蓝规定:api提交营销短信的时候,需要自己加短信的签名及退订信息
|
||||
'sign' => '【通讯云】',
|
||||
'unsubscribe' => '回TD退订',
|
||||
],
|
||||
```
|
||||
|
||||
### [融云](http://www.rongcloud.cn)
|
||||
|
||||
短信分为两大类,验证类和通知类短信。 发送验证类短信使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'rongcloud' => [
|
||||
'app_key' => '',
|
||||
'app_secret' => '',
|
||||
]
|
||||
```
|
||||
|
||||
### [天毅无线](http://www.85hu.com/)
|
||||
|
||||
短信内容使用 `content`
|
||||
|
||||
```php
|
||||
'tianyiwuxian' => [
|
||||
'username' => '', //用户名
|
||||
'password' => '', //密码
|
||||
'gwid' => '', //网关ID
|
||||
]
|
||||
```
|
||||
|
||||
### [twilio](https://www.twilio.com)
|
||||
|
||||
短信使用 `content`
|
||||
发送对象需要 使用`+`添加区号
|
||||
|
||||
```php
|
||||
'twilio' => [
|
||||
'account_sid' => '', // sid
|
||||
'from' => '', // 发送的号码 可以在控制台购买
|
||||
'token' => '', // apitoken
|
||||
],
|
||||
```
|
||||
|
||||
### [tiniyo](https://www.tiniyo.com)
|
||||
|
||||
短信使用 `content`
|
||||
发送对象需要 使用`+`添加区号
|
||||
|
||||
```php
|
||||
'tiniyo' => [
|
||||
'account_sid' => '', // auth_id from https://tiniyo.com
|
||||
'from' => '', // 发送的号码 可以在控制台购买
|
||||
'token' => '', // auth_secret from https://tiniyo.com
|
||||
],
|
||||
```
|
||||
|
||||
|
||||
### [腾讯云 SMS](https://cloud.tencent.com/product/sms)
|
||||
|
||||
短信内容使用 `content`
|
||||
|
||||
```php
|
||||
'qcloud' => [
|
||||
'sdk_app_id' => '', // SDK APP ID
|
||||
'app_key' => '', // APP KEY
|
||||
'sign_name' => '', // 短信签名,如果使用默认签名,该字段可缺省(对应官方文档中的sign)
|
||||
],
|
||||
```
|
||||
|
||||
发送示例:
|
||||
|
||||
```php
|
||||
$easySms->send(18888888888, [
|
||||
'template' => 101234, // 模板ID
|
||||
'content' => "您的动态验证码为:{1},请于5分钟内完成验证,如非本人操作,请忽略本短信!", // 模板内容
|
||||
'data' => [
|
||||
$code, // 模板变量
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
### [阿凡达数据](http://www.avatardata.cn/)
|
||||
|
||||
短信内容使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'avatardata' => [
|
||||
'app_key' => '', // APP KEY
|
||||
],
|
||||
```
|
||||
|
||||
### [华为云 SMS](https://www.huaweicloud.com/product/msgsms.html)
|
||||
|
||||
短信内容使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'huawei' => [
|
||||
'endpoint' => '', // APP接入地址
|
||||
'app_key' => '', // APP KEY
|
||||
'app_secret' => '', // APP SECRET
|
||||
'from' => [
|
||||
'default' => '1069012345', // 默认使用签名通道号
|
||||
'custom' => 'csms12345', // 其他签名通道号 可以在 data 中定义 from 来指定
|
||||
'abc' => 'csms67890', // 其他签名通道号
|
||||
...
|
||||
],
|
||||
'callback' => '' // 短信状态回调地址
|
||||
],
|
||||
```
|
||||
|
||||
使用默认签名通道 `default`
|
||||
|
||||
```php
|
||||
$easySms->send(13188888888, [
|
||||
'template' => 'SMS_001',
|
||||
'data' => [
|
||||
6379
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
使用指定签名通道
|
||||
|
||||
```php
|
||||
$easySms->send(13188888888, [
|
||||
'template' => 'SMS_001',
|
||||
'data' => [
|
||||
6379,
|
||||
'from' => 'custom' // 对应 config 中的 from 数组中 custom
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
### [网易云信](https://yunxin.163.com/sms)
|
||||
|
||||
短信内容使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'yunxin' => [
|
||||
'app_key' => '',
|
||||
'app_secret' => '',
|
||||
'code_length' => 4, // 随机验证码长度,范围 4~10,默认为 4
|
||||
'need_up' => false, // 是否需要支持短信上行
|
||||
],
|
||||
```
|
||||
|
||||
```php
|
||||
$easySms->send(18888888888, [
|
||||
'template' => 'SMS_001', // 不填则使用默认模板
|
||||
'data' => [
|
||||
'code' => 8946, // 如果设置了该参数,则 code_length 参数无效
|
||||
'action' => 'sendCode', // 默认为 `sendCode`,校验短信验证码使用 `verifyCode`
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
### [云之讯](https://www.ucpaas.com/index.html)
|
||||
|
||||
短信内容使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'yunzhixun' => [
|
||||
'sid' => '',
|
||||
'token' => '',
|
||||
'app_id' => '',
|
||||
],
|
||||
```
|
||||
|
||||
```php
|
||||
$easySms->send(18888888888, [
|
||||
'template' => 'SMS_001',
|
||||
'data' => [
|
||||
'params' => '8946,3', // 模板参数,多个参数使用 `,` 分割,模板无参数时可为空
|
||||
'uid' => 'hexianghui', // 用户 ID,随状态报告返回,可为空
|
||||
'mobiles' => '18888888888,188888888889', // 批量发送短信,手机号使用 `,` 分割,不使用批量发送请不要设置该参数
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
### [凯信通](http://www.kingtto.cn/)
|
||||
|
||||
短信内容使用 `content`
|
||||
|
||||
```php
|
||||
'kingtto' => [
|
||||
'userid' => '',
|
||||
'account' => '',
|
||||
'password' => '',
|
||||
],
|
||||
```
|
||||
|
||||
```php
|
||||
$easySms->send(18888888888, [
|
||||
'content' => '您的验证码为: 6379',
|
||||
]);
|
||||
```
|
||||
|
||||
### [七牛云](https://www.qiniu.com/)
|
||||
|
||||
短信内容使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'qiniu' => [
|
||||
'secret_key' => '',
|
||||
'access_key' => '',
|
||||
],
|
||||
```
|
||||
|
||||
```php
|
||||
$easySms->send(18888888888, [
|
||||
'template' => '1231234123412341234',
|
||||
'data' => [
|
||||
'code' => 1234,
|
||||
],
|
||||
]);
|
||||
```
|
||||
### [Ucloud](https://www.ucloud.cn/)
|
||||
短信使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'ucloud' => [
|
||||
'private_key' => '', //私钥
|
||||
'public_key' => '', //公钥
|
||||
’sig_content‘ => '', // 短信签名,
|
||||
'project_id' => '', //项目ID,子账号才需要该参数
|
||||
],
|
||||
```
|
||||
|
||||
```php
|
||||
$easySms->send(18888888888, [
|
||||
'template' => 'UTAXXXXX', //短信模板
|
||||
'data' => [
|
||||
'code' => 1234, //模板参数,模板没有参数不用则填写,有多个参数请用数组,[1111,1111]
|
||||
'mobiles' =>'', //同时发送多个手机短信,请用数组[xxx,xxx]
|
||||
],
|
||||
]);
|
||||
|
||||
```
|
||||
|
||||
|
||||
### [短信宝](http://www.smsbao.com/)
|
||||
短信使用 `template`
|
||||
|
||||
```php
|
||||
'smsbao' => [
|
||||
'user' => '', //账号
|
||||
'password' => '' //密码
|
||||
],
|
||||
```
|
||||
|
||||
```php
|
||||
$easySms->send(18888888888, [
|
||||
'template' => '您的验证码为: 6379', //短信模板
|
||||
]);
|
||||
|
||||
```
|
||||
|
||||
### [摩杜云](https://www.moduyun.com/)
|
||||
短信使用 `template` + `data`
|
||||
|
||||
```php
|
||||
'moduyun' => [
|
||||
'accesskey' => '', //必填 ACCESS KEY
|
||||
'secretkey' => '', //必填 SECRET KEY
|
||||
'signId' => '', //选填 短信签名,如果使用默认签名,该字段可缺省
|
||||
'type' => 0, //选填 0:普通短信;1:营销短信
|
||||
],
|
||||
```
|
||||
|
||||
```php
|
||||
$easySms->send(18888888888, [
|
||||
'template' => '5a95****b953', //短信模板
|
||||
'data' => [
|
||||
1234, //模板参数,对应模板的{1}
|
||||
30 //模板参数,对应模板的{2}
|
||||
//...
|
||||
],
|
||||
]);
|
||||
|
||||
```
|
||||
|
||||
## PHP 扩展包开发
|
||||
|
||||
> 想知道如何从零开始构建 PHP 扩展包?
|
||||
>
|
||||
> 请关注我的实战课程,我会在此课程中分享一些扩展开发经验 —— [《PHP 扩展包实战教程 - 从入门到发布》](https://learnku.com/courses/creating-package)
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
29
vendor/overtrue/easy-sms/composer.json
vendored
Executable file
29
vendor/overtrue/easy-sms/composer.json
vendored
Executable file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "overtrue/easy-sms",
|
||||
"description": "The easiest way to send short message.",
|
||||
"type": "library",
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^6.2 || ^7.0",
|
||||
"php": ">=5.6",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7 || ^7.5",
|
||||
"mockery/mockery": "1.3.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Overtrue\\EasySms\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Overtrue\\EasySms\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"license": "MIT",
|
||||
"authors": [{
|
||||
"name": "overtrue",
|
||||
"email": "i@overtrue.me"
|
||||
}]
|
||||
}
|
||||
38
vendor/overtrue/easy-sms/src/Contracts/GatewayInterface.php
vendored
Executable file
38
vendor/overtrue/easy-sms/src/Contracts/GatewayInterface.php
vendored
Executable file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Contracts;
|
||||
|
||||
use Overtrue\EasySms\Support\Config;
|
||||
|
||||
/**
|
||||
* Class GatewayInterface.
|
||||
*/
|
||||
interface GatewayInterface
|
||||
{
|
||||
/**
|
||||
* Get gateway name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Send a short message.
|
||||
*
|
||||
* @param \Overtrue\EasySms\Contracts\PhoneNumberInterface $to
|
||||
* @param \Overtrue\EasySms\Contracts\MessageInterface $message
|
||||
* @param \Overtrue\EasySms\Support\Config $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config);
|
||||
}
|
||||
63
vendor/overtrue/easy-sms/src/Contracts/MessageInterface.php
vendored
Executable file
63
vendor/overtrue/easy-sms/src/Contracts/MessageInterface.php
vendored
Executable file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Contracts;
|
||||
|
||||
/**
|
||||
* Interface MessageInterface.
|
||||
*/
|
||||
interface MessageInterface
|
||||
{
|
||||
const TEXT_MESSAGE = 'text';
|
||||
|
||||
const VOICE_MESSAGE = 'voice';
|
||||
|
||||
/**
|
||||
* Return the message type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMessageType();
|
||||
|
||||
/**
|
||||
* Return message content.
|
||||
*
|
||||
* @param \Overtrue\EasySms\Contracts\GatewayInterface|null $gateway
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(GatewayInterface $gateway = null);
|
||||
|
||||
/**
|
||||
* Return the template id of message.
|
||||
*
|
||||
* @param \Overtrue\EasySms\Contracts\GatewayInterface|null $gateway
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTemplate(GatewayInterface $gateway = null);
|
||||
|
||||
/**
|
||||
* Return the template data of message.
|
||||
*
|
||||
* @param \Overtrue\EasySms\Contracts\GatewayInterface|null $gateway
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getData(GatewayInterface $gateway = null);
|
||||
|
||||
/**
|
||||
* Return message supported gateways.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGateways();
|
||||
}
|
||||
53
vendor/overtrue/easy-sms/src/Contracts/PhoneNumberInterface.php
vendored
Executable file
53
vendor/overtrue/easy-sms/src/Contracts/PhoneNumberInterface.php
vendored
Executable file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Contracts;
|
||||
|
||||
/**
|
||||
* Interface PhoneNumberInterface.
|
||||
*
|
||||
* @author overtrue <i@overtrue.me>
|
||||
*/
|
||||
interface PhoneNumberInterface extends \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* 86.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getIDDCode();
|
||||
|
||||
/**
|
||||
* 18888888888.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumber();
|
||||
|
||||
/**
|
||||
* +8618888888888.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUniversalNumber();
|
||||
|
||||
/**
|
||||
* 008618888888888.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getZeroPrefixedNumber();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString();
|
||||
}
|
||||
27
vendor/overtrue/easy-sms/src/Contracts/StrategyInterface.php
vendored
Executable file
27
vendor/overtrue/easy-sms/src/Contracts/StrategyInterface.php
vendored
Executable file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Contracts;
|
||||
|
||||
/**
|
||||
* Interface StrategyInterface.
|
||||
*/
|
||||
interface StrategyInterface
|
||||
{
|
||||
/**
|
||||
* Apply the strategy and return result.
|
||||
*
|
||||
* @param array $gateways
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function apply(array $gateways);
|
||||
}
|
||||
327
vendor/overtrue/easy-sms/src/EasySms.php
vendored
Executable file
327
vendor/overtrue/easy-sms/src/EasySms.php
vendored
Executable file
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms;
|
||||
|
||||
use Closure;
|
||||
use Overtrue\EasySms\Contracts\GatewayInterface;
|
||||
use Overtrue\EasySms\Contracts\MessageInterface;
|
||||
use Overtrue\EasySms\Contracts\PhoneNumberInterface;
|
||||
use Overtrue\EasySms\Contracts\StrategyInterface;
|
||||
use Overtrue\EasySms\Exceptions\InvalidArgumentException;
|
||||
use Overtrue\EasySms\Gateways\Gateway;
|
||||
use Overtrue\EasySms\Strategies\OrderStrategy;
|
||||
use Overtrue\EasySms\Support\Config;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Class EasySms.
|
||||
*/
|
||||
class EasySms
|
||||
{
|
||||
/**
|
||||
* @var \Overtrue\EasySms\Support\Config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $defaultGateway;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $customCreators = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $gateways = [];
|
||||
|
||||
/**
|
||||
* @var \Overtrue\EasySms\Messenger
|
||||
*/
|
||||
protected $messenger;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $strategies = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
{
|
||||
$this->config = new Config($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message.
|
||||
*
|
||||
* @param string|array $to
|
||||
* @param \Overtrue\EasySms\Contracts\MessageInterface|array $message
|
||||
* @param array $gateways
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \Overtrue\EasySms\Exceptions\InvalidArgumentException
|
||||
* @throws \Overtrue\EasySms\Exceptions\NoGatewayAvailableException
|
||||
*/
|
||||
public function send($to, $message, array $gateways = [])
|
||||
{
|
||||
$to = $this->formatPhoneNumber($to);
|
||||
$message = $this->formatMessage($message);
|
||||
$gateways = empty($gateways) ? $message->getGateways() : $gateways;
|
||||
|
||||
if (empty($gateways)) {
|
||||
$gateways = $this->config->get('default.gateways', []);
|
||||
}
|
||||
|
||||
return $this->getMessenger()->send($to, $message, $this->formatGateways($gateways));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a gateway.
|
||||
*
|
||||
* @param string|null $name
|
||||
*
|
||||
* @return \Overtrue\EasySms\Contracts\GatewayInterface
|
||||
*
|
||||
* @throws \Overtrue\EasySms\Exceptions\InvalidArgumentException
|
||||
*/
|
||||
public function gateway($name)
|
||||
{
|
||||
if (!isset($this->gateways[$name])) {
|
||||
$this->gateways[$name] = $this->createGateway($name);
|
||||
}
|
||||
|
||||
return $this->gateways[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a strategy instance.
|
||||
*
|
||||
* @param string|null $strategy
|
||||
*
|
||||
* @return \Overtrue\EasySms\Contracts\StrategyInterface
|
||||
*
|
||||
* @throws \Overtrue\EasySms\Exceptions\InvalidArgumentException
|
||||
*/
|
||||
public function strategy($strategy = null)
|
||||
{
|
||||
if (\is_null($strategy)) {
|
||||
$strategy = $this->config->get('default.strategy', OrderStrategy::class);
|
||||
}
|
||||
|
||||
if (!\class_exists($strategy)) {
|
||||
$strategy = __NAMESPACE__.'\Strategies\\'.\ucfirst($strategy);
|
||||
}
|
||||
|
||||
if (!\class_exists($strategy)) {
|
||||
throw new InvalidArgumentException("Unsupported strategy \"{$strategy}\"");
|
||||
}
|
||||
|
||||
if (empty($this->strategies[$strategy]) || !($this->strategies[$strategy] instanceof StrategyInterface)) {
|
||||
$this->strategies[$strategy] = new $strategy($this);
|
||||
}
|
||||
|
||||
return $this->strategies[$strategy];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom driver creator Closure.
|
||||
*
|
||||
* @param string $name
|
||||
* @param \Closure $callback
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function extend($name, Closure $callback)
|
||||
{
|
||||
$this->customCreators[$name] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Overtrue\EasySms\Support\Config
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Overtrue\EasySms\Messenger
|
||||
*/
|
||||
public function getMessenger()
|
||||
{
|
||||
return $this->messenger ?: $this->messenger = new Messenger($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new driver instance.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return GatewayInterface
|
||||
*
|
||||
* @throws \Overtrue\EasySms\Exceptions\InvalidArgumentException
|
||||
*/
|
||||
protected function createGateway($name)
|
||||
{
|
||||
$config = $this->config->get("gateways.{$name}", []);
|
||||
|
||||
if (!isset($config['timeout'])) {
|
||||
$config['timeout'] = $this->config->get('timeout', Gateway::DEFAULT_TIMEOUT);
|
||||
}
|
||||
|
||||
$config['options'] = $this->config->get('options', []);
|
||||
|
||||
if (isset($this->customCreators[$name])) {
|
||||
$gateway = $this->callCustomCreator($name, $config);
|
||||
} else {
|
||||
$className = $this->formatGatewayClassName($name);
|
||||
$gateway = $this->makeGateway($className, $config);
|
||||
}
|
||||
|
||||
if (!($gateway instanceof GatewayInterface)) {
|
||||
throw new InvalidArgumentException(\sprintf('Gateway "%s" must implement interface %s.', $name, GatewayInterface::class));
|
||||
}
|
||||
|
||||
return $gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make gateway instance.
|
||||
*
|
||||
* @param string $gateway
|
||||
* @param array $config
|
||||
*
|
||||
* @return \Overtrue\EasySms\Contracts\GatewayInterface
|
||||
*
|
||||
* @throws \Overtrue\EasySms\Exceptions\InvalidArgumentException
|
||||
*/
|
||||
protected function makeGateway($gateway, $config)
|
||||
{
|
||||
if (!\class_exists($gateway) || !\in_array(GatewayInterface::class, \class_implements($gateway))) {
|
||||
throw new InvalidArgumentException(\sprintf('Class "%s" is a invalid easy-sms gateway.', $gateway));
|
||||
}
|
||||
|
||||
return new $gateway($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format gateway name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function formatGatewayClassName($name)
|
||||
{
|
||||
if (\class_exists($name) && \in_array(GatewayInterface::class, \class_implements($name))) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
$name = \ucfirst(\str_replace(['-', '_', ''], '', $name));
|
||||
|
||||
return __NAMESPACE__."\\Gateways\\{$name}Gateway";
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a custom gateway creator.
|
||||
*
|
||||
* @param string $gateway
|
||||
* @param array $config
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function callCustomCreator($gateway, $config)
|
||||
{
|
||||
return \call_user_func($this->customCreators[$gateway], $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|\Overtrue\EasySms\Contracts\PhoneNumberInterface $number
|
||||
*
|
||||
* @return \Overtrue\EasySms\Contracts\PhoneNumberInterface|string
|
||||
*/
|
||||
protected function formatPhoneNumber($number)
|
||||
{
|
||||
if ($number instanceof PhoneNumberInterface) {
|
||||
return $number;
|
||||
}
|
||||
|
||||
return new PhoneNumber(\trim($number));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string|\Overtrue\EasySms\Contracts\MessageInterface $message
|
||||
*
|
||||
* @return \Overtrue\EasySms\Contracts\MessageInterface
|
||||
*/
|
||||
protected function formatMessage($message)
|
||||
{
|
||||
if (!($message instanceof MessageInterface)) {
|
||||
if (!\is_array($message)) {
|
||||
$message = [
|
||||
'content' => $message,
|
||||
'template' => $message,
|
||||
];
|
||||
}
|
||||
|
||||
$message = new Message($message);
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $gateways
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \Overtrue\EasySms\Exceptions\InvalidArgumentException
|
||||
*/
|
||||
protected function formatGateways(array $gateways)
|
||||
{
|
||||
$formatted = [];
|
||||
|
||||
foreach ($gateways as $gateway => $setting) {
|
||||
if (\is_int($gateway) && \is_string($setting)) {
|
||||
$gateway = $setting;
|
||||
$setting = [];
|
||||
}
|
||||
|
||||
$formatted[$gateway] = $setting;
|
||||
$globalSettings = $this->config->get("gateways.{$gateway}", []);
|
||||
|
||||
if (\is_string($gateway) && !empty($globalSettings) && \is_array($setting)) {
|
||||
$formatted[$gateway] = new Config(\array_merge($globalSettings, $setting));
|
||||
}
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($this->strategy()->apply($formatted) as $name) {
|
||||
$result[$name] = $formatted[$name];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
21
vendor/overtrue/easy-sms/src/Exceptions/Exception.php
vendored
Executable file
21
vendor/overtrue/easy-sms/src/Exceptions/Exception.php
vendored
Executable file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Exceptions;
|
||||
|
||||
/**
|
||||
* Class Exception.
|
||||
*
|
||||
* @author overtrue <i@overtrue.me>
|
||||
*/
|
||||
class Exception extends \Exception
|
||||
{
|
||||
}
|
||||
37
vendor/overtrue/easy-sms/src/Exceptions/GatewayErrorException.php
vendored
Executable file
37
vendor/overtrue/easy-sms/src/Exceptions/GatewayErrorException.php
vendored
Executable file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Exceptions;
|
||||
|
||||
/**
|
||||
* Class GatewayErrorException.
|
||||
*/
|
||||
class GatewayErrorException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $raw = [];
|
||||
|
||||
/**
|
||||
* GatewayErrorException constructor.
|
||||
*
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param array $raw
|
||||
*/
|
||||
public function __construct($message, $code, array $raw = [])
|
||||
{
|
||||
parent::__construct($message, intval($code));
|
||||
|
||||
$this->raw = $raw;
|
||||
}
|
||||
}
|
||||
19
vendor/overtrue/easy-sms/src/Exceptions/InvalidArgumentException.php
vendored
Executable file
19
vendor/overtrue/easy-sms/src/Exceptions/InvalidArgumentException.php
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Exceptions;
|
||||
|
||||
/**
|
||||
* Class InvalidArgumentException.
|
||||
*/
|
||||
class InvalidArgumentException extends Exception
|
||||
{
|
||||
}
|
||||
81
vendor/overtrue/easy-sms/src/Exceptions/NoGatewayAvailableException.php
vendored
Executable file
81
vendor/overtrue/easy-sms/src/Exceptions/NoGatewayAvailableException.php
vendored
Executable file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Exceptions;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class NoGatewayAvailableException.
|
||||
*
|
||||
* @author overtrue <i@overtrue.me>
|
||||
*/
|
||||
class NoGatewayAvailableException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $results = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $exceptions = [];
|
||||
|
||||
/**
|
||||
* NoGatewayAvailableException constructor.
|
||||
*
|
||||
* @param array $results
|
||||
* @param int $code
|
||||
* @param \Throwable|null $previous
|
||||
*/
|
||||
public function __construct(array $results = [], $code = 0, Throwable $previous = null)
|
||||
{
|
||||
$this->results = $results;
|
||||
$this->exceptions = \array_column($results, 'exception', 'gateway');
|
||||
|
||||
parent::__construct('All the gateways have failed. You can get error details by `$exception->getExceptions()`', $code, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getResults()
|
||||
{
|
||||
return $this->results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $gateway
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getException($gateway)
|
||||
{
|
||||
return isset($this->exceptions[$gateway]) ? $this->exceptions[$gateway] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getExceptions()
|
||||
{
|
||||
return $this->exceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLastException()
|
||||
{
|
||||
return end($this->exceptions);
|
||||
}
|
||||
}
|
||||
104
vendor/overtrue/easy-sms/src/Gateways/AliyunGateway.php
vendored
Executable file
104
vendor/overtrue/easy-sms/src/Gateways/AliyunGateway.php
vendored
Executable file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 AliyunGateway.
|
||||
*
|
||||
* @author carson <docxcn@gmail.com>
|
||||
*
|
||||
* @see https://help.aliyun.com/document_detail/55451.html
|
||||
*/
|
||||
class AliyunGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'http://dysmsapi.aliyuncs.com';
|
||||
|
||||
const ENDPOINT_METHOD = 'SendSms';
|
||||
|
||||
const ENDPOINT_VERSION = '2017-05-25';
|
||||
|
||||
const ENDPOINT_FORMAT = 'JSON';
|
||||
|
||||
const ENDPOINT_REGION_ID = 'cn-hangzhou';
|
||||
|
||||
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(),
|
||||
'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
|
||||
'Action' => self::ENDPOINT_METHOD,
|
||||
'Version' => self::ENDPOINT_VERSION,
|
||||
'PhoneNumbers' => !\is_null($to->getIDDCode()) ? strval($to->getZeroPrefixedNumber()) : $to->getNumber(),
|
||||
'SignName' => $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['Code']) {
|
||||
throw new GatewayErrorException($result['Message'], $result['Code'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Sign.
|
||||
*
|
||||
* @param array $params
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateSign($params)
|
||||
{
|
||||
ksort($params);
|
||||
$accessKeySecret = $this->config->get('access_key_secret');
|
||||
$stringToSign = 'GET&%2F&'.urlencode(http_build_query($params, null, '&', PHP_QUERY_RFC3986));
|
||||
|
||||
return base64_encode(hash_hmac('sha1', $stringToSign, $accessKeySecret.'&', true));
|
||||
}
|
||||
}
|
||||
107
vendor/overtrue/easy-sms/src/Gateways/AliyunrestGateway.php
vendored
Executable file
107
vendor/overtrue/easy-sms/src/Gateways/AliyunrestGateway.php
vendored
Executable file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 AliyunrestGateway.
|
||||
*/
|
||||
class AliyunrestGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'http://gw.api.taobao.com/router/rest';
|
||||
|
||||
const ENDPOINT_VERSION = '2.0';
|
||||
|
||||
const ENDPOINT_FORMAT = 'json';
|
||||
|
||||
const ENDPOINT_METHOD = 'alibaba.aliqin.fc.sms.num.send';
|
||||
|
||||
const ENDPOINT_SIGNATURE_METHOD = 'md5';
|
||||
|
||||
const ENDPOINT_PARTNER_ID = 'EasySms';
|
||||
|
||||
/**
|
||||
* @param PhoneNumberInterface $to
|
||||
* @param MessageInterface $message
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array|void
|
||||
*/
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$urlParams = [
|
||||
'app_key' => $config->get('app_key'),
|
||||
'v' => self::ENDPOINT_VERSION,
|
||||
'format' => self::ENDPOINT_FORMAT,
|
||||
'sign_method' => self::ENDPOINT_SIGNATURE_METHOD,
|
||||
'method' => self::ENDPOINT_METHOD,
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'partner_id' => self::ENDPOINT_PARTNER_ID,
|
||||
];
|
||||
|
||||
$params = [
|
||||
'extend' => '',
|
||||
'sms_type' => 'normal',
|
||||
'sms_free_sign_name' => $config->get('sign_name'),
|
||||
'sms_param' => json_encode($message->getData($this)),
|
||||
'rec_num' => !\is_null($to->getIDDCode()) ? strval($to->getZeroPrefixedNumber()) : $to->getNumber(),
|
||||
'sms_template_code' => $message->getTemplate($this),
|
||||
];
|
||||
$urlParams['sign'] = $this->generateSign(array_merge($params, $urlParams));
|
||||
|
||||
$result = $this->post($this->getEndpointUrl($urlParams), $params);
|
||||
|
||||
if (isset($result['error_response']) && 0 != $result['error_response']['code']) {
|
||||
throw new GatewayErrorException($result['error_response']['msg'], $result['error_response']['code'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getEndpointUrl($params)
|
||||
{
|
||||
return self::ENDPOINT_URL.'?'.http_build_query($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateSign($params)
|
||||
{
|
||||
ksort($params);
|
||||
|
||||
$stringToBeSigned = $this->config->get('app_secret_key');
|
||||
foreach ($params as $k => $v) {
|
||||
if (!is_array($v) && '@' != substr($v, 0, 1)) {
|
||||
$stringToBeSigned .= "$k$v";
|
||||
}
|
||||
}
|
||||
unset($k, $v);
|
||||
$stringToBeSigned .= $this->config->get('app_secret_key');
|
||||
|
||||
return strtoupper(md5($stringToBeSigned));
|
||||
}
|
||||
}
|
||||
60
vendor/overtrue/easy-sms/src/Gateways/AvatardataGateway.php
vendored
Executable file
60
vendor/overtrue/easy-sms/src/Gateways/AvatardataGateway.php
vendored
Executable file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 AvatardataGateway.
|
||||
*
|
||||
* @see http://www.avatardata.cn/Docs/Api/fd475e40-7809-4be7-936c-5926dd41b0fe
|
||||
*/
|
||||
class AvatardataGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'http://v1.avatardata.cn/Sms/Send';
|
||||
|
||||
const ENDPOINT_FORMAT = 'json';
|
||||
|
||||
/**
|
||||
* @param PhoneNumberInterface $to
|
||||
* @param MessageInterface $message
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws GatewayErrorException;
|
||||
*/
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$params = [
|
||||
'mobile' => $to->getNumber(),
|
||||
'templateId' => $message->getTemplate($this),
|
||||
'param' => implode(',', $message->getData($this)),
|
||||
'dtype' => self::ENDPOINT_FORMAT,
|
||||
'key' => $config->get('app_key'),
|
||||
];
|
||||
|
||||
$result = $this->get(self::ENDPOINT_URL, $params);
|
||||
|
||||
if ($result['error_code']) {
|
||||
throw new GatewayErrorException($result['reason'], $result['error_code'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
174
vendor/overtrue/easy-sms/src/Gateways/BaiduGateway.php
vendored
Executable file
174
vendor/overtrue/easy-sms/src/Gateways/BaiduGateway.php
vendored
Executable file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 BaiduGateway.
|
||||
*
|
||||
* @see https://cloud.baidu.com/doc/SMS/index.html
|
||||
*/
|
||||
class BaiduGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_HOST = 'smsv3.bj.baidubce.com';
|
||||
|
||||
const ENDPOINT_URI = '/api/v3/sendSms';
|
||||
|
||||
const BCE_AUTH_VERSION = 'bce-auth-v1';
|
||||
|
||||
const DEFAULT_EXPIRATION_IN_SECONDS = 1800; //签名有效期默认1800秒
|
||||
|
||||
const SUCCESS_CODE = 1000;
|
||||
|
||||
/**
|
||||
* Send message.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
$params = [
|
||||
'signatureId' => $config->get('invoke_id'),
|
||||
'mobile' => $to->getNumber(),
|
||||
'template' => $message->getTemplate($this),
|
||||
'contentVar' => $message->getData($this),
|
||||
];
|
||||
if (!empty($params['contentVar']['custom'])) {
|
||||
//用户自定义参数,格式为字符串,状态回调时会回传该值
|
||||
$params['custom'] = $params['contentVar']['custom'];
|
||||
unset($params['contentVar']['custom']);
|
||||
}
|
||||
if (!empty($params['contentVar']['userExtId'])) {
|
||||
//通道自定义扩展码,上行回调时会回传该值,其格式为纯数字串。默认为不开通,请求时无需设置该参数。如需开通请联系客服申请
|
||||
$params['userExtId'] = $params['contentVar']['userExtId'];
|
||||
unset($params['contentVar']['userExtId']);
|
||||
}
|
||||
|
||||
$datetime = gmdate('Y-m-d\TH:i:s\Z');
|
||||
|
||||
$headers = [
|
||||
'host' => self::ENDPOINT_HOST,
|
||||
'content-type' => 'application/json',
|
||||
'x-bce-date' => $datetime,
|
||||
];
|
||||
//获得需要签名的数据
|
||||
$signHeaders = $this->getHeadersToSign($headers, ['host', 'x-bce-date']);
|
||||
|
||||
$headers['Authorization'] = $this->generateSign($signHeaders, $datetime, $config);
|
||||
|
||||
$result = $this->request('post', self::buildEndpoint($config), ['headers' => $headers, 'json' => $params]);
|
||||
|
||||
if (self::SUCCESS_CODE != $result['code']) {
|
||||
throw new GatewayErrorException($result['message'], $result['code'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build endpoint url.
|
||||
*
|
||||
* @param \Overtrue\EasySms\Support\Config $config
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndpoint(Config $config)
|
||||
{
|
||||
return 'http://'.$config->get('domain', self::ENDPOINT_HOST).self::ENDPOINT_URI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Authorization header.
|
||||
*
|
||||
* @param array $signHeaders
|
||||
* @param int $datetime
|
||||
* @param \Overtrue\EasySms\Support\Config $config
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateSign(array $signHeaders, $datetime, Config $config)
|
||||
{
|
||||
// 生成 authString
|
||||
$authString = self::BCE_AUTH_VERSION.'/'.$config->get('ak').'/'
|
||||
.$datetime.'/'.self::DEFAULT_EXPIRATION_IN_SECONDS;
|
||||
|
||||
// 使用 sk 和 authString 生成 signKey
|
||||
$signingKey = hash_hmac('sha256', $authString, $config->get('sk'));
|
||||
// 生成标准化 URI
|
||||
// 根据 RFC 3986,除了:1.大小写英文字符 2.阿拉伯数字 3.点'.'、波浪线'~'、减号'-'以及下划线'_' 以外都要编码
|
||||
$canonicalURI = str_replace('%2F', '/', rawurlencode(self::ENDPOINT_URI));
|
||||
|
||||
// 生成标准化 QueryString
|
||||
$canonicalQueryString = ''; // 此 api 不需要此项。返回空字符串
|
||||
|
||||
// 整理 headersToSign,以 ';' 号连接
|
||||
$signedHeaders = empty($signHeaders) ? '' : strtolower(trim(implode(';', array_keys($signHeaders))));
|
||||
|
||||
// 生成标准化 header
|
||||
$canonicalHeader = $this->getCanonicalHeaders($signHeaders);
|
||||
|
||||
// 组成标准请求串
|
||||
$canonicalRequest = "POST\n{$canonicalURI}\n{$canonicalQueryString}\n{$canonicalHeader}";
|
||||
|
||||
// 使用 signKey 和标准请求串完成签名
|
||||
$signature = hash_hmac('sha256', $canonicalRequest, $signingKey);
|
||||
|
||||
// 组成最终签名串
|
||||
return "{$authString}/{$signedHeaders}/{$signature}";
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成标准化 http 请求头串.
|
||||
*
|
||||
* @param array $headers
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getCanonicalHeaders(array $headers)
|
||||
{
|
||||
$headerStrings = [];
|
||||
foreach ($headers as $name => $value) {
|
||||
//trim后再encode,之后使用':'号连接起来
|
||||
$headerStrings[] = rawurlencode(strtolower(trim($name))).':'.rawurlencode(trim($value));
|
||||
}
|
||||
|
||||
sort($headerStrings);
|
||||
|
||||
return implode("\n", $headerStrings);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 指定的 keys 过滤应该参与签名的 header.
|
||||
*
|
||||
* @param array $headers
|
||||
* @param array $keys
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getHeadersToSign(array $headers, array $keys)
|
||||
{
|
||||
return array_intersect_key($headers, array_flip($keys));
|
||||
}
|
||||
}
|
||||
156
vendor/overtrue/easy-sms/src/Gateways/ChuanglanGateway.php
vendored
Executable file
156
vendor/overtrue/easy-sms/src/Gateways/ChuanglanGateway.php
vendored
Executable file
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Gateways;
|
||||
|
||||
use Overtrue\EasySms\Contracts\MessageInterface;
|
||||
use Overtrue\EasySms\Contracts\PhoneNumberInterface;
|
||||
use Overtrue\EasySms\Exceptions\GatewayErrorException;
|
||||
use Overtrue\EasySms\Exceptions\InvalidArgumentException;
|
||||
use Overtrue\EasySms\Support\Config;
|
||||
use Overtrue\EasySms\Traits\HasHttpRequest;
|
||||
|
||||
/**
|
||||
* Class ChuanglanGateway.
|
||||
*
|
||||
* @see https://zz.253.com/v5.html#/api_doc
|
||||
*/
|
||||
class ChuanglanGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
/**
|
||||
* URL模板
|
||||
*/
|
||||
const ENDPOINT_URL_TEMPLATE = 'https://%s.253.com/msg/send/json';
|
||||
|
||||
/**
|
||||
* 国际短信
|
||||
*/
|
||||
const INT_URL = 'http://intapi.253.com/send/json';
|
||||
|
||||
/**
|
||||
* 验证码渠道code.
|
||||
*/
|
||||
const CHANNEL_VALIDATE_CODE = 'smsbj1';
|
||||
|
||||
/**
|
||||
* 会员营销渠道code.
|
||||
*/
|
||||
const CHANNEL_PROMOTION_CODE = 'smssh1';
|
||||
|
||||
/**
|
||||
* @param PhoneNumberInterface $to
|
||||
* @param MessageInterface $message
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws GatewayErrorException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$IDDCode = !empty($to->getIDDCode()) ? $to->getIDDCode() : 86;
|
||||
|
||||
$params = [
|
||||
'account' => $config->get('account'),
|
||||
'password' => $config->get('password'),
|
||||
'phone' => $to->getNumber(),
|
||||
'msg' => $this->wrapChannelContent($message->getContent($this), $config, $IDDCode),
|
||||
];
|
||||
|
||||
if (86 != $IDDCode) {
|
||||
$params['mobile'] = $to->getIDDCode().$to->getNumber();
|
||||
$params['account'] = $config->get('intel_account') ?: $config->get('account');
|
||||
$params['password'] = $config->get('intel_password') ?: $config->get('password');
|
||||
}
|
||||
|
||||
$result = $this->postJson($this->buildEndpoint($config, $IDDCode), $params);
|
||||
|
||||
if (!isset($result['code']) || '0' != $result['code']) {
|
||||
throw new GatewayErrorException(json_encode($result, JSON_UNESCAPED_UNICODE), isset($result['code']) ? $result['code'] : 0, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Config $config
|
||||
* @param int $IDDCode
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function buildEndpoint(Config $config, $IDDCode = 86)
|
||||
{
|
||||
$channel = $this->getChannel($config, $IDDCode);
|
||||
|
||||
if (self::INT_URL === $channel) {
|
||||
return $channel;
|
||||
}
|
||||
|
||||
return sprintf(self::ENDPOINT_URL_TEMPLATE, $channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Config $config
|
||||
* @param int $IDDCode
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function getChannel(Config $config, $IDDCode)
|
||||
{
|
||||
if (86 != $IDDCode) {
|
||||
return self::INT_URL;
|
||||
}
|
||||
$channel = $config->get('channel', self::CHANNEL_VALIDATE_CODE);
|
||||
|
||||
if (!in_array($channel, [self::CHANNEL_VALIDATE_CODE, self::CHANNEL_PROMOTION_CODE])) {
|
||||
throw new InvalidArgumentException('Invalid channel for ChuanglanGateway.');
|
||||
}
|
||||
|
||||
return $channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $content
|
||||
* @param Config $config
|
||||
* @param int $IDDCode
|
||||
*
|
||||
* @return string|string
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function wrapChannelContent($content, Config $config, $IDDCode)
|
||||
{
|
||||
$channel = $this->getChannel($config, $IDDCode);
|
||||
|
||||
if (self::CHANNEL_PROMOTION_CODE == $channel) {
|
||||
$sign = (string) $config->get('sign', '');
|
||||
if (empty($sign)) {
|
||||
throw new InvalidArgumentException('Invalid sign for ChuanglanGateway when using promotion channel');
|
||||
}
|
||||
|
||||
$unsubscribe = (string) $config->get('unsubscribe', '');
|
||||
if (empty($unsubscribe)) {
|
||||
throw new InvalidArgumentException('Invalid unsubscribe for ChuanglanGateway when using promotion channel');
|
||||
}
|
||||
|
||||
$content = $sign.$content.$unsubscribe;
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
50
vendor/overtrue/easy-sms/src/Gateways/ErrorlogGateway.php
vendored
Executable file
50
vendor/overtrue/easy-sms/src/Gateways/ErrorlogGateway.php
vendored
Executable file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Gateways;
|
||||
|
||||
use Overtrue\EasySms\Contracts\MessageInterface;
|
||||
use Overtrue\EasySms\Contracts\PhoneNumberInterface;
|
||||
use Overtrue\EasySms\Support\Config;
|
||||
|
||||
/**
|
||||
* Class ErrorlogGateway.
|
||||
*/
|
||||
class ErrorlogGateway extends Gateway
|
||||
{
|
||||
/**
|
||||
* @param \Overtrue\EasySms\Contracts\PhoneNumberInterface $to
|
||||
* @param \Overtrue\EasySms\Contracts\MessageInterface $message
|
||||
* @param \Overtrue\EasySms\Support\Config $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
if (is_array($to)) {
|
||||
$to = implode(',', $to);
|
||||
}
|
||||
|
||||
$message = sprintf(
|
||||
"[%s] to: %s | message: \"%s\" | template: \"%s\" | data: %s\n",
|
||||
date('Y-m-d H:i:s'),
|
||||
$to,
|
||||
$message->getContent($this),
|
||||
$message->getTemplate($this),
|
||||
json_encode($message->getData($this))
|
||||
);
|
||||
|
||||
$file = $this->config->get('file', ini_get('error_log'));
|
||||
$status = error_log($message, 3, $file);
|
||||
|
||||
return compact('status', 'file');
|
||||
}
|
||||
}
|
||||
120
vendor/overtrue/easy-sms/src/Gateways/Gateway.php
vendored
Executable file
120
vendor/overtrue/easy-sms/src/Gateways/Gateway.php
vendored
Executable file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Gateways;
|
||||
|
||||
use Overtrue\EasySms\Contracts\GatewayInterface;
|
||||
use Overtrue\EasySms\Support\Config;
|
||||
|
||||
/**
|
||||
* Class Gateway.
|
||||
*/
|
||||
abstract class Gateway implements GatewayInterface
|
||||
{
|
||||
const DEFAULT_TIMEOUT = 5.0;
|
||||
|
||||
/**
|
||||
* @var \Overtrue\EasySms\Support\Config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
protected $timeout;
|
||||
|
||||
/**
|
||||
* Gateway constructor.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
{
|
||||
$this->config = new Config($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return timeout.
|
||||
*
|
||||
* @return int|mixed
|
||||
*/
|
||||
public function getTimeout()
|
||||
{
|
||||
return $this->timeout ?: $this->config->get('timeout', self::DEFAULT_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set timeout.
|
||||
*
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTimeout($timeout)
|
||||
{
|
||||
$this->timeout = floatval($timeout);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Overtrue\EasySms\Support\Config
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Overtrue\EasySms\Support\Config $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setConfig(Config $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setGuzzleOptions($options)
|
||||
{
|
||||
$this->options = $options;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getGuzzleOptions()
|
||||
{
|
||||
return $this->options ?: $this->config->get('options', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return \strtolower(str_replace([__NAMESPACE__.'\\', 'Gateway'], '', \get_class($this)));
|
||||
}
|
||||
}
|
||||
148
vendor/overtrue/easy-sms/src/Gateways/HuaweiGateway.php
vendored
Executable file
148
vendor/overtrue/easy-sms/src/Gateways/HuaweiGateway.php
vendored
Executable file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Gateways;
|
||||
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Overtrue\EasySms\Contracts\MessageInterface;
|
||||
use Overtrue\EasySms\Contracts\PhoneNumberInterface;
|
||||
use Overtrue\EasySms\Exceptions\GatewayErrorException;
|
||||
use Overtrue\EasySms\Exceptions\InvalidArgumentException;
|
||||
use Overtrue\EasySms\Support\Config;
|
||||
use Overtrue\EasySms\Traits\HasHttpRequest;
|
||||
|
||||
class HuaweiGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_HOST = 'https://api.rtc.huaweicloud.com:10443';
|
||||
|
||||
const ENDPOINT_URI = '/sms/batchSendSms/v1';
|
||||
|
||||
const SUCCESS_CODE = '000000';
|
||||
|
||||
/**
|
||||
* 发送信息.
|
||||
*
|
||||
* @param PhoneNumberInterface $to
|
||||
* @param MessageInterface $message
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws GatewayErrorException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$appKey = $config->get('app_key');
|
||||
$appSecret = $config->get('app_secret');
|
||||
$channels = $config->get('from');
|
||||
$statusCallback = $config->get('callback', '');
|
||||
|
||||
$endpoint = $this->getEndpoint($config);
|
||||
$headers = $this->getHeaders($appKey, $appSecret);
|
||||
|
||||
$templateId = $message->getTemplate($this);
|
||||
$messageData = $message->getData($this);
|
||||
|
||||
// 短信签名通道号码
|
||||
$from = 'default';
|
||||
if (isset($messageData['from'])) {
|
||||
$from = $messageData['from'];
|
||||
unset($messageData['from']);
|
||||
}
|
||||
$channel = isset($channels[$from]) ? $channels[$from] : '';
|
||||
|
||||
if (empty($channel)) {
|
||||
throw new InvalidArgumentException("From Channel [{$from}] Not Exist");
|
||||
}
|
||||
|
||||
$params = [
|
||||
'from' => $channel,
|
||||
'to' => $to->getUniversalNumber(),
|
||||
'templateId' => $templateId,
|
||||
'templateParas' => json_encode($messageData),
|
||||
'statusCallback' => $statusCallback,
|
||||
];
|
||||
|
||||
try {
|
||||
$result = $this->request('post', $endpoint, [
|
||||
'headers' => $headers,
|
||||
'form_params' => $params,
|
||||
//为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题
|
||||
'verify' => false,
|
||||
]);
|
||||
} catch (RequestException $e) {
|
||||
$result = $this->unwrapResponse($e->getResponse());
|
||||
}
|
||||
|
||||
if (self::SUCCESS_CODE != $result['code']) {
|
||||
throw new GatewayErrorException($result['description'], ltrim($result['code'], 'E'), $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 Endpoint.
|
||||
*
|
||||
* @param Config $config
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getEndpoint(Config $config)
|
||||
{
|
||||
$endpoint = rtrim($config->get('endpoint', self::ENDPOINT_HOST), '/');
|
||||
|
||||
return $endpoint.self::ENDPOINT_URI;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求 Headers 参数.
|
||||
*
|
||||
* @param string $appKey
|
||||
* @param string $appSecret
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getHeaders($appKey, $appSecret)
|
||||
{
|
||||
return [
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Authorization' => 'WSSE realm="SDP",profile="UsernameToken",type="Appkey"',
|
||||
'X-WSSE' => $this->buildWsseHeader($appKey, $appSecret),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造X-WSSE参数值
|
||||
*
|
||||
* @param string $appKey
|
||||
* @param string $appSecret
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildWsseHeader($appKey, $appSecret)
|
||||
{
|
||||
$now = date('Y-m-d\TH:i:s\Z');
|
||||
$nonce = uniqid();
|
||||
$passwordDigest = base64_encode(hash('sha256', ($nonce.$now.$appSecret)));
|
||||
|
||||
return sprintf(
|
||||
'UsernameToken Username="%s",PasswordDigest="%s",Nonce="%s",Created="%s"',
|
||||
$appKey,
|
||||
$passwordDigest,
|
||||
$nonce,
|
||||
$now
|
||||
);
|
||||
}
|
||||
}
|
||||
73
vendor/overtrue/easy-sms/src/Gateways/HuaxinGateway.php
vendored
Executable file
73
vendor/overtrue/easy-sms/src/Gateways/HuaxinGateway.php
vendored
Executable file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 HuaxinGateway.
|
||||
*
|
||||
* @see http://www.ipyy.com/help/
|
||||
*/
|
||||
class HuaxinGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_TEMPLATE = 'http://%s/smsJson.aspx';
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$endpoint = $this->buildEndpoint($config->get('ip'));
|
||||
|
||||
$result = $this->post($endpoint, [
|
||||
'userid' => $config->get('user_id'),
|
||||
'account' => $config->get('account'),
|
||||
'password' => $config->get('password'),
|
||||
'mobile' => $to->getNumber(),
|
||||
'content' => $message->getContent($this),
|
||||
'sendTime' => '',
|
||||
'action' => 'send',
|
||||
'extno' => $config->get('ext_no'),
|
||||
]);
|
||||
|
||||
if ('Success' !== $result['returnstatus']) {
|
||||
throw new GatewayErrorException($result['message'], 400, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build endpoint url.
|
||||
*
|
||||
* @param string $ip
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndpoint($ip)
|
||||
{
|
||||
return sprintf(self::ENDPOINT_TEMPLATE, $ip);
|
||||
}
|
||||
}
|
||||
77
vendor/overtrue/easy-sms/src/Gateways/HuyiGateway.php
vendored
Executable file
77
vendor/overtrue/easy-sms/src/Gateways/HuyiGateway.php
vendored
Executable file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 HuyiGateway.
|
||||
*
|
||||
* @see http://www.ihuyi.com/api/sms.html
|
||||
*/
|
||||
class HuyiGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'http://106.ihuyi.com/webservice/sms.php?method=Submit';
|
||||
|
||||
const ENDPOINT_FORMAT = 'json';
|
||||
|
||||
const SUCCESS_CODE = 2;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$params = [
|
||||
'account' => $config->get('api_id'),
|
||||
'mobile' => $to->getIDDCode() ? \sprintf('%s %s', $to->getIDDCode(), $to->getNumber()) : $to->getNumber(),
|
||||
'content' => $message->getContent($this),
|
||||
'time' => time(),
|
||||
'format' => self::ENDPOINT_FORMAT,
|
||||
'sign' => $config->get('signature'),
|
||||
];
|
||||
|
||||
$params['password'] = $this->generateSign($params);
|
||||
|
||||
$result = $this->post(self::ENDPOINT_URL, $params);
|
||||
|
||||
if (self::SUCCESS_CODE != $result['code']) {
|
||||
throw new GatewayErrorException($result['msg'], $result['code'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Sign.
|
||||
*
|
||||
* @param array $params
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateSign($params)
|
||||
{
|
||||
return md5($params['account'].$this->config->get('api_key').$params['mobile'].$params['content'].$params['time']);
|
||||
}
|
||||
}
|
||||
76
vendor/overtrue/easy-sms/src/Gateways/JuheGateway.php
vendored
Executable file
76
vendor/overtrue/easy-sms/src/Gateways/JuheGateway.php
vendored
Executable file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 JuheGateway.
|
||||
*
|
||||
* @see https://www.juhe.cn/docs/api/id/54
|
||||
*/
|
||||
class JuheGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'http://v.juhe.cn/sms/send';
|
||||
|
||||
const ENDPOINT_FORMAT = 'json';
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$params = [
|
||||
'mobile' => $to->getNumber(),
|
||||
'tpl_id' => $message->getTemplate($this),
|
||||
'tpl_value' => $this->formatTemplateVars($message->getData($this)),
|
||||
'dtype' => self::ENDPOINT_FORMAT,
|
||||
'key' => $config->get('app_key'),
|
||||
];
|
||||
|
||||
$result = $this->get(self::ENDPOINT_URL, $params);
|
||||
|
||||
if ($result['error_code']) {
|
||||
throw new GatewayErrorException($result['reason'], $result['error_code'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $vars
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function formatTemplateVars(array $vars)
|
||||
{
|
||||
$formatted = [];
|
||||
|
||||
foreach ($vars as $key => $value) {
|
||||
$formatted[sprintf('#%s#', trim($key, '#'))] = $value;
|
||||
}
|
||||
|
||||
return http_build_query($formatted);
|
||||
}
|
||||
}
|
||||
61
vendor/overtrue/easy-sms/src/Gateways/KingttoGateway.php
vendored
Executable file
61
vendor/overtrue/easy-sms/src/Gateways/KingttoGateway.php
vendored
Executable file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 KingttoGateWay.
|
||||
*
|
||||
* @see http://www.kingtto.cn/
|
||||
*/
|
||||
class KingttoGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'http://101.201.41.194:9999/sms.aspx';
|
||||
|
||||
const ENDPOINT_METHOD = 'send';
|
||||
|
||||
/**
|
||||
* @param PhoneNumberInterface $to
|
||||
* @param MessageInterface $message
|
||||
* @param Config $config
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface|array|string
|
||||
*
|
||||
* @throws GatewayErrorException
|
||||
*/
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$params = [
|
||||
'action' => self::ENDPOINT_METHOD,
|
||||
'userid' => $config->get('userid'),
|
||||
'account' => $config->get('account'),
|
||||
'password' => $config->get('password'),
|
||||
'mobile' => $to->getNumber(),
|
||||
'content' => $message->getContent(),
|
||||
];
|
||||
|
||||
$result = $this->post(self::ENDPOINT_URL, $params);
|
||||
|
||||
if ('Success' != $result['returnstatus']) {
|
||||
throw new GatewayErrorException($result['message'], $result['remainpoint'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
74
vendor/overtrue/easy-sms/src/Gateways/LuosimaoGateway.php
vendored
Executable file
74
vendor/overtrue/easy-sms/src/Gateways/LuosimaoGateway.php
vendored
Executable file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 LuosimaoGateway.
|
||||
*
|
||||
* @see https://luosimao.com/docs/api/
|
||||
*/
|
||||
class LuosimaoGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_TEMPLATE = 'https://%s.luosimao.com/%s/%s.%s';
|
||||
|
||||
const ENDPOINT_VERSION = 'v1';
|
||||
|
||||
const ENDPOINT_FORMAT = 'json';
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$endpoint = $this->buildEndpoint('sms-api', 'send');
|
||||
|
||||
$result = $this->post($endpoint, [
|
||||
'mobile' => $to->getNumber(),
|
||||
'message' => $message->getContent($this),
|
||||
], [
|
||||
'Authorization' => 'Basic '.base64_encode('api:key-'.$config->get('api_key')),
|
||||
]);
|
||||
|
||||
if ($result['error']) {
|
||||
throw new GatewayErrorException($result['msg'], $result['error'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build endpoint url.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $function
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndpoint($type, $function)
|
||||
{
|
||||
return sprintf(self::ENDPOINT_TEMPLATE, $type, self::ENDPOINT_VERSION, $function, self::ENDPOINT_FORMAT);
|
||||
}
|
||||
}
|
||||
106
vendor/overtrue/easy-sms/src/Gateways/ModuyunGateway.php
vendored
Executable file
106
vendor/overtrue/easy-sms/src/Gateways/ModuyunGateway.php
vendored
Executable file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 ModuyunGateway.
|
||||
*
|
||||
* @see https://www.moduyun.com/doc/index.html#10002
|
||||
*/
|
||||
class ModuyunGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'https://live.moduyun.com/sms/v2/sendsinglesms';
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$urlParams = [
|
||||
'accesskey' => $config->get('accesskey'),
|
||||
'random' => rand(100000, 999999),
|
||||
];
|
||||
|
||||
$params = [
|
||||
'tel' => [
|
||||
'mobile' => $to->getNumber(),
|
||||
'nationcode' => $to->getIDDCode() ?: '86',
|
||||
],
|
||||
'signId' => $config->get('signId', ''),
|
||||
'templateId' => $message->getTemplate($this),
|
||||
'time' => time(),
|
||||
'type' => $config->get('type', 0),
|
||||
'params' => array_values($message->getData($this)),
|
||||
'ext' => '',
|
||||
'extend' => '',
|
||||
];
|
||||
$params['sig'] = $this->generateSign($params, $urlParams['random']);
|
||||
|
||||
$result = $this->request('post', $this->getEndpointUrl($urlParams), [
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json'
|
||||
],
|
||||
'json' => $params,
|
||||
]);
|
||||
|
||||
$result = is_string($result) ? json_decode($result, true) : $result;
|
||||
if (0 != $result['result']) {
|
||||
throw new GatewayErrorException($result['errmsg'], $result['result'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getEndpointUrl($params)
|
||||
{
|
||||
return self::ENDPOINT_URL . '?' . http_build_query($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Sign.
|
||||
*
|
||||
* @param array $params
|
||||
* @param string $random
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateSign($params, $random)
|
||||
{
|
||||
return hash('sha256', sprintf(
|
||||
'secretkey=%s&random=%d&time=%d&mobile=%s',
|
||||
$this->config->get('secretkey'),
|
||||
$random,
|
||||
$params['time'],
|
||||
$params['tel']['mobile']
|
||||
));
|
||||
}
|
||||
}
|
||||
115
vendor/overtrue/easy-sms/src/Gateways/QcloudGateway.php
vendored
Executable file
115
vendor/overtrue/easy-sms/src/Gateways/QcloudGateway.php
vendored
Executable file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 QcloudGateway.
|
||||
*
|
||||
* @see https://cloud.tencent.com/document/product/382/13297
|
||||
*/
|
||||
class QcloudGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'https://yun.tim.qq.com/v5/';
|
||||
|
||||
const ENDPOINT_METHOD = 'tlssmssvr/sendsms';
|
||||
|
||||
const ENDPOINT_VERSION = 'v5';
|
||||
|
||||
const ENDPOINT_FORMAT = 'json';
|
||||
|
||||
/**
|
||||
* @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']);
|
||||
|
||||
$msg = $message->getContent($this);
|
||||
if (!empty($msg) && '【' != mb_substr($msg, 0, 1) && !empty($signName)) {
|
||||
$msg = '【'.$signName.'】'.$msg;
|
||||
}
|
||||
|
||||
$type = !empty($data['type']) ? $data['type'] : 0;
|
||||
$params = [
|
||||
'tel' => [
|
||||
'nationcode' => $to->getIDDCode() ?: 86,
|
||||
'mobile' => $to->getNumber(),
|
||||
],
|
||||
'type' => $type,
|
||||
'msg' => $msg,
|
||||
'time' => time(),
|
||||
'extend' => '',
|
||||
'ext' => '',
|
||||
];
|
||||
if (!is_null($message->getTemplate($this)) && is_array($data)) {
|
||||
unset($params['msg']);
|
||||
$params['params'] = array_values($data);
|
||||
$params['tpl_id'] = $message->getTemplate($this);
|
||||
$params['sign'] = $signName;
|
||||
}
|
||||
$random = substr(uniqid(), -10);
|
||||
|
||||
$params['sig'] = $this->generateSign($params, $random);
|
||||
|
||||
$url = self::ENDPOINT_URL.self::ENDPOINT_METHOD.'?sdkappid='.$config->get('sdk_app_id').'&random='.$random;
|
||||
|
||||
$result = $this->request('post', $url, [
|
||||
'headers' => ['Accept' => 'application/json'],
|
||||
'json' => $params,
|
||||
]);
|
||||
|
||||
if (0 != $result['result']) {
|
||||
throw new GatewayErrorException($result['errmsg'], $result['result'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Sign.
|
||||
*
|
||||
* @param array $params
|
||||
* @param string $random
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateSign($params, $random)
|
||||
{
|
||||
ksort($params);
|
||||
|
||||
return hash('sha256', sprintf(
|
||||
'appkey=%s&random=%s&time=%s&mobile=%s',
|
||||
$this->config->get('app_key'),
|
||||
$random,
|
||||
$params['time'],
|
||||
$params['tel']['mobile']
|
||||
), false);
|
||||
}
|
||||
}
|
||||
148
vendor/overtrue/easy-sms/src/Gateways/QiniuGateway.php
vendored
Executable file
148
vendor/overtrue/easy-sms/src/Gateways/QiniuGateway.php
vendored
Executable file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 QiniuGateway.
|
||||
*
|
||||
* @see https://developer.qiniu.com/sms/api/5897/sms-api-send-message
|
||||
*/
|
||||
class QiniuGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_TEMPLATE = 'https://%s.qiniuapi.com/%s/%s';
|
||||
|
||||
const ENDPOINT_VERSION = 'v1';
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$endpoint = $this->buildEndpoint('sms', 'message/single');
|
||||
|
||||
$data = $message->getData($this);
|
||||
|
||||
$params = [
|
||||
'template_id' => $message->getTemplate($this),
|
||||
'mobile' => $to->getNumber(),
|
||||
];
|
||||
|
||||
if (!empty($data)) {
|
||||
$params['parameters'] = $data;
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json',
|
||||
];
|
||||
|
||||
$headers['Authorization'] = $this->generateSign($endpoint, 'POST', json_encode($params), $headers['Content-Type'], $config);
|
||||
|
||||
$result = $this->postJson($endpoint, $params, $headers);
|
||||
|
||||
if (isset($result['error'])) {
|
||||
throw new GatewayErrorException($result['message'], $result['error'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build endpoint url.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $function
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndpoint($type, $function)
|
||||
{
|
||||
return sprintf(self::ENDPOINT_TEMPLATE, $type, self::ENDPOINT_VERSION, $function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build endpoint url.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param string $body
|
||||
* @param string $contentType
|
||||
* @param Config $config
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateSign($url, $method, $body, $contentType, Config $config)
|
||||
{
|
||||
$urlItems = parse_url($url);
|
||||
$host = $urlItems['host'];
|
||||
if (isset($urlItems['port'])) {
|
||||
$port = $urlItems['port'];
|
||||
} else {
|
||||
$port = '';
|
||||
}
|
||||
$path = $urlItems['path'];
|
||||
if (isset($urlItems['query'])) {
|
||||
$query = $urlItems['query'];
|
||||
} else {
|
||||
$query = '';
|
||||
}
|
||||
//write request uri
|
||||
$toSignStr = $method.' '.$path;
|
||||
if (!empty($query)) {
|
||||
$toSignStr .= '?'.$query;
|
||||
}
|
||||
//write host and port
|
||||
$toSignStr .= "\nHost: ".$host;
|
||||
if (!empty($port)) {
|
||||
$toSignStr .= ':'.$port;
|
||||
}
|
||||
//write content type
|
||||
if (!empty($contentType)) {
|
||||
$toSignStr .= "\nContent-Type: ".$contentType;
|
||||
}
|
||||
$toSignStr .= "\n\n";
|
||||
//write body
|
||||
if (!empty($body)) {
|
||||
$toSignStr .= $body;
|
||||
}
|
||||
|
||||
$hmac = hash_hmac('sha1', $toSignStr, $config->get('secret_key'), true);
|
||||
|
||||
return 'Qiniu '.$config->get('access_key').':'.$this->base64UrlSafeEncode($hmac);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function base64UrlSafeEncode($data)
|
||||
{
|
||||
$find = array('+', '/');
|
||||
$replace = array('-', '_');
|
||||
|
||||
return str_replace($find, $replace, base64_encode($data));
|
||||
}
|
||||
}
|
||||
134
vendor/overtrue/easy-sms/src/Gateways/RongcloudGateway.php
vendored
Executable file
134
vendor/overtrue/easy-sms/src/Gateways/RongcloudGateway.php
vendored
Executable file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Gateways;
|
||||
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
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 RongcloudGateway.
|
||||
*
|
||||
* @author Darren Gao <realgaodacheng@gmail.com>
|
||||
*
|
||||
* @see http://www.rongcloud.cn/docs/sms_service.html#send_sms_code
|
||||
*/
|
||||
class RongcloudGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_TEMPLATE = 'http://api.sms.ronghub.com/%s.%s';
|
||||
|
||||
const ENDPOINT_ACTION = 'sendCode';
|
||||
|
||||
const ENDPOINT_FORMAT = 'json';
|
||||
|
||||
const ENDPOINT_REGION = '86'; // 中国区,目前只支持此国别
|
||||
|
||||
const SUCCESS_CODE = 200;
|
||||
|
||||
/**
|
||||
* @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();
|
||||
$action = array_key_exists('action', $data) ? $data['action'] : self::ENDPOINT_ACTION;
|
||||
$endpoint = $this->buildEndpoint($action);
|
||||
|
||||
$headers = [
|
||||
'Nonce' => uniqid(),
|
||||
'App-Key' => $config->get('app_key'),
|
||||
'Timestamp' => time(),
|
||||
];
|
||||
$headers['Signature'] = $this->generateSign($headers, $config);
|
||||
|
||||
switch ($action) {
|
||||
case 'sendCode':
|
||||
$params = [
|
||||
'mobile' => $to->getNumber(),
|
||||
'region' => self::ENDPOINT_REGION,
|
||||
'templateId' => $message->getTemplate($this),
|
||||
];
|
||||
|
||||
break;
|
||||
case 'verifyCode':
|
||||
if (!array_key_exists('code', $data)
|
||||
or !array_key_exists('sessionId', $data)) {
|
||||
throw new GatewayErrorException('"code" or "sessionId" is not set', 0);
|
||||
}
|
||||
$params = [
|
||||
'code' => $data['code'],
|
||||
'sessionId' => $data['sessionId'],
|
||||
];
|
||||
|
||||
break;
|
||||
case 'sendNotify':
|
||||
$params = [
|
||||
'mobile' => $to->getNumber(),
|
||||
'region' => self::ENDPOINT_REGION,
|
||||
'templateId' => $message->getTemplate($this),
|
||||
];
|
||||
$params = array_merge($params, $data);
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new GatewayErrorException(sprintf('action: %s not supported', $action));
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->post($endpoint, $params, $headers);
|
||||
|
||||
if (self::SUCCESS_CODE !== $result['code']) {
|
||||
throw new GatewayErrorException($result['errorMessage'], $result['code'], $result);
|
||||
}
|
||||
} catch (ClientException $e) {
|
||||
throw new GatewayErrorException($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Sign.
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Overtrue\EasySms\Support\Config $config
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateSign($params, Config $config)
|
||||
{
|
||||
return sha1(sprintf('%s%s%s', $config->get('app_secret'), $params['Nonce'], $params['Timestamp']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build endpoint url.
|
||||
*
|
||||
* @param string $action
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndpoint($action)
|
||||
{
|
||||
return sprintf(self::ENDPOINT_TEMPLATE, $action, self::ENDPOINT_FORMAT);
|
||||
}
|
||||
}
|
||||
95
vendor/overtrue/easy-sms/src/Gateways/SendcloudGateway.php
vendored
Executable file
95
vendor/overtrue/easy-sms/src/Gateways/SendcloudGateway.php
vendored
Executable file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 SendcloudGateway.
|
||||
*
|
||||
* @see http://sendcloud.sohu.com/doc/sms/
|
||||
*/
|
||||
class SendcloudGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_TEMPLATE = 'http://www.sendcloud.net/smsapi/%s';
|
||||
|
||||
/**
|
||||
* Send a short message.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
$params = [
|
||||
'smsUser' => $config->get('sms_user'),
|
||||
'templateId' => $message->getTemplate($this),
|
||||
'msgType' => $to->getIDDCode() ? 2 : 0,
|
||||
'phone' => $to->getZeroPrefixedNumber(),
|
||||
'vars' => $this->formatTemplateVars($message->getData($this)),
|
||||
];
|
||||
|
||||
if ($config->get('timestamp', false)) {
|
||||
$params['timestamp'] = time() * 1000;
|
||||
}
|
||||
|
||||
$params['signature'] = $this->sign($params, $config->get('sms_key'));
|
||||
|
||||
$result = $this->post(sprintf(self::ENDPOINT_TEMPLATE, 'send'), $params);
|
||||
|
||||
if (!$result['result']) {
|
||||
throw new GatewayErrorException($result['message'], $result['statusCode'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $vars
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function formatTemplateVars(array $vars)
|
||||
{
|
||||
$formatted = [];
|
||||
|
||||
foreach ($vars as $key => $value) {
|
||||
$formatted[sprintf('%%%s%%', trim($key, '%'))] = $value;
|
||||
}
|
||||
|
||||
return json_encode($formatted, JSON_FORCE_OBJECT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
* @param string $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function sign($params, $key)
|
||||
{
|
||||
ksort($params);
|
||||
|
||||
return md5(sprintf('%s&%s&%s', $key, urldecode(http_build_query($params)), $key));
|
||||
}
|
||||
}
|
||||
78
vendor/overtrue/easy-sms/src/Gateways/SmsbaoGateway.php
vendored
Executable file
78
vendor/overtrue/easy-sms/src/Gateways/SmsbaoGateway.php
vendored
Executable file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 SmsbaoGateway
|
||||
* @author iwindy <203962638@qq.com>
|
||||
* @see http://www.smsbao.com/openapi/
|
||||
*/
|
||||
class SmsbaoGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'http://api.smsbao.com/%s';
|
||||
|
||||
const SUCCESS_CODE = '0';
|
||||
|
||||
protected $errorStatuses = [
|
||||
'0' => '短信发送成功',
|
||||
'-1' => '参数不全',
|
||||
'-2' => '服务器空间不支持,请确认支持curl或者fsocket,联系您的空间商解决或者更换空间!',
|
||||
'30' => '密码错误',
|
||||
'40' => '账号不存在',
|
||||
'41' => '余额不足',
|
||||
'42' => '帐户已过期',
|
||||
'43' => 'IP地址限制',
|
||||
'50' => '内容含有敏感词'
|
||||
];
|
||||
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$data = $message->getContent($this);
|
||||
|
||||
if (is_null($to->getIDDCode())) {
|
||||
$number = $to->getNumber();
|
||||
$action = 'sms';
|
||||
} else {
|
||||
$number = $to->getUniversalNumber();
|
||||
$action = 'wsms';
|
||||
}
|
||||
|
||||
$params = [
|
||||
'u' => $config->get('user'),
|
||||
'p' => md5($config->get('password')),
|
||||
'm' => $number,
|
||||
'c' => $data
|
||||
];
|
||||
|
||||
$result = $this->get($this->buildEndpoint($action), $params);
|
||||
|
||||
if ($result !== self::SUCCESS_CODE) {
|
||||
throw new GatewayErrorException($this->errorStatuses[$result], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function buildEndpoint($type)
|
||||
{
|
||||
return sprintf(self::ENDPOINT_URL, $type);
|
||||
}
|
||||
}
|
||||
88
vendor/overtrue/easy-sms/src/Gateways/SubmailGateway.php
vendored
Executable file
88
vendor/overtrue/easy-sms/src/Gateways/SubmailGateway.php
vendored
Executable file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 SubmailGateway.
|
||||
*
|
||||
* @see https://www.mysubmail.com/chs/documents/developer/index
|
||||
*/
|
||||
class SubmailGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_TEMPLATE = 'https://api.mysubmail.com/%s.%s';
|
||||
|
||||
const ENDPOINT_FORMAT = 'json';
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$endpoint = $this->buildEndpoint($this->inChineseMainland($to) ? 'message/xsend' : 'internationalsms/xsend');
|
||||
|
||||
$data = $message->getData($this);
|
||||
|
||||
$result = $this->post($endpoint, [
|
||||
'appid' => $config->get('app_id'),
|
||||
'signature' => $config->get('app_key'),
|
||||
'project' => !empty($data['project']) ? $data['project'] : $config->get('project'),
|
||||
'to' => $to->getUniversalNumber(),
|
||||
'vars' => json_encode($data, JSON_FORCE_OBJECT),
|
||||
]);
|
||||
|
||||
if ('success' != $result['status']) {
|
||||
throw new GatewayErrorException($result['msg'], $result['code'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build endpoint url.
|
||||
*
|
||||
* @param string $function
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndpoint($function)
|
||||
{
|
||||
return sprintf(self::ENDPOINT_TEMPLATE, $function, self::ENDPOINT_FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the phone number belongs to chinese mainland.
|
||||
*
|
||||
* @param \Overtrue\EasySms\Contracts\PhoneNumberInterface $to
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function inChineseMainland($to)
|
||||
{
|
||||
$code = $to->getIDDCode();
|
||||
|
||||
return empty($code) || 86 === $code;
|
||||
}
|
||||
}
|
||||
84
vendor/overtrue/easy-sms/src/Gateways/TianyiwuxianGateway.php
vendored
Executable file
84
vendor/overtrue/easy-sms/src/Gateways/TianyiwuxianGateway.php
vendored
Executable file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 TianyiwuxianGateway.
|
||||
*
|
||||
* @author Darren Gao <realgaodacheng@gmail.com>
|
||||
*/
|
||||
class TianyiwuxianGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_TEMPLATE = 'http://jk.106api.cn/sms%s.aspx';
|
||||
|
||||
const ENDPOINT_ENCODE = 'UTF8';
|
||||
|
||||
const ENDPOINT_TYPE = 'send';
|
||||
|
||||
const ENDPOINT_FORMAT = 'json';
|
||||
|
||||
const SUCCESS_STATUS = 'success';
|
||||
|
||||
const SUCCESS_CODE = '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)
|
||||
{
|
||||
$endpoint = $this->buildEndpoint();
|
||||
|
||||
$params = [
|
||||
'gwid' => $config->get('gwid'),
|
||||
'type' => self::ENDPOINT_TYPE,
|
||||
'rece' => self::ENDPOINT_FORMAT,
|
||||
'mobile' => $to->getNumber(),
|
||||
'message' => $message->getContent($this),
|
||||
'username' => $config->get('username'),
|
||||
'password' => strtoupper(md5($config->get('password'))),
|
||||
];
|
||||
|
||||
$result = $this->post($endpoint, $params);
|
||||
|
||||
$result = json_decode($result, true);
|
||||
|
||||
if (self::SUCCESS_STATUS !== $result['returnstatus'] || self::SUCCESS_CODE !== $result['code']) {
|
||||
throw new GatewayErrorException($result['remark'], $result['code']);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build endpoint url.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndpoint()
|
||||
{
|
||||
return sprintf(self::ENDPOINT_TEMPLATE, self::ENDPOINT_ENCODE);
|
||||
}
|
||||
}
|
||||
86
vendor/overtrue/easy-sms/src/Gateways/TiniyoGateway.php
vendored
Executable file
86
vendor/overtrue/easy-sms/src/Gateways/TiniyoGateway.php
vendored
Executable file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Gateways;
|
||||
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
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 Tiniyo Gateway.
|
||||
*
|
||||
* @see https://tiniyo.com/sms.html
|
||||
*/
|
||||
class TiniyoGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'https://api.tiniyo.com/v1/Account/%s/Message';
|
||||
|
||||
const SUCCESS_CODE = '000000';
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'tiniyo';
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$accountSid = $config->get('account_sid');
|
||||
$endpoint = $this->buildEndPoint($accountSid);
|
||||
|
||||
$params = [
|
||||
'dst' => $to->getUniversalNumber(),
|
||||
'src' => $config->get('from'),
|
||||
'text' => $message->getContent($this),
|
||||
];
|
||||
|
||||
$result = $this->request('post', $endpoint, [
|
||||
'json' => $params,
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json;charset=utf-8',
|
||||
'Authorization' => base64_encode($config->get('account_sid').':'.$config->get('token')),
|
||||
],
|
||||
]);
|
||||
|
||||
if (self::SUCCESS_CODE != $result['statusCode']) {
|
||||
throw new GatewayErrorException($result['statusCode'], $result['statusCode'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* build endpoint url.
|
||||
*
|
||||
* @param string $accountSid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndPoint($accountSid)
|
||||
{
|
||||
return sprintf(self::ENDPOINT_URL, $accountSid);
|
||||
}
|
||||
}
|
||||
91
vendor/overtrue/easy-sms/src/Gateways/TwilioGateway.php
vendored
Executable file
91
vendor/overtrue/easy-sms/src/Gateways/TwilioGateway.php
vendored
Executable file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Gateways;
|
||||
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
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 TwilioGateway.
|
||||
*
|
||||
* @see https://www.twilio.com/docs/api/messaging/send-messages
|
||||
*/
|
||||
class TwilioGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json';
|
||||
|
||||
protected $errorStatuses = [
|
||||
'failed',
|
||||
'undelivered',
|
||||
];
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'twilio';
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$accountSid = $config->get('account_sid');
|
||||
$endpoint = $this->buildEndPoint($accountSid);
|
||||
|
||||
$params = [
|
||||
'To' => $to->getUniversalNumber(),
|
||||
'From' => $config->get('from'),
|
||||
'Body' => $message->getContent($this),
|
||||
];
|
||||
|
||||
try {
|
||||
$result = $this->request('post', $endpoint, [
|
||||
'auth' => [
|
||||
$accountSid,
|
||||
$config->get('token'),
|
||||
],
|
||||
'form_params' => $params,
|
||||
]);
|
||||
if (in_array($result['status'], $this->errorStatuses) || !is_null($result['error_code'])) {
|
||||
throw new GatewayErrorException($result['message'], $result['error_code'], $result);
|
||||
}
|
||||
} catch (ClientException $e) {
|
||||
throw new GatewayErrorException($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* build endpoint url.
|
||||
*
|
||||
* @param string $accountSid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndPoint($accountSid)
|
||||
{
|
||||
return sprintf(self::ENDPOINT_URL, $accountSid);
|
||||
}
|
||||
}
|
||||
130
vendor/overtrue/easy-sms/src/Gateways/UcloudGateway.php
vendored
Executable file
130
vendor/overtrue/easy-sms/src/Gateways/UcloudGateway.php
vendored
Executable file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 UcloudGateway.
|
||||
*/
|
||||
class UcloudGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_URL = 'https://api.ucloud.cn';
|
||||
|
||||
const ENDPOINT_Action = 'SendUSMSMessage';
|
||||
|
||||
const SUCCESS_CODE = 0;
|
||||
|
||||
/**
|
||||
* Send Message.
|
||||
*
|
||||
* @param PhoneNumberInterface $to
|
||||
* @param MessageInterface $message
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws GatewayErrorException
|
||||
*/
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$params = $this->buildParams($to, $message, $config);
|
||||
|
||||
$result = $this->get(self::ENDPOINT_URL, $params);
|
||||
|
||||
if (self::SUCCESS_CODE != $result['RetCode']) {
|
||||
throw new GatewayErrorException($result['Message'], $result['RetCode'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Params.
|
||||
*
|
||||
* @param PhoneNumberInterface $to
|
||||
* @param MessageInterface $message
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function buildParams(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$data = $message->getData($this);
|
||||
$params = [
|
||||
'Action' => self::ENDPOINT_Action,
|
||||
'SigContent' => $config->get('sig_content'),
|
||||
'TemplateId' => $message->getTemplate($this),
|
||||
'PublicKey' => $config->get('public_key'),
|
||||
];
|
||||
$code = isset($data['code']) ? $data['code'] : '';
|
||||
if (is_array($code) && !empty($code)) {
|
||||
foreach ($code as $key => $value) {
|
||||
$params['TemplateParams.'.$key] = $value;
|
||||
}
|
||||
} else {
|
||||
if (!empty($code) || !is_null($code)) {
|
||||
$params['TemplateParams.0'] = $code;
|
||||
}
|
||||
}
|
||||
|
||||
$mobiles = isset($data['mobiles']) ? $data['mobiles'] : '';
|
||||
if (!empty($mobiles) && !is_null($mobiles)) {
|
||||
if (is_array($mobiles)) {
|
||||
foreach ($mobiles as $key => $value) {
|
||||
$params['PhoneNumbers.'.$key] = $value;
|
||||
}
|
||||
} else {
|
||||
$params['PhoneNumbers.0'] = $mobiles;
|
||||
}
|
||||
} else {
|
||||
$params['PhoneNumbers.0'] = $to->getNumber();
|
||||
}
|
||||
|
||||
if (!is_null($config->get('project_id')) && !empty($config->get('project_id'))) {
|
||||
$params['ProjectId'] = $config->get('project_id');
|
||||
}
|
||||
|
||||
$signature = $this->getSignature($params, $config->get('private_key'));
|
||||
$params['Signature'] = $signature;
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Sign.
|
||||
*
|
||||
* @param array $params
|
||||
* @param string $privateKey
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getSignature($params, $privateKey)
|
||||
{
|
||||
ksort($params);
|
||||
|
||||
$paramsData = '';
|
||||
foreach ($params as $key => $value) {
|
||||
$paramsData .= $key;
|
||||
$paramsData .= $value;
|
||||
}
|
||||
$paramsData .= $privateKey;
|
||||
|
||||
return sha1($paramsData);
|
||||
}
|
||||
}
|
||||
77
vendor/overtrue/easy-sms/src/Gateways/Ue35Gateway.php
vendored
Executable file
77
vendor/overtrue/easy-sms/src/Gateways/Ue35Gateway.php
vendored
Executable file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 Ue35Gateway.
|
||||
*
|
||||
* @see https://shimo.im/docs/380b42d8cba24521
|
||||
*/
|
||||
class Ue35Gateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_HOST = 'sms.ue35.cn';
|
||||
|
||||
const ENDPOINT_URI = '/sms/interface/sendmess.htm';
|
||||
|
||||
const SUCCESS_CODE = 1;
|
||||
|
||||
/**
|
||||
* Send message.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
$params = [
|
||||
'username' => $config->get('username'),
|
||||
'userpwd' => $config->get('userpwd'),
|
||||
'mobiles' => $to->getNumber(),
|
||||
'content' => $message->getContent($this),
|
||||
];
|
||||
|
||||
$headers = [
|
||||
'host' => static::ENDPOINT_HOST,
|
||||
'content-type' => 'application/json',
|
||||
'user-agent' => 'PHP EasySms Client',
|
||||
];
|
||||
|
||||
$result = $this->request('get', self::getEndpointUri().'?'.http_build_query($params), ['headers' => $headers]);
|
||||
if (is_string($result)) {
|
||||
$result = json_decode(json_encode(simplexml_load_string($result)), true);
|
||||
}
|
||||
|
||||
if (self::SUCCESS_CODE != $result['errorcode']) {
|
||||
throw new GatewayErrorException($result['message'], $result['errorcode'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getEndpointUri()
|
||||
{
|
||||
return 'http://'.static::ENDPOINT_HOST.static::ENDPOINT_URI;
|
||||
}
|
||||
}
|
||||
99
vendor/overtrue/easy-sms/src/Gateways/YunpianGateway.php
vendored
Executable file
99
vendor/overtrue/easy-sms/src/Gateways/YunpianGateway.php
vendored
Executable file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 YunpianGateway.
|
||||
*
|
||||
* @see https://www.yunpian.com/doc/zh_CN/intl/single_send.html
|
||||
*/
|
||||
class YunpianGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_TEMPLATE = 'https://%s.yunpian.com/%s/%s/%s.%s';
|
||||
|
||||
const ENDPOINT_VERSION = 'v2';
|
||||
|
||||
const ENDPOINT_FORMAT = 'json';
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$template = $message->getTemplate($this);
|
||||
$function = 'single_send';
|
||||
$option = [
|
||||
'form_params' => [
|
||||
'apikey' => $config->get('api_key'),
|
||||
'mobile' => $to->getUniversalNumber()
|
||||
],
|
||||
'exceptions' => false,
|
||||
];
|
||||
|
||||
if(!is_null($template)){
|
||||
$function = 'tpl_single_send';
|
||||
$data = [];
|
||||
|
||||
foreach ($message->getData($this) ?? [] as $key => $value) {
|
||||
$data[] = urlencode('#'.$key.'#') . '=' . urlencode($value);
|
||||
}
|
||||
|
||||
$option['form_params'] = array_merge($option['form_params'],[
|
||||
'tpl_id' => $template,
|
||||
'tpl_value' => implode('&', $data)
|
||||
]);
|
||||
}else{
|
||||
$content = $message->getContent($this);
|
||||
$signature = $config->get('signature', '');
|
||||
$option['form_params'] = array_merge($option['form_params'],[
|
||||
'text' => 0 === \stripos($content, '【') ? $content : $signature.$content
|
||||
]);
|
||||
}
|
||||
|
||||
$endpoint = $this->buildEndpoint('sms', 'sms', $function);
|
||||
$result = $this->request('post', $endpoint, $option);
|
||||
|
||||
if ($result['code']) {
|
||||
throw new GatewayErrorException($result['msg'], $result['code'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build endpoint url.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $resource
|
||||
* @param string $function
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndpoint($type, $resource, $function)
|
||||
{
|
||||
return sprintf(self::ENDPOINT_TEMPLATE, $type, self::ENDPOINT_VERSION, $resource, $function, self::ENDPOINT_FORMAT);
|
||||
}
|
||||
}
|
||||
99
vendor/overtrue/easy-sms/src/Gateways/YuntongxunGateway.php
vendored
Executable file
99
vendor/overtrue/easy-sms/src/Gateways/YuntongxunGateway.php
vendored
Executable file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 YuntongxunGateway.
|
||||
*
|
||||
* @see http://www.yuntongxun.com/doc/rest/sms/3_2_2_2.html
|
||||
*/
|
||||
class YuntongxunGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_TEMPLATE = 'https://%s:%s/%s/%s/%s/%s/%s?sig=%s';
|
||||
|
||||
const SERVER_IP = 'app.cloopen.com';
|
||||
|
||||
const DEBUG_SERVER_IP = 'sandboxapp.cloopen.com';
|
||||
|
||||
const DEBUG_TEMPLATE_ID = 1;
|
||||
|
||||
const SERVER_PORT = '8883';
|
||||
|
||||
const SDK_VERSION = '2013-12-26';
|
||||
|
||||
const SUCCESS_CODE = '000000';
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$datetime = date('YmdHis');
|
||||
|
||||
$endpoint = $this->buildEndpoint('SMS', 'TemplateSMS', $datetime, $config);
|
||||
|
||||
$result = $this->request('post', $endpoint, [
|
||||
'json' => [
|
||||
'to' => $to,
|
||||
'templateId' => (int) ($this->config->get('debug') ? self::DEBUG_TEMPLATE_ID : $message->getTemplate($this)),
|
||||
'appId' => $config->get('app_id'),
|
||||
'datas' => $message->getData($this),
|
||||
],
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json;charset=utf-8',
|
||||
'Authorization' => base64_encode($config->get('account_sid').':'.$datetime),
|
||||
],
|
||||
]);
|
||||
|
||||
if (self::SUCCESS_CODE != $result['statusCode']) {
|
||||
throw new GatewayErrorException($result['statusCode'], $result['statusCode'], $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build endpoint url.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $resource
|
||||
* @param string $datetime
|
||||
* @param \Overtrue\EasySms\Support\Config $config
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndpoint($type, $resource, $datetime, Config $config)
|
||||
{
|
||||
$serverIp = $this->config->get('debug') ? self::DEBUG_SERVER_IP : self::SERVER_IP;
|
||||
|
||||
$accountType = $this->config->get('is_sub_account') ? 'SubAccounts' : 'Accounts';
|
||||
|
||||
$sig = strtoupper(md5($config->get('account_sid').$config->get('account_token').$datetime));
|
||||
|
||||
return sprintf(self::ENDPOINT_TEMPLATE, $serverIp, self::SERVER_PORT, self::SDK_VERSION, $accountType, $config->get('account_sid'), $type, $resource, $sig);
|
||||
}
|
||||
}
|
||||
162
vendor/overtrue/easy-sms/src/Gateways/YunxinGateway.php
vendored
Executable file
162
vendor/overtrue/easy-sms/src/Gateways/YunxinGateway.php
vendored
Executable file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 YunxinGateway.
|
||||
*
|
||||
* @author her-cat <i@her-cat.com>
|
||||
*
|
||||
* @see https://dev.yunxin.163.com/docs/product/%E7%9F%AD%E4%BF%A1/%E7%9F%AD%E4%BF%A1%E6%8E%A5%E5%8F%A3%E6%8C%87%E5%8D%97
|
||||
*/
|
||||
class YunxinGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const ENDPOINT_TEMPLATE = 'https://api.netease.im/%s/%s.action';
|
||||
|
||||
const ENDPOINT_ACTION = 'sendCode';
|
||||
|
||||
const SUCCESS_CODE = 200;
|
||||
|
||||
/**
|
||||
* Send a short message.
|
||||
*
|
||||
* @param \Overtrue\EasySms\Contracts\PhoneNumberInterface $to
|
||||
* @param \Overtrue\EasySms\Contracts\MessageInterface $message
|
||||
* @param \Overtrue\EasySms\Support\Config $config
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws GatewayErrorException
|
||||
*/
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$data = $message->getData($this);
|
||||
|
||||
$action = isset($data['action']) ? $data['action'] : self::ENDPOINT_ACTION;
|
||||
|
||||
$endpoint = $this->buildEndpoint('sms', $action);
|
||||
|
||||
switch ($action) {
|
||||
case 'sendCode':
|
||||
$params = $this->buildSendCodeParams($to, $message, $config);
|
||||
|
||||
break;
|
||||
case 'verifyCode':
|
||||
$params = $this->buildVerifyCodeParams($to, $message);
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new GatewayErrorException(sprintf('action: %s not supported', $action), 0);
|
||||
}
|
||||
|
||||
$headers = $this->buildHeaders($config);
|
||||
|
||||
try {
|
||||
$result = $this->post($endpoint, $params, $headers);
|
||||
|
||||
if (!isset($result['code']) || self::SUCCESS_CODE !== $result['code']) {
|
||||
$code = isset($result['code']) ? $result['code'] : 0;
|
||||
$error = isset($result['msg']) ? $result['msg'] : json_encode($result, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
throw new GatewayErrorException($error, $code);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new GatewayErrorException($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $resource
|
||||
* @param $function
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndpoint($resource, $function)
|
||||
{
|
||||
return sprintf(self::ENDPOINT_TEMPLATE, $resource, strtolower($function));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the request headers.
|
||||
*
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function buildHeaders(Config $config)
|
||||
{
|
||||
$headers = [
|
||||
'AppKey' => $config->get('app_key'),
|
||||
'Nonce' => md5(uniqid('easysms')),
|
||||
'CurTime' => (string) time(),
|
||||
'Content-Type' => 'application/x-www-form-urlencoded;charset=utf-8',
|
||||
];
|
||||
|
||||
$headers['CheckSum'] = sha1("{$config->get('app_secret')}{$headers['Nonce']}{$headers['CurTime']}");
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PhoneNumberInterface $to
|
||||
* @param MessageInterface $message
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function buildSendCodeParams(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$data = $message->getData($this);
|
||||
$template = $message->getTemplate($this);
|
||||
|
||||
return [
|
||||
'mobile' => $to->getUniversalNumber(),
|
||||
'authCode' => array_key_exists('code', $data) ? $data['code'] : '',
|
||||
'deviceId' => array_key_exists('device_id', $data) ? $data['device_id'] : '',
|
||||
'templateid' => is_string($template) ? $template : '',
|
||||
'codeLen' => $config->get('code_length', 4),
|
||||
'needUp' => $config->get('need_up', false),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PhoneNumberInterface $to
|
||||
* @param MessageInterface $message
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws GatewayErrorException
|
||||
*/
|
||||
public function buildVerifyCodeParams(PhoneNumberInterface $to, MessageInterface $message)
|
||||
{
|
||||
$data = $message->getData($this);
|
||||
|
||||
if (!array_key_exists('code', $data)) {
|
||||
throw new GatewayErrorException('"code" cannot be empty', 0);
|
||||
}
|
||||
|
||||
return [
|
||||
'mobile' => $to->getUniversalNumber(),
|
||||
'code' => $data['code'],
|
||||
];
|
||||
}
|
||||
}
|
||||
121
vendor/overtrue/easy-sms/src/Gateways/YunzhixunGateway.php
vendored
Executable file
121
vendor/overtrue/easy-sms/src/Gateways/YunzhixunGateway.php
vendored
Executable file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
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 YunzhixunGateway.
|
||||
*
|
||||
* @author her-cat <i@her-cat.com>
|
||||
*
|
||||
* @see http://docs.ucpaas.com/doku.php?id=%E7%9F%AD%E4%BF%A1:sendsms
|
||||
*/
|
||||
class YunzhixunGateway extends Gateway
|
||||
{
|
||||
use HasHttpRequest;
|
||||
|
||||
const SUCCESS_CODE = '000000';
|
||||
|
||||
const FUNCTION_SEND_SMS = 'sendsms';
|
||||
|
||||
const FUNCTION_BATCH_SEND_SMS = 'sendsms_batch';
|
||||
|
||||
const ENDPOINT_TEMPLATE = 'https://open.ucpaas.com/ol/%s/%s';
|
||||
|
||||
/**
|
||||
* Send a short message.
|
||||
*
|
||||
* @param \Overtrue\EasySms\Contracts\PhoneNumberInterface $to
|
||||
* @param \Overtrue\EasySms\Contracts\MessageInterface $message
|
||||
* @param \Overtrue\EasySms\Support\Config $config
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws GatewayErrorException
|
||||
*/
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$data = $message->getData($this);
|
||||
|
||||
$function = isset($data['mobiles']) ? self::FUNCTION_BATCH_SEND_SMS : self::FUNCTION_SEND_SMS;
|
||||
|
||||
$endpoint = $this->buildEndpoint('sms', $function);
|
||||
|
||||
$params = $this->buildParams($to, $message, $config);
|
||||
|
||||
return $this->execute($endpoint, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $resource
|
||||
* @param $function
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildEndpoint($resource, $function)
|
||||
{
|
||||
return sprintf(self::ENDPOINT_TEMPLATE, $resource, $function);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PhoneNumberInterface $to
|
||||
* @param MessageInterface $message
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function buildParams(PhoneNumberInterface $to, MessageInterface $message, Config $config)
|
||||
{
|
||||
$data = $message->getData($this);
|
||||
|
||||
return [
|
||||
'sid' => $config->get('sid'),
|
||||
'token' => $config->get('token'),
|
||||
'appid' => $config->get('app_id'),
|
||||
'templateid' => $message->getTemplate($this),
|
||||
'uid' => isset($data['uid']) ? $data['uid'] : '',
|
||||
'param' => isset($data['params']) ? $data['params'] : '',
|
||||
'mobile' => isset($data['mobiles']) ? $data['mobiles'] : $to->getNumber(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $endpoint
|
||||
* @param $params
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws GatewayErrorException
|
||||
*/
|
||||
protected function execute($endpoint, $params)
|
||||
{
|
||||
try {
|
||||
$result = $this->postJson($endpoint, $params);
|
||||
|
||||
if (!isset($result['code']) || self::SUCCESS_CODE !== $result['code']) {
|
||||
$code = isset($result['code']) ? $result['code'] : 0;
|
||||
$error = isset($result['msg']) ? $result['msg'] : json_encode($result, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
throw new GatewayErrorException($error, $code);
|
||||
}
|
||||
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
throw new GatewayErrorException($e->getMessage(), $e->getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
187
vendor/overtrue/easy-sms/src/Message.php
vendored
Executable file
187
vendor/overtrue/easy-sms/src/Message.php
vendored
Executable file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms;
|
||||
|
||||
use Overtrue\EasySms\Contracts\GatewayInterface;
|
||||
use Overtrue\EasySms\Contracts\MessageInterface;
|
||||
|
||||
/**
|
||||
* Class Message.
|
||||
*/
|
||||
class Message implements MessageInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $gateways = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $content;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $template;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* Message constructor.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param string $type
|
||||
*/
|
||||
public function __construct(array $attributes = [], $type = MessageInterface::TEXT_MESSAGE)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
foreach ($attributes as $property => $value) {
|
||||
if (property_exists($this, $property)) {
|
||||
$this->$property = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the message type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMessageType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return message content.
|
||||
*
|
||||
* @param \Overtrue\EasySms\Contracts\GatewayInterface|null $gateway
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(GatewayInterface $gateway = null)
|
||||
{
|
||||
return is_callable($this->content) ? call_user_func($this->content, $gateway) : $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the template id of message.
|
||||
*
|
||||
* @param \Overtrue\EasySms\Contracts\GatewayInterface|null $gateway
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTemplate(GatewayInterface $gateway = null)
|
||||
{
|
||||
return is_callable($this->template) ? call_user_func($this->template, $gateway) : $this->template;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $content
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setContent($content)
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $template
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTemplate($template)
|
||||
{
|
||||
$this->template = $template;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Overtrue\EasySms\Contracts\GatewayInterface|null $gateway
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getData(GatewayInterface $gateway = null)
|
||||
{
|
||||
return is_callable($this->data) ? call_user_func($this->data, $gateway) : $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|callable $data
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setData($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getGateways()
|
||||
{
|
||||
return $this->gateways;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $gateways
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setGateways(array $gateways)
|
||||
{
|
||||
$this->gateways = $gateways;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $property
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __get($property)
|
||||
{
|
||||
if (property_exists($this, $property)) {
|
||||
return $this->$property;
|
||||
}
|
||||
}
|
||||
}
|
||||
89
vendor/overtrue/easy-sms/src/Messenger.php
vendored
Executable file
89
vendor/overtrue/easy-sms/src/Messenger.php
vendored
Executable file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms;
|
||||
|
||||
use Overtrue\EasySms\Contracts\MessageInterface;
|
||||
use Overtrue\EasySms\Contracts\PhoneNumberInterface;
|
||||
use Overtrue\EasySms\Exceptions\NoGatewayAvailableException;
|
||||
|
||||
/**
|
||||
* Class Messenger.
|
||||
*/
|
||||
class Messenger
|
||||
{
|
||||
const STATUS_SUCCESS = 'success';
|
||||
|
||||
const STATUS_FAILURE = 'failure';
|
||||
|
||||
/**
|
||||
* @var \Overtrue\EasySms\EasySms
|
||||
*/
|
||||
protected $easySms;
|
||||
|
||||
/**
|
||||
* Messenger constructor.
|
||||
*
|
||||
* @param \Overtrue\EasySms\EasySms $easySms
|
||||
*/
|
||||
public function __construct(EasySms $easySms)
|
||||
{
|
||||
$this->easySms = $easySms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message.
|
||||
*
|
||||
* @param \Overtrue\EasySms\Contracts\PhoneNumberInterface $to
|
||||
* @param \Overtrue\EasySms\Contracts\MessageInterface $message
|
||||
* @param array $gateways
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \Overtrue\EasySms\Exceptions\NoGatewayAvailableException
|
||||
*/
|
||||
public function send(PhoneNumberInterface $to, MessageInterface $message, array $gateways = [])
|
||||
{
|
||||
$results = [];
|
||||
$isSuccessful = false;
|
||||
|
||||
foreach ($gateways as $gateway => $config) {
|
||||
try {
|
||||
$results[$gateway] = [
|
||||
'gateway' => $gateway,
|
||||
'status' => self::STATUS_SUCCESS,
|
||||
'result' => $this->easySms->gateway($gateway)->send($to, $message, $config),
|
||||
];
|
||||
$isSuccessful = true;
|
||||
|
||||
break;
|
||||
} catch (\Exception $e) {
|
||||
$results[$gateway] = [
|
||||
'gateway' => $gateway,
|
||||
'status' => self::STATUS_FAILURE,
|
||||
'exception' => $e,
|
||||
];
|
||||
} catch (\Throwable $e) {
|
||||
$results[$gateway] = [
|
||||
'gateway' => $gateway,
|
||||
'status' => self::STATUS_FAILURE,
|
||||
'exception' => $e,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$isSuccessful) {
|
||||
throw new NoGatewayAvailableException($results);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
115
vendor/overtrue/easy-sms/src/PhoneNumber.php
vendored
Executable file
115
vendor/overtrue/easy-sms/src/PhoneNumber.php
vendored
Executable file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms;
|
||||
|
||||
/**
|
||||
* Class PhoneNumberInterface.
|
||||
*
|
||||
* @author overtrue <i@overtrue.me>
|
||||
*/
|
||||
class PhoneNumber implements \Overtrue\EasySms\Contracts\PhoneNumberInterface
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $number;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $IDDCode;
|
||||
|
||||
/**
|
||||
* PhoneNumberInterface constructor.
|
||||
*
|
||||
* @param int $numberWithoutIDDCode
|
||||
* @param string $IDDCode
|
||||
*/
|
||||
public function __construct($numberWithoutIDDCode, $IDDCode = null)
|
||||
{
|
||||
$this->number = $numberWithoutIDDCode;
|
||||
$this->IDDCode = $IDDCode ? intval(ltrim($IDDCode, '+0')) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 86.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getIDDCode()
|
||||
{
|
||||
return $this->IDDCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 18888888888.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNumber()
|
||||
{
|
||||
return $this->number;
|
||||
}
|
||||
|
||||
/**
|
||||
* +8618888888888.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUniversalNumber()
|
||||
{
|
||||
return $this->getPrefixedIDDCode('+').$this->number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 008618888888888.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getZeroPrefixedNumber()
|
||||
{
|
||||
return $this->getPrefixedIDDCode('00').$this->number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPrefixedIDDCode($prefix)
|
||||
{
|
||||
return $this->IDDCode ? $prefix.$this->IDDCode : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getUniversalNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify data which should be serialized to JSON.
|
||||
*
|
||||
* @see http://php.net/manual/en/jsonserializable.jsonserialize.php
|
||||
*
|
||||
* @return mixed data which can be serialized by <b>json_encode</b>,
|
||||
* which is a value of any type other than a resource
|
||||
*
|
||||
* @since 5.4.0
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->getUniversalNumber();
|
||||
}
|
||||
}
|
||||
32
vendor/overtrue/easy-sms/src/Strategies/OrderStrategy.php
vendored
Executable file
32
vendor/overtrue/easy-sms/src/Strategies/OrderStrategy.php
vendored
Executable file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Strategies;
|
||||
|
||||
use Overtrue\EasySms\Contracts\StrategyInterface;
|
||||
|
||||
/**
|
||||
* Class OrderStrategy.
|
||||
*/
|
||||
class OrderStrategy implements StrategyInterface
|
||||
{
|
||||
/**
|
||||
* Apply the strategy and return result.
|
||||
*
|
||||
* @param array $gateways
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function apply(array $gateways)
|
||||
{
|
||||
return array_keys($gateways);
|
||||
}
|
||||
}
|
||||
34
vendor/overtrue/easy-sms/src/Strategies/RandomStrategy.php
vendored
Executable file
34
vendor/overtrue/easy-sms/src/Strategies/RandomStrategy.php
vendored
Executable file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Strategies;
|
||||
|
||||
use Overtrue\EasySms\Contracts\StrategyInterface;
|
||||
|
||||
/**
|
||||
* Class RandomStrategy.
|
||||
*/
|
||||
class RandomStrategy implements StrategyInterface
|
||||
{
|
||||
/**
|
||||
* @param array $gateways
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function apply(array $gateways)
|
||||
{
|
||||
uasort($gateways, function () {
|
||||
return mt_rand() - mt_rand();
|
||||
});
|
||||
|
||||
return array_keys($gateways);
|
||||
}
|
||||
}
|
||||
143
vendor/overtrue/easy-sms/src/Support/Config.php
vendored
Executable file
143
vendor/overtrue/easy-sms/src/Support/Config.php
vendored
Executable file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Support;
|
||||
|
||||
use ArrayAccess;
|
||||
|
||||
/**
|
||||
* Class Config.
|
||||
*/
|
||||
class Config implements ArrayAccess
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Config constructor.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item from an array using "dot" notation.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
$config = $this->config;
|
||||
|
||||
if (isset($config[$key])) {
|
||||
return $config[$key];
|
||||
}
|
||||
|
||||
if (false === strpos($key, '.')) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
foreach (explode('.', $key) as $segment) {
|
||||
if (!is_array($config) || !array_key_exists($segment, $config)) {
|
||||
return $default;
|
||||
}
|
||||
$config = $config[$segment];
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a offset exists.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetexists.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* An offset to check for.
|
||||
* </p>
|
||||
*
|
||||
* @return bool true on success or false on failure.
|
||||
* </p>
|
||||
* <p>
|
||||
* The return value will be casted to boolean if non-boolean was returned
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return array_key_exists($offset, $this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to retrieve.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetget.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to retrieve.
|
||||
* </p>
|
||||
*
|
||||
* @return mixed Can return all value types
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->get($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to set.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetset.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to assign the value to.
|
||||
* </p>
|
||||
* @param mixed $value <p>
|
||||
* The value to set.
|
||||
* </p>
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (isset($this->config[$offset])) {
|
||||
$this->config[$offset] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to unset.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetunset.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to unset.
|
||||
* </p>
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
if (isset($this->config[$offset])) {
|
||||
unset($this->config[$offset]);
|
||||
}
|
||||
}
|
||||
}
|
||||
136
vendor/overtrue/easy-sms/src/Traits/HasHttpRequest.php
vendored
Executable file
136
vendor/overtrue/easy-sms/src/Traits/HasHttpRequest.php
vendored
Executable file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/easy-sms.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\EasySms\Traits;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Trait HasHttpRequest.
|
||||
*/
|
||||
trait HasHttpRequest
|
||||
{
|
||||
/**
|
||||
* Make a get request.
|
||||
*
|
||||
* @param string $endpoint
|
||||
* @param array $query
|
||||
* @param array $headers
|
||||
*
|
||||
* @return ResponseInterface|array|string
|
||||
*/
|
||||
protected function get($endpoint, $query = [], $headers = [])
|
||||
{
|
||||
return $this->request('get', $endpoint, [
|
||||
'headers' => $headers,
|
||||
'query' => $query,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a post request.
|
||||
*
|
||||
* @param string $endpoint
|
||||
* @param array $params
|
||||
* @param array $headers
|
||||
*
|
||||
* @return ResponseInterface|array|string
|
||||
*/
|
||||
protected function post($endpoint, $params = [], $headers = [])
|
||||
{
|
||||
return $this->request('post', $endpoint, [
|
||||
'headers' => $headers,
|
||||
'form_params' => $params,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a post request with json params.
|
||||
*
|
||||
* @param $endpoint
|
||||
* @param array $params
|
||||
* @param array $headers
|
||||
*
|
||||
* @return ResponseInterface|array|string
|
||||
*/
|
||||
protected function postJson($endpoint, $params = [], $headers = [])
|
||||
{
|
||||
return $this->request('post', $endpoint, [
|
||||
'headers' => $headers,
|
||||
'json' => $params,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a http request.
|
||||
*
|
||||
* @param string $method
|
||||
* @param string $endpoint
|
||||
* @param array $options http://docs.guzzlephp.org/en/latest/request-options.html
|
||||
*
|
||||
* @return ResponseInterface|array|string
|
||||
*/
|
||||
protected function request($method, $endpoint, $options = [])
|
||||
{
|
||||
return $this->unwrapResponse($this->getHttpClient($this->getBaseOptions())->{$method}($endpoint, $options));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return base Guzzle options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getBaseOptions()
|
||||
{
|
||||
$options = method_exists($this, 'getGuzzleOptions') ? $this->getGuzzleOptions() : [];
|
||||
|
||||
return \array_merge($options, [
|
||||
'base_uri' => method_exists($this, 'getBaseUri') ? $this->getBaseUri() : '',
|
||||
'timeout' => method_exists($this, 'getTimeout') ? $this->getTimeout() : 5.0,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return http client.
|
||||
*
|
||||
* @param array $options
|
||||
*
|
||||
* @return \GuzzleHttp\Client
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function getHttpClient(array $options = [])
|
||||
{
|
||||
return new Client($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert response contents to json.
|
||||
*
|
||||
* @param \Psr\Http\Message\ResponseInterface $response
|
||||
*
|
||||
* @return ResponseInterface|array|string
|
||||
*/
|
||||
protected function unwrapResponse(ResponseInterface $response)
|
||||
{
|
||||
$contentType = $response->getHeaderLine('Content-Type');
|
||||
$contents = $response->getBody()->getContents();
|
||||
|
||||
if (false !== stripos($contentType, 'json') || stripos($contentType, 'javascript')) {
|
||||
return json_decode($contents, true);
|
||||
} elseif (false !== stripos($contentType, 'xml')) {
|
||||
return json_decode(json_encode(simplexml_load_string($contents)), true);
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
}
|
||||
20
vendor/overtrue/flysystem-cos/.editorconfig
vendored
Executable file
20
vendor/overtrue/flysystem-cos/.editorconfig
vendored
Executable file
@@ -0,0 +1,20 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = false
|
||||
|
||||
[*.{vue,js,scss}]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
101
vendor/overtrue/flysystem-cos/README.md
vendored
Executable file
101
vendor/overtrue/flysystem-cos/README.md
vendored
Executable file
@@ -0,0 +1,101 @@
|
||||
<h1 align="center">Flysystem QCloud COS</h1>
|
||||
|
||||
<p align="center">:floppy_disk: Flysystem adapter for the Qcloud COS storage.</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/overtrue/flysystem-cos"><img src="https://travis-ci.org/overtrue/flysystem-cos.svg?branch=master" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/flysystem-cos"><img src="https://poser.pugx.org/overtrue/flysystem-cos/v/stable.svg" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/flysystem-cos"><img src="https://poser.pugx.org/overtrue/flysystem-cos/v/unstable.svg" alt="Latest Unstable Version"></a>
|
||||
<a href="https://scrutinizer-ci.com/g/overtrue/flysystem-cos/?branch=master"><img src="https://scrutinizer-ci.com/g/overtrue/flysystem-cos/badges/quality-score.png?b=master" alt="Scrutinizer Code Quality"></a>
|
||||
<a href="https://scrutinizer-ci.com/g/overtrue/flysystem-cos/?branch=master"><img src="https://scrutinizer-ci.com/g/overtrue/flysystem-cos/badges/coverage.png?b=master" alt="Code Coverage"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/flysystem-cos"><img src="https://poser.pugx.org/overtrue/flysystem-cos/downloads" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/flysystem-cos"><img src="https://poser.pugx.org/overtrue/flysystem-cos/license" alt="License"></a>
|
||||
</p>
|
||||
|
||||
|
||||
## Requirement
|
||||
|
||||
* PHP >= 7.0
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
$ composer require overtrue/flysystem-cos -vvv
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```php
|
||||
use League\Flysystem\Filesystem;
|
||||
use Overtrue\Flysystem\Cos\CosAdapter;
|
||||
|
||||
$config = [
|
||||
'region' => 'ap-guangzhou',
|
||||
'credentials' => [
|
||||
'appId' => 1234567889, // 域名中数字部分
|
||||
'secretId' => 'AKIDS5jNr5NNygGxxxxxxxxxxxxxxxxxx',
|
||||
'secretKey' => 'NfszEWmyDqGmao0a4XS8wxxxxxxxxxxxx',
|
||||
],
|
||||
'bucket' => 'test',
|
||||
'timeout' => 60,
|
||||
'connect_timeout' => 60,
|
||||
'cdn' => '您的 CDN 域名',
|
||||
'scheme' => 'https',
|
||||
'read_from_cdn' => false,
|
||||
];
|
||||
|
||||
$adapter = new CosAdapter($config);
|
||||
|
||||
$flysystem = new League\Flysystem\Filesystem($adapter);
|
||||
|
||||
```
|
||||
## API
|
||||
|
||||
```php
|
||||
|
||||
bool $flysystem->write('file.md', 'contents');
|
||||
|
||||
bool $flysystem->write('file.md', 'http://httpbin.org/robots.txt', ['mime' => 'application/redirect302']);
|
||||
|
||||
bool $flysystem->writeStream('file.md', fopen('path/to/your/local/file.jpg', 'r'));
|
||||
|
||||
bool $flysystem->update('file.md', 'new contents');
|
||||
|
||||
bool $flysystem->updateStream('file.md', fopen('path/to/your/local/file.jpg', 'r'));
|
||||
|
||||
bool $flysystem->rename('foo.md', 'bar.md');
|
||||
|
||||
bool $flysystem->copy('foo.md', 'foo2.md');
|
||||
|
||||
bool $flysystem->delete('file.md');
|
||||
|
||||
bool $flysystem->has('file.md');
|
||||
|
||||
string|false $flysystem->read('file.md');
|
||||
|
||||
array $flysystem->listContents();
|
||||
|
||||
array $flysystem->getMetadata('file.md');
|
||||
|
||||
int $flysystem->getSize('file.md');
|
||||
|
||||
string $flysystem->getAdapter()->getUrl('file.md');
|
||||
|
||||
string $flysystem->getMimetype('file.md');
|
||||
|
||||
int $flysystem->getTimestamp('file.md');
|
||||
```
|
||||
|
||||
## Plugins
|
||||
|
||||
TODO
|
||||
|
||||
## PHP 扩展包开发
|
||||
|
||||
> 想知道如何从零开始构建 PHP 扩展包?
|
||||
>
|
||||
> 请关注我的实战课程,我会在此课程中分享一些扩展开发经验 —— [《PHP 扩展包实战教程 - 从入门到发布》](https://learnku.com/courses/creating-package)
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
32
vendor/overtrue/flysystem-cos/composer.json
vendored
Executable file
32
vendor/overtrue/flysystem-cos/composer.json
vendored
Executable file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "overtrue/flysystem-cos",
|
||||
"description": "Flysystem adapter for the QCloud COS storage.",
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"league/flysystem": "^1.0",
|
||||
"qcloud/cos-sdk-v5": "^2.0.0",
|
||||
"guzzlehttp/guzzle": "^6.3|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php": ">=7.1",
|
||||
"phpunit/phpunit": "^8.0",
|
||||
"mockery/mockery": "~1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Overtrue\\Flysystem\\Cos\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Overtrue\\Flysystem\\Cos\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "overtrue",
|
||||
"email": "i@overtrue.me"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
}
|
||||
560
vendor/overtrue/flysystem-cos/src/CosAdapter.php
vendored
Executable file
560
vendor/overtrue/flysystem-cos/src/CosAdapter.php
vendored
Executable file
@@ -0,0 +1,560 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/flysystem-cos.
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Flysystem\Cos;
|
||||
|
||||
use GuzzleHttp\Client as HttpClient;
|
||||
use League\Flysystem\Adapter\AbstractAdapter;
|
||||
use League\Flysystem\Adapter\CanOverwriteFiles;
|
||||
use League\Flysystem\AdapterInterface;
|
||||
use League\Flysystem\Config;
|
||||
use Qcloud\Cos\Client;
|
||||
use Qcloud\Cos\Exception\NoSuchKeyException;
|
||||
|
||||
/**
|
||||
* Class CosAdapter.
|
||||
*/
|
||||
class CosAdapter extends AbstractAdapter implements CanOverwriteFiles
|
||||
{
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @var \GuzzleHttp\Client
|
||||
*/
|
||||
protected $httpClient;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* CosAdapter constructor.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
if (!empty($this->config['cdn'])) {
|
||||
$this->setPathPrefix($this->config['cdn']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getBucket()
|
||||
{
|
||||
return $this->config['bucket'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAppId()
|
||||
{
|
||||
return $this->config['credentials']['appId'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRegion()
|
||||
{
|
||||
return $this->config['region'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSourcePath($path)
|
||||
{
|
||||
return sprintf('%s.cos.%s.myqcloud.com/%s',
|
||||
$this->getBucket(), $this->getRegion(), $path
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl($path)
|
||||
{
|
||||
if (!empty($this->config['cdn'])) {
|
||||
return $this->applyPathPrefix($path);
|
||||
}
|
||||
|
||||
$options = [
|
||||
'Scheme' => $this->config['scheme'] ?? 'http',
|
||||
];
|
||||
|
||||
return $this->getClient()->getObjectUrl(
|
||||
$this->getBucket(), $path, null, $options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string|int $expiration
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTemporaryUrl($path, $expiration, array $options = [])
|
||||
{
|
||||
$options = array_merge($options, ['Scheme' => $this->config['scheme'] ?? 'http']);
|
||||
|
||||
$expiration = date('c', !\is_numeric($expiration) ? \strtotime($expiration) : \intval($expiration));
|
||||
|
||||
$objectUrl = $this->getClient()->getObjectUrl(
|
||||
$this->getBucket(), $path, $expiration, $options
|
||||
);
|
||||
|
||||
$url = parse_url($objectUrl);
|
||||
|
||||
if (!empty($this->config['cdn'])) {
|
||||
return \sprintf(
|
||||
'%s/%s?%s',
|
||||
\rtrim($this->config['cdn'], '/'),
|
||||
\ltrim(urldecode($url['path']), '/'),
|
||||
$url['query']
|
||||
);
|
||||
}
|
||||
|
||||
return $objectUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $contents
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function write($path, $contents, Config $config)
|
||||
{
|
||||
$options = $this->getUploadOptions($config);
|
||||
|
||||
return $this->getClient()->upload($this->getBucket(), $path, $contents, $options['params']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param resource $resource
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function writeStream($path, $resource, Config $config)
|
||||
{
|
||||
$options = $this->getUploadOptions($config);
|
||||
|
||||
return $this->getClient()->upload(
|
||||
$this->getBucket(),
|
||||
$path,
|
||||
stream_get_contents($resource, -1, 0),
|
||||
$options['params']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $contents
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function update($path, $contents, Config $config)
|
||||
{
|
||||
return $this->write($path, $contents, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param resource $resource
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function updateStream($path, $resource, Config $config)
|
||||
{
|
||||
return $this->writeStream($path, $resource, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $to
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function rename($path, $to)
|
||||
{
|
||||
$result = $this->copy($path, $to);
|
||||
|
||||
$this->delete($path);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $to
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function copy($path, $to)
|
||||
{
|
||||
$source = [
|
||||
'Region' => $this->getRegion(),
|
||||
'Bucket' => $this->getBucket(),
|
||||
'Key' => $path,
|
||||
];
|
||||
|
||||
return (bool) $this->getClient()->copy($this->getBucket(), $to, $source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($path)
|
||||
{
|
||||
return (bool) $this->getClient()->deleteObject([
|
||||
'Bucket' => $this->getBucket(),
|
||||
'Key' => $path,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $dirname
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteDir($dirname)
|
||||
{
|
||||
$response = $this->listObjects($dirname);
|
||||
|
||||
if (empty($response['Contents'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$keys = array_map(function ($item) {
|
||||
return ['Key' => $item['Key']];
|
||||
}, (array) $response['Contents']);
|
||||
|
||||
return (bool) $this->getClient()->deleteObjects([
|
||||
'Bucket' => $this->getBucket(),
|
||||
'Objects' => $keys,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $dirname
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function createDir($dirname, Config $config)
|
||||
{
|
||||
return $this->getClient()->putObject([
|
||||
'Bucket' => $this->getBucket(),
|
||||
'Key' => $dirname.'/',
|
||||
'Body' => '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $visibility
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function setVisibility($path, $visibility)
|
||||
{
|
||||
return (bool) $this->getClient()->PutObjectAcl([
|
||||
'Bucket' => $this->getBucket(),
|
||||
'Key' => $path,
|
||||
'ACL' => $this->normalizeVisibility($visibility),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has($path)
|
||||
{
|
||||
try {
|
||||
return (bool) $this->getMetadata($path);
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function read($path)
|
||||
{
|
||||
try {
|
||||
if ($this->config['read_from_cdn']) {
|
||||
$response = $this->getHttpClient()
|
||||
->get($this->getTemporaryUrl($path, date('+5 min')))
|
||||
->getBody()
|
||||
->getContents();
|
||||
} else {
|
||||
$response = $this->getClient()->getObject([
|
||||
'Bucket' => $this->getBucket(),
|
||||
'Key' => $path,
|
||||
])['Body'];
|
||||
}
|
||||
|
||||
return ['contents' => (string) $response];
|
||||
} catch (\Throwable $e) {
|
||||
return null;
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client ?: $this->client = new Client($this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Qcloud\Cos\Client $client
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setClient(Client $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \GuzzleHttp\Client
|
||||
*/
|
||||
public function getHttpClient()
|
||||
{
|
||||
return $this->httpClient ?: $this->httpClient = new HttpClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \GuzzleHttp\Client $client
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setHttpClient(HttpClient $client)
|
||||
{
|
||||
$this->httpClient = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function readStream($path)
|
||||
{
|
||||
try {
|
||||
$temporaryUrl = $this->getTemporaryUrl($path, \strtotime('+5 min'));
|
||||
|
||||
$stream = $this->getHttpClient()
|
||||
->get($temporaryUrl, ['stream' => true])
|
||||
->getBody()
|
||||
->detach();
|
||||
|
||||
return ['stream' => $stream];
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $directory
|
||||
* @param bool $recursive
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function listContents($directory = '', $recursive = false)
|
||||
{
|
||||
$list = [];
|
||||
|
||||
$response = $this->listObjects($directory, $recursive);
|
||||
|
||||
foreach ((array) $response['Contents'] as $content) {
|
||||
$list[] = $this->normalizeFileInfo($content);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getMetadata($path)
|
||||
{
|
||||
return $this->getClient()->headObject([
|
||||
'Bucket' => $this->getBucket(),
|
||||
'Key' => $path,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getSize($path)
|
||||
{
|
||||
$meta = $this->getMetadata($path);
|
||||
|
||||
return isset($meta['ContentLength']) ? ['size' => $meta['ContentLength']] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getMimetype($path)
|
||||
{
|
||||
$meta = $this->getMetadata($path);
|
||||
|
||||
return isset($meta['ContentType']) ? ['mimetype' => $meta['ContentType']] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getTimestamp($path)
|
||||
{
|
||||
$meta = $this->getMetadata($path);
|
||||
|
||||
return isset($meta['LastModified']) ? ['timestamp' => strtotime($meta['LastModified'])] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getVisibility($path)
|
||||
{
|
||||
$meta = $this->getClient()->getObjectAcl([
|
||||
'Bucket' => $this->getBucket(),
|
||||
'Key' => $path,
|
||||
]);
|
||||
|
||||
foreach ($meta->get('Grants') as $grant) {
|
||||
if ('READ' === $grant['Permission'] && false !== strpos($grant['Grantee']['URI'] ?? '', 'global/AllUsers')) {
|
||||
return ['visibility' => AdapterInterface::VISIBILITY_PUBLIC];
|
||||
}
|
||||
}
|
||||
|
||||
return ['visibility' => AdapterInterface::VISIBILITY_PRIVATE];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $content
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function normalizeFileInfo(array $content)
|
||||
{
|
||||
$path = pathinfo($content['Key']);
|
||||
|
||||
return [
|
||||
'type' => '/' === substr($content['Key'], -1) ? 'dir' : 'file',
|
||||
'path' => $content['Key'],
|
||||
'size' => \intval($content['Size']),
|
||||
'dirname' => \strval($path['dirname']),
|
||||
'basename' => \strval($path['basename']),
|
||||
'filename' => strval($path['filename']),
|
||||
'timestamp' => \strtotime($content['LastModified']),
|
||||
'extension' => $path['extension'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $directory
|
||||
* @param bool $recursive
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function listObjects($directory = '', $recursive = false)
|
||||
{
|
||||
return $this->getClient()->listObjects([
|
||||
'Bucket' => $this->getBucket(),
|
||||
'Prefix' => ('' === (string) $directory) ? '' : ($directory.'/'),
|
||||
'Delimiter' => $recursive ? '' : '/',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Config $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUploadOptions(Config $config)
|
||||
{
|
||||
$options = ['params' => []];
|
||||
|
||||
if ($config->has('params')) {
|
||||
$options['params'] = (array) $config->get('params');
|
||||
}
|
||||
|
||||
if ($config->has('visibility')) {
|
||||
$options['params']['ACL'] = $this->normalizeVisibility($config->get('visibility'));
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $visibility
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function normalizeVisibility($visibility)
|
||||
{
|
||||
switch ($visibility) {
|
||||
case AdapterInterface::VISIBILITY_PUBLIC:
|
||||
$visibility = 'public-read';
|
||||
break;
|
||||
}
|
||||
|
||||
return $visibility;
|
||||
}
|
||||
}
|
||||
19
vendor/overtrue/flysystem-cos/src/Plugins/FileUrl.php
vendored
Executable file
19
vendor/overtrue/flysystem-cos/src/Plugins/FileUrl.php
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Overtrue\Flysystem\Cos\Plugins;
|
||||
|
||||
use League\Flysystem\Plugin\AbstractPlugin;
|
||||
|
||||
class FileUrl extends AbstractPlugin
|
||||
{
|
||||
public function getMethod()
|
||||
{
|
||||
return 'getUrl';
|
||||
}
|
||||
|
||||
public function handle($path)
|
||||
{
|
||||
return $this->filesystem->getAdapter()->getUrl($path);
|
||||
}
|
||||
}
|
||||
9
vendor/overtrue/socialite/.github/FUNDING.yml
vendored
Executable file
9
vendor/overtrue/socialite/.github/FUNDING.yml
vendored
Executable file
@@ -0,0 +1,9 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: overtrue
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
custom: # Replace with a single custom sponsorship URL
|
||||
9
vendor/overtrue/socialite/.gitignore
vendored
Executable file
9
vendor/overtrue/socialite/.gitignore
vendored
Executable file
@@ -0,0 +1,9 @@
|
||||
/vendor
|
||||
composer.phar
|
||||
composer.lock
|
||||
.DS_Store
|
||||
/.idea
|
||||
Thumbs.db
|
||||
/*.php
|
||||
sftp-config.json
|
||||
.php_cs.cache
|
||||
28
vendor/overtrue/socialite/.php_cs
vendored
Executable file
28
vendor/overtrue/socialite/.php_cs
vendored
Executable file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
$header = <<<EOF
|
||||
This file is part of the overtrue/socialite.
|
||||
|
||||
(c) overtrue <i@overtrue.me>
|
||||
|
||||
This source file is subject to the MIT license that is bundled
|
||||
with this source code in the file LICENSE.
|
||||
EOF;
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
->setRiskyAllowed(true)
|
||||
->setRules(array(
|
||||
'@Symfony' => true,
|
||||
'header_comment' => array('header' => $header),
|
||||
'array_syntax' => array('syntax' => 'short'),
|
||||
'ordered_imports' => true,
|
||||
'no_useless_else' => true,
|
||||
'no_useless_return' => true,
|
||||
'php_unit_construct' => true,
|
||||
'php_unit_strict' => true,
|
||||
))
|
||||
->setFinder(
|
||||
PhpCsFixer\Finder::create()
|
||||
->exclude('vendor')
|
||||
->in(__DIR__)
|
||||
)
|
||||
;
|
||||
13
vendor/overtrue/socialite/.travis.yml
vendored
Executable file
13
vendor/overtrue/socialite/.travis.yml
vendored
Executable file
@@ -0,0 +1,13 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
|
||||
sudo: false
|
||||
dist: trusty
|
||||
|
||||
install: travis_retry composer install --no-interaction --prefer-source
|
||||
|
||||
script: vendor/bin/phpunit --verbose
|
||||
267
vendor/overtrue/socialite/README.md
vendored
Executable file
267
vendor/overtrue/socialite/README.md
vendored
Executable file
@@ -0,0 +1,267 @@
|
||||
<h1 align="center"> Socialite</h1>
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/overtrue/socialite"><img src="https://travis-ci.org/overtrue/socialite.svg?branch=master" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/socialite"><img src="https://poser.pugx.org/overtrue/socialite/v/stable.svg" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/socialite"><img src="https://poser.pugx.org/overtrue/socialite/v/unstable.svg" alt="Latest Unstable Version"></a>
|
||||
<a href="https://scrutinizer-ci.com/g/overtrue/socialite/build-status/master"><img src="https://scrutinizer-ci.com/g/overtrue/socialite/badges/build.png?b=master" alt="Build Status"></a>
|
||||
<a href="https://scrutinizer-ci.com/g/overtrue/socialite/?branch=master"><img src="https://scrutinizer-ci.com/g/overtrue/socialite/badges/quality-score.png?b=master" alt="Scrutinizer Code Quality"></a>
|
||||
<a href="https://scrutinizer-ci.com/g/overtrue/socialite/?branch=master"><img src="https://scrutinizer-ci.com/g/overtrue/socialite/badges/coverage.png?b=master" alt="Code Coverage"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/socialite"><img src="https://poser.pugx.org/overtrue/socialite/downloads" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/socialite"><img src="https://poser.pugx.org/overtrue/socialite/license" alt="License"></a>
|
||||
</p>
|
||||
|
||||
|
||||
<p align="center">Socialite is an OAuth2 Authentication tool. It is inspired by <a href="https://github.com/laravel/socialite">laravel/socialite</a>, You can easily use it in any PHP project.</p>
|
||||
|
||||
# Requirement
|
||||
|
||||
```
|
||||
PHP >= 5.6
|
||||
```
|
||||
# Installation
|
||||
|
||||
```shell
|
||||
$ composer require "overtrue/socialite" -vvv
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
For Laravel 5: [overtrue/laravel-socialite](https://github.com/overtrue/laravel-socialite)
|
||||
|
||||
`authorize.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Overtrue\Socialite\SocialiteManager;
|
||||
|
||||
$config = [
|
||||
'github' => [
|
||||
'client_id' => 'your-app-id',
|
||||
'client_secret' => 'your-app-secret',
|
||||
'redirect' => 'http://localhost/socialite/callback.php',
|
||||
],
|
||||
];
|
||||
|
||||
$socialite = new SocialiteManager($config);
|
||||
|
||||
$response = $socialite->driver('github')->redirect();
|
||||
|
||||
echo $response;// or $response->send();
|
||||
```
|
||||
|
||||
`callback.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Overtrue\Socialite\SocialiteManager;
|
||||
|
||||
$config = [
|
||||
'github' => [
|
||||
'client_id' => 'your-app-id',
|
||||
'client_secret' => 'your-app-secret',
|
||||
'redirect' => 'http://localhost/socialite/callback.php',
|
||||
],
|
||||
];
|
||||
|
||||
$socialite = new SocialiteManager($config);
|
||||
|
||||
$user = $socialite->driver('github')->user();
|
||||
|
||||
$user->getId(); // 1472352
|
||||
$user->getNickname(); // "overtrue"
|
||||
$user->getUsername(); // "overtrue"
|
||||
$user->getName(); // "安正超"
|
||||
$user->getEmail(); // "anzhengchao@gmail.com"
|
||||
$user->getProviderName(); // GitHub
|
||||
...
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
Now we support the following sites:
|
||||
|
||||
`facebook`, `github`, `google`, `linkedin`, `outlook`, `weibo`, `taobao`, `qq`, `wechat`, `douyin`, `baidu`, `feishu`, and `douban`.
|
||||
|
||||
Each driver uses the same configuration keys: `client_id`, `client_secret`, `redirect`.
|
||||
|
||||
Example:
|
||||
```
|
||||
...
|
||||
'weibo' => [
|
||||
'client_id' => 'your-app-id',
|
||||
'client_secret' => 'your-app-secret',
|
||||
'redirect' => 'http://localhost/socialite/callback.php',
|
||||
],
|
||||
...
|
||||
```
|
||||
|
||||
### Scope
|
||||
|
||||
Before redirecting the user, you may also set "scopes" on the request using the scope method. This method will overwrite all existing scopes:
|
||||
|
||||
```php
|
||||
$response = $socialite->driver('github')
|
||||
->scopes(['scope1', 'scope2'])->redirect();
|
||||
|
||||
```
|
||||
|
||||
### Redirect URL
|
||||
|
||||
You may also want to dynamicly set `redirect`,you can use the following methods to change the `redirect` URL:
|
||||
|
||||
```php
|
||||
$socialite->redirect($url);
|
||||
// or
|
||||
$socialite->withRedirectUrl($url)->redirect();
|
||||
// or
|
||||
$socialite->setRedirectUrl($url)->redirect();
|
||||
```
|
||||
|
||||
> WeChat scopes:
|
||||
- `snsapi_base`, `snsapi_userinfo` - Used to Media Platform Authentication.
|
||||
- `snsapi_login` - Used to web Authentication.
|
||||
|
||||
### Additional parameters
|
||||
|
||||
To include any optional parameters in the request, call the with method with an associative array:
|
||||
|
||||
```php
|
||||
$response = $socialite->driver('google')
|
||||
->with(['hd' => 'example.com'])->redirect();
|
||||
```
|
||||
|
||||
### User interface
|
||||
|
||||
#### Standard user api:
|
||||
|
||||
```php
|
||||
|
||||
$user = $socialite->driver('weibo')->user();
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1472352,
|
||||
"nickname": "overtrue",
|
||||
"name": "安正超",
|
||||
"email": "anzhengchao@gmail.com",
|
||||
"avatar": "https://avatars.githubusercontent.com/u/1472352?v=3",
|
||||
"original": {
|
||||
"login": "overtrue",
|
||||
"id": 1472352,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1472352?v=3",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/overtrue",
|
||||
"html_url": "https://github.com/overtrue",
|
||||
...
|
||||
},
|
||||
"token": {
|
||||
"access_token": "5b1dc56d64fffbd052359f032716cc4e0a1cb9a0",
|
||||
"token_type": "bearer",
|
||||
"scope": "user:email"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can fetch the user attribute as a array keys like these:
|
||||
|
||||
```php
|
||||
$user['id']; // 1472352
|
||||
$user['nickname']; // "overtrue"
|
||||
$user['name']; // "安正超"
|
||||
$user['email']; // "anzhengchao@gmail.com"
|
||||
...
|
||||
```
|
||||
|
||||
Or using the method:
|
||||
|
||||
```php
|
||||
$user->getId();
|
||||
$user->getNickname();
|
||||
$user->getName();
|
||||
$user->getEmail();
|
||||
$user->getAvatar();
|
||||
$user->getOriginal();
|
||||
$user->getToken();// or $user->getAccessToken()
|
||||
$user->getProviderName(); // GitHub/Google/Facebook...
|
||||
```
|
||||
|
||||
#### Get original response from OAuth API
|
||||
|
||||
The `$user->getOriginal()` method will return an array of the API raw response.
|
||||
|
||||
#### Get access token Object
|
||||
|
||||
You can get the access token instance of current session by call `$user->getToken()` or `$user->getAccessToken()` or `$user['token']` .
|
||||
|
||||
|
||||
### Get user with access token
|
||||
|
||||
```php
|
||||
$accessToken = new AccessToken(['access_token' => $accessToken]);
|
||||
$user = $socialite->user($accessToken);
|
||||
```
|
||||
|
||||
|
||||
### Custom Session or Request instance.
|
||||
|
||||
You can set the request with your custom `Request` instance which instanceof `Symfony\Component\HttpFoundation\Request` before you call `driver` method.
|
||||
|
||||
|
||||
```php
|
||||
|
||||
$request = new Request(); // or use AnotherCustomRequest.
|
||||
|
||||
$socialite = new SocialiteManager($config, $request);
|
||||
```
|
||||
|
||||
Or set request to `SocialiteManager` instance:
|
||||
|
||||
```php
|
||||
$socialite->setRequest($request);
|
||||
```
|
||||
|
||||
You can get the request from the `SocialiteManager` instance by `getRequest()`:
|
||||
|
||||
```php
|
||||
$request = $socialite->getRequest();
|
||||
```
|
||||
|
||||
#### Set custom session manager.
|
||||
|
||||
By default, the `SocialiteManager` uses the `Symfony\Component\HttpFoundation\Session\Session` instance as session manager, you can change it as follows:
|
||||
|
||||
```php
|
||||
$session = new YourCustomSessionManager();
|
||||
$socialite->getRequest()->setSession($session);
|
||||
```
|
||||
|
||||
> Your custom session manager must be implement the [`Symfony\Component\HttpFoundation\Session\SessionInterface`](http://api.symfony.com/3.0/Symfony/Component/HttpFoundation/Session/SessionInterface.html).
|
||||
|
||||
Enjoy it! :heart:
|
||||
|
||||
# Reference
|
||||
|
||||
- [Google - OpenID Connect](https://developers.google.com/identity/protocols/OpenIDConnect)
|
||||
- [Facebook - Graph API](https://developers.facebook.com/docs/graph-api)
|
||||
- [Linkedin - Authenticating with OAuth 2.0](https://developer.linkedin.com/docs/oauth2)
|
||||
- [微博 - OAuth 2.0 授权机制说明](http://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E)
|
||||
- [QQ - OAuth 2.0 登录QQ](http://wiki.connect.qq.com/oauth2-0%E7%AE%80%E4%BB%8B)
|
||||
- [微信公众平台 - OAuth文档](http://mp.weixin.qq.com/wiki/9/01f711493b5a02f24b04365ac5d8fd95.html)
|
||||
- [微信开放平台 - 网站应用微信登录开发指南](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN)
|
||||
- [微信开放平台 - 代公众号发起网页授权](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318590&token=&lang=zh_CN)
|
||||
- [豆瓣 - OAuth 2.0 授权机制说明](http://developers.douban.com/wiki/?title=oauth2)
|
||||
- [抖音 - 网站应用开发指南](http://open.douyin.com/platform/doc)
|
||||
- [飞书 - 授权说明](https://open.feishu.cn/document/ukTMukTMukTM/uMTNz4yM1MjLzUzM)
|
||||
|
||||
## PHP 扩展包开发
|
||||
|
||||
> 想知道如何从零开始构建 PHP 扩展包?
|
||||
>
|
||||
> 请关注我的实战课程,我会在此课程中分享一些扩展开发经验 —— [《PHP 扩展包实战教程 - 从入门到发布》](https://learnku.com/courses/creating-package)
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
34
vendor/overtrue/socialite/composer.json
vendored
Executable file
34
vendor/overtrue/socialite/composer.json
vendored
Executable file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "overtrue/socialite",
|
||||
"description": "A collection of OAuth 2 packages that extracts from laravel/socialite.",
|
||||
"keywords": [
|
||||
"OAuth",
|
||||
"social",
|
||||
"login",
|
||||
"Weibo",
|
||||
"WeChat",
|
||||
"QQ"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Overtrue\\Socialite\\": "src/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6",
|
||||
"guzzlehttp/guzzle": "^5.0|^6.0|^7.0",
|
||||
"symfony/http-foundation": "^2.7|^3.0|^4.0|^5.0",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~1.2",
|
||||
"phpunit/phpunit": "^6.0|^7.0|^8.0|^9.0"
|
||||
},
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "overtrue",
|
||||
"email": "anzhengchao@gmail.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
18
vendor/overtrue/socialite/phpunit.xml
vendored
Executable file
18
vendor/overtrue/socialite/phpunit.xml
vendored
Executable file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Package Test Suite">
|
||||
<directory suffix=".php">./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
84
vendor/overtrue/socialite/src/AccessToken.php
vendored
Executable file
84
vendor/overtrue/socialite/src/AccessToken.php
vendored
Executable file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
use ArrayAccess;
|
||||
use InvalidArgumentException;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* Class AccessToken.
|
||||
*/
|
||||
class AccessToken implements AccessTokenInterface, ArrayAccess, JsonSerializable
|
||||
{
|
||||
use HasAttributes;
|
||||
|
||||
/**
|
||||
* AccessToken constructor.
|
||||
*
|
||||
* @param array $attributes
|
||||
*/
|
||||
public function __construct(array $attributes)
|
||||
{
|
||||
if (empty($attributes['access_token'])) {
|
||||
throw new InvalidArgumentException('The key "access_token" could not be empty.');
|
||||
}
|
||||
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the access token string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return $this->getAttribute('access_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the refresh token string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRefreshToken()
|
||||
{
|
||||
return $this->getAttribute('refresh_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set refresh token into this object.
|
||||
*
|
||||
* @param string $token
|
||||
*/
|
||||
public function setRefreshToken($token)
|
||||
{
|
||||
$this->setAttribute('refresh_token', $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return strval($this->getAttribute('access_token', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->getToken();
|
||||
}
|
||||
}
|
||||
25
vendor/overtrue/socialite/src/AccessTokenInterface.php
vendored
Executable file
25
vendor/overtrue/socialite/src/AccessTokenInterface.php
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
/**
|
||||
* Interface AccessTokenInterface.
|
||||
*/
|
||||
interface AccessTokenInterface
|
||||
{
|
||||
/**
|
||||
* Return the access token string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getToken();
|
||||
}
|
||||
35
vendor/overtrue/socialite/src/AuthorizeFailedException.php
vendored
Executable file
35
vendor/overtrue/socialite/src/AuthorizeFailedException.php
vendored
Executable file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
class AuthorizeFailedException extends \RuntimeException
|
||||
{
|
||||
/**
|
||||
* Response body.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $body;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $body
|
||||
*/
|
||||
public function __construct($message, $body)
|
||||
{
|
||||
parent::__construct($message, -1);
|
||||
|
||||
$this->body = $body;
|
||||
}
|
||||
}
|
||||
180
vendor/overtrue/socialite/src/Config.php
vendored
Executable file
180
vendor/overtrue/socialite/src/Config.php
vendored
Executable file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
use ArrayAccess;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Class Config.
|
||||
*/
|
||||
class Config implements ArrayAccess
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Config constructor.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item from an array using "dot" notation.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
$config = $this->config;
|
||||
|
||||
if (is_null($key)) {
|
||||
return $config;
|
||||
}
|
||||
if (isset($config[$key])) {
|
||||
return $config[$key];
|
||||
}
|
||||
foreach (explode('.', $key) as $segment) {
|
||||
if (!is_array($config) || !array_key_exists($segment, $config)) {
|
||||
return $default;
|
||||
}
|
||||
$config = $config[$segment];
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an array item to a given value using "dot" notation.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
if (is_null($key)) {
|
||||
throw new InvalidArgumentException('Invalid config key.');
|
||||
}
|
||||
|
||||
$keys = explode('.', $key);
|
||||
$config = &$this->config;
|
||||
|
||||
while (count($keys) > 1) {
|
||||
$key = array_shift($keys);
|
||||
if (!isset($config[$key]) || !is_array($config[$key])) {
|
||||
$config[$key] = [];
|
||||
}
|
||||
$config = &$config[$key];
|
||||
}
|
||||
|
||||
$config[array_shift($keys)] = $value;
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given configuration value exists.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has($key)
|
||||
{
|
||||
return (bool) $this->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a offset exists.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetexists.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* An offset to check for.
|
||||
* </p>
|
||||
*
|
||||
* @return bool true on success or false on failure.
|
||||
* </p>
|
||||
* <p>
|
||||
* The return value will be casted to boolean if non-boolean was returned
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return array_key_exists($offset, $this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to retrieve.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetget.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to retrieve.
|
||||
* </p>
|
||||
*
|
||||
* @return mixed Can return all value types
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->get($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to set.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetset.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to assign the value to.
|
||||
* </p>
|
||||
* @param mixed $value <p>
|
||||
* The value to set.
|
||||
* </p>
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->set($offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to unset.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetunset.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to unset.
|
||||
* </p>
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
$this->set($offset, null);
|
||||
}
|
||||
}
|
||||
27
vendor/overtrue/socialite/src/FactoryInterface.php
vendored
Executable file
27
vendor/overtrue/socialite/src/FactoryInterface.php
vendored
Executable file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
/**
|
||||
* Interface FactoryInterface.
|
||||
*/
|
||||
interface FactoryInterface
|
||||
{
|
||||
/**
|
||||
* Get an OAuth provider implementation.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @return \Overtrue\Socialite\ProviderInterface
|
||||
*/
|
||||
public function driver($driver);
|
||||
}
|
||||
135
vendor/overtrue/socialite/src/HasAttributes.php
vendored
Executable file
135
vendor/overtrue/socialite/src/HasAttributes.php
vendored
Executable file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
/**
|
||||
* Trait HasAttributes.
|
||||
*/
|
||||
trait HasAttributes
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [];
|
||||
|
||||
/**
|
||||
* Return the attributes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the extra attribute.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttribute($name, $default = null)
|
||||
{
|
||||
return isset($this->attributes[$name]) ? $this->attributes[$name] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set extra attributes.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAttribute($name, $value)
|
||||
{
|
||||
$this->attributes[$name] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the given array onto the user's properties.
|
||||
*
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function merge(array $attributes)
|
||||
{
|
||||
$this->attributes = array_merge($this->attributes, $attributes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return array_key_exists($offset, $this->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->getAttribute($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->setAttribute($offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->attributes[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __get($property)
|
||||
{
|
||||
return $this->getAttribute($property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->getAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSON.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toJSON()
|
||||
{
|
||||
return json_encode($this->getAttributes(), JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
}
|
||||
16
vendor/overtrue/socialite/src/InvalidArgumentException.php
vendored
Executable file
16
vendor/overtrue/socialite/src/InvalidArgumentException.php
vendored
Executable file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
class InvalidArgumentException extends \InvalidArgumentException
|
||||
{
|
||||
}
|
||||
16
vendor/overtrue/socialite/src/InvalidStateException.php
vendored
Executable file
16
vendor/overtrue/socialite/src/InvalidStateException.php
vendored
Executable file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
class InvalidStateException extends \InvalidArgumentException
|
||||
{
|
||||
}
|
||||
31
vendor/overtrue/socialite/src/ProviderInterface.php
vendored
Executable file
31
vendor/overtrue/socialite/src/ProviderInterface.php
vendored
Executable file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
interface ProviderInterface
|
||||
{
|
||||
/**
|
||||
* Redirect the user to the authentication page for the provider.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
*/
|
||||
public function redirect();
|
||||
|
||||
/**
|
||||
* Get the User instance for the authenticated user.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
public function user(AccessTokenInterface $token = null);
|
||||
}
|
||||
602
vendor/overtrue/socialite/src/Providers/AbstractProvider.php
vendored
Executable file
602
vendor/overtrue/socialite/src/Providers/AbstractProvider.php
vendored
Executable file
@@ -0,0 +1,602 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Overtrue\Socialite\AccessToken;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\AuthorizeFailedException;
|
||||
use Overtrue\Socialite\Config;
|
||||
use Overtrue\Socialite\InvalidStateException;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Class AbstractProvider.
|
||||
*/
|
||||
abstract class AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* Provider name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The HTTP request instance.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Driver config.
|
||||
*
|
||||
* @var Config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The client ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $clientId;
|
||||
|
||||
/**
|
||||
* The client secret.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $clientSecret;
|
||||
|
||||
/**
|
||||
* @var \Overtrue\Socialite\AccessTokenInterface
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* The redirect URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectUrl;
|
||||
|
||||
/**
|
||||
* The custom parameters to be sent with the request.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parameters = [];
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [];
|
||||
|
||||
/**
|
||||
* The separating character for the requested scopes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $scopeSeparator = ',';
|
||||
|
||||
/**
|
||||
* The type of the encoding in the query.
|
||||
*
|
||||
* @var int Can be either PHP_QUERY_RFC3986 or PHP_QUERY_RFC1738
|
||||
*/
|
||||
protected $encodingType = PHP_QUERY_RFC1738;
|
||||
|
||||
/**
|
||||
* Indicates if the session state should be utilized.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $stateless = false;
|
||||
|
||||
/**
|
||||
* The options for guzzle\client.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $guzzleOptions = ['http_errors' => false];
|
||||
|
||||
/**
|
||||
* Create a new provider instance.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(Request $request, $config)
|
||||
{
|
||||
// 兼容处理
|
||||
if (!\is_array($config)) {
|
||||
$config = [
|
||||
'client_id' => \func_get_arg(1),
|
||||
'client_secret' => \func_get_arg(2),
|
||||
'redirect' => \func_get_arg(3) ?: null,
|
||||
];
|
||||
}
|
||||
$this->config = new Config($config);
|
||||
$this->request = $request;
|
||||
$this->clientId = $config['client_id'];
|
||||
$this->clientSecret = $config['client_secret'];
|
||||
$this->redirectUrl = isset($config['redirect']) ? $config['redirect'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getAuthUrl($state);
|
||||
|
||||
/**
|
||||
* Get the token URL for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getTokenUrl();
|
||||
|
||||
/**
|
||||
* Get the raw user for the given access token.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getUserByToken(AccessTokenInterface $token);
|
||||
|
||||
/**
|
||||
* Map the raw user array to a Socialite User instance.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
abstract protected function mapUserToObject(array $user);
|
||||
|
||||
/**
|
||||
* Redirect the user of the application to the provider's authentication screen.
|
||||
*
|
||||
* @param string $redirectUrl
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
*/
|
||||
public function redirect($redirectUrl = null)
|
||||
{
|
||||
$state = null;
|
||||
|
||||
if (!is_null($redirectUrl)) {
|
||||
$this->redirectUrl = $redirectUrl;
|
||||
}
|
||||
|
||||
if ($this->usesState()) {
|
||||
$state = $this->makeState();
|
||||
}
|
||||
|
||||
return new RedirectResponse($this->getAuthUrl($state));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function user(AccessTokenInterface $token = null)
|
||||
{
|
||||
if (is_null($token) && $this->hasInvalidState()) {
|
||||
throw new InvalidStateException();
|
||||
}
|
||||
|
||||
$token = $token ?: $this->getAccessToken($this->getCode());
|
||||
|
||||
$user = $this->getUserByToken($token);
|
||||
|
||||
$user = $this->mapUserToObject($user)->merge(['original' => $user]);
|
||||
|
||||
return $user->setToken($token)->setProviderName($this->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $code
|
||||
*/
|
||||
public function userByCode($code, AccessTokenInterface $token = null){
|
||||
if (is_null($token) && $this->hasInvalidState()) {
|
||||
throw new InvalidStateException();
|
||||
}
|
||||
|
||||
$token = $token ?: $this->getAccessToken($code);
|
||||
|
||||
$user = $this->getUserByToken($token);
|
||||
|
||||
$user = $this->mapUserToObject($user)->merge(['original' => $user]);
|
||||
|
||||
return $user->setToken($token)->setProviderName($this->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set redirect url.
|
||||
*
|
||||
* @param string $redirectUrl
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRedirectUrl($redirectUrl)
|
||||
{
|
||||
$this->redirectUrl = $redirectUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set redirect url.
|
||||
*
|
||||
* @param string $redirectUrl
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function withRedirectUrl($redirectUrl)
|
||||
{
|
||||
$this->redirectUrl = $redirectUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the redirect url.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUrl()
|
||||
{
|
||||
return $this->redirectUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $accessToken
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAccessToken(AccessTokenInterface $accessToken)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessTokenInterface
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
if ($this->accessToken) {
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
$guzzleVersion = \defined(ClientInterface::class.'::VERSION') ? \constant(ClientInterface::class.'::VERSION') : 7;
|
||||
|
||||
$postKey = (1 === version_compare($guzzleVersion, '6')) ? 'form_params' : 'body';
|
||||
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'headers' => ['Accept' => 'application/json'],
|
||||
$postKey => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scopes of the requested access.
|
||||
*
|
||||
* @param array $scopes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function scopes(array $scopes)
|
||||
{
|
||||
$this->scopes = $scopes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request instance.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequest(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the request instance.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the provider should operate as stateless.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function stateless()
|
||||
{
|
||||
$this->stateless = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the custom parameters of the request.
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function with(array $parameters)
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ReflectionException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
if (empty($this->name)) {
|
||||
$this->name = strstr((new \ReflectionClass(get_class($this)))->getShortName(), 'Provider', true);
|
||||
}
|
||||
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildAuthUrlFromBase($url, $state)
|
||||
{
|
||||
return $url.'?'.http_build_query($this->getCodeFields($state), '', '&', $this->encodingType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the GET parameters for the code request.
|
||||
*
|
||||
* @param string|null $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getCodeFields($state = null)
|
||||
{
|
||||
$fields = array_merge([
|
||||
'client_id' => $this->config['client_id'],
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
'response_type' => 'code',
|
||||
], $this->parameters);
|
||||
|
||||
if ($this->usesState()) {
|
||||
$fields['state'] = $state;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the given scopes.
|
||||
*
|
||||
* @param array $scopes
|
||||
* @param string $scopeSeparator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function formatScopes(array $scopes, $scopeSeparator)
|
||||
{
|
||||
return implode($scopeSeparator, $scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current request / session has a mismatching "state".
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasInvalidState()
|
||||
{
|
||||
if ($this->isStateless()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$state = $this->request->getSession()->get('state');
|
||||
|
||||
return !(strlen($state) > 0 && $this->request->get('state') === $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the POST fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return [
|
||||
'client_id' => $this->getConfig()->get('client_id'),
|
||||
'client_secret' => $this->getConfig()->get('client_secret'),
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token from the token response body.
|
||||
*
|
||||
* @param \Psr\Http\Message\StreamInterface|array $body
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessTokenInterface
|
||||
*/
|
||||
protected function parseAccessToken($body)
|
||||
{
|
||||
if (!is_array($body)) {
|
||||
$body = json_decode($body, true);
|
||||
}
|
||||
|
||||
if (empty($body['access_token'])) {
|
||||
throw new AuthorizeFailedException('Authorize Failed: '.json_encode($body, JSON_UNESCAPED_UNICODE), $body);
|
||||
}
|
||||
|
||||
return new AccessToken($body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the code from the request.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getCode()
|
||||
{
|
||||
return $this->request->get('code');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a fresh instance of the Guzzle HTTP client.
|
||||
*
|
||||
* @return \GuzzleHttp\Client
|
||||
*/
|
||||
protected function getHttpClient()
|
||||
{
|
||||
return new Client(self::$guzzleOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set options for Guzzle HTTP client.
|
||||
*
|
||||
* @param array $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function setGuzzleOptions($config = [])
|
||||
{
|
||||
return self::$guzzleOptions = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the provider is operating with state.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function usesState()
|
||||
{
|
||||
return !$this->stateless;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the provider is operating as stateless.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isStateless()
|
||||
{
|
||||
return !$this->request->hasSession() || $this->stateless;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array item by key.
|
||||
*
|
||||
* @param array $array
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function arrayItem(array $array, $key, $default = null)
|
||||
{
|
||||
if (is_null($key)) {
|
||||
return $array;
|
||||
}
|
||||
|
||||
if (isset($array[$key])) {
|
||||
return $array[$key];
|
||||
}
|
||||
|
||||
foreach (explode('.', $key) as $segment) {
|
||||
if (!is_array($array) || !array_key_exists($segment, $array)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$array = $array[$segment];
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put state to session storage and return it.
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
protected function makeState()
|
||||
{
|
||||
if (!$this->request->hasSession()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$state = sha1(uniqid(mt_rand(1, 1000000), true));
|
||||
$session = $this->request->getSession();
|
||||
|
||||
if (is_callable([$session, 'put'])) {
|
||||
$session->put('state', $state);
|
||||
} elseif (is_callable([$session, 'set'])) {
|
||||
$session->set('state', $state);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
}
|
||||
134
vendor/overtrue/socialite/src/Providers/BaiduProvider.php
vendored
Executable file
134
vendor/overtrue/socialite/src/Providers/BaiduProvider.php
vendored
Executable file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class BaiduProvider.
|
||||
*
|
||||
* @see https://developer.baidu.com/wiki/index.php?title=docs/oauth [OAuth 2.0 授权机制说明]
|
||||
*/
|
||||
class BaiduProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base url of Weibo API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://openapi.baidu.com';
|
||||
|
||||
/**
|
||||
* The API version for the request.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version = '2.0';
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [''];
|
||||
|
||||
/**
|
||||
* The uid of user authorized.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $uid;
|
||||
|
||||
protected $display = 'popup';
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth/'.$this->version.'/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getCodeFields($state = null)
|
||||
{
|
||||
return array_merge([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->getConfig()->get('client_id'),
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
'display' => $this->display,
|
||||
], $this->parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token URL for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/oauth/'.$this->version.'/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Post fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw user for the given access token.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/rest/'.$this->version.'/passport/users/getInfo', [
|
||||
'query' => [
|
||||
'access_token' => $token->getToken(),
|
||||
],
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the raw user array to a Socialite User instance.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
$realname = $this->arrayItem($user, 'realname');
|
||||
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'userid'),
|
||||
'nickname' => empty($realname) ? '' : $realname,
|
||||
'name' => $this->arrayItem($user, 'username'),
|
||||
'email' => '',
|
||||
'avatar' => $this->arrayItem($user, 'portrait'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
169
vendor/overtrue/socialite/src/Providers/DouYinProvider.php
vendored
Executable file
169
vendor/overtrue/socialite/src/Providers/DouYinProvider.php
vendored
Executable file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessToken;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class DouYinProvider.
|
||||
*
|
||||
* @author haoliang@qiyuankeji.vip
|
||||
*
|
||||
* @see http://open.douyin.com/platform
|
||||
*/
|
||||
class DouYinProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* 抖音接口域名.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://open.douyin.com';
|
||||
|
||||
/**
|
||||
* 应用授权作用域.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['user_info'];
|
||||
|
||||
/**
|
||||
* 获取登录页面地址.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/platform/oauth/connect', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权码接口参数.
|
||||
*
|
||||
* @param string|null $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCodeFields($state = null)
|
||||
{
|
||||
$fields = [
|
||||
'client_key' => $this->getConfig()->get('client_id'),
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
'response_type' => 'code',
|
||||
];
|
||||
|
||||
if ($this->usesState()) {
|
||||
$fields['state'] = $state;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token地址.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/oauth/access_token';
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过code获取access_token.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->getTokenUrl(), [
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token接口参数.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return [
|
||||
'client_key' => $this->getConfig()->get('client_id'),
|
||||
'client_secret' => $this->getConfig()->get('client_secret'),
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化token.
|
||||
*
|
||||
* @param \Psr\Http\Message\StreamInterface|array $body
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessTokenInterface
|
||||
*/
|
||||
protected function parseAccessToken($body)
|
||||
{
|
||||
if (!is_array($body)) {
|
||||
$body = json_decode($body, true);
|
||||
}
|
||||
|
||||
if (empty($body['data']['access_token'])) {
|
||||
throw new AuthorizeFailedException('Authorize Failed: '.json_encode($body, JSON_UNESCAPED_UNICODE), $body);
|
||||
}
|
||||
|
||||
return new AccessToken($body['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过token 获取用户信息.
|
||||
*
|
||||
* @param AccessTokenInterface $token
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$userUrl = $this->baseUrl.'/oauth/userinfo/';
|
||||
|
||||
$response = $this->getHttpClient()->get(
|
||||
$userUrl,
|
||||
[
|
||||
'query' => [
|
||||
'access_token' => $token->getToken(),
|
||||
'open_id' => $token['open_id'],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化用户信息.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'open_id'),
|
||||
'username' => $this->arrayItem($user, 'nickname'),
|
||||
'nickname' => $this->arrayItem($user, 'nickname'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
88
vendor/overtrue/socialite/src/Providers/DoubanProvider.php
vendored
Executable file
88
vendor/overtrue/socialite/src/Providers/DoubanProvider.php
vendored
Executable file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class DoubanProvider.
|
||||
*
|
||||
* @see http://developers.douban.com/wiki/?title=oauth2 [使用 OAuth 2.0 访问豆瓣 API]
|
||||
*/
|
||||
class DoubanProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://www.douban.com/service/auth2/auth', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'https://www.douban.com/service/auth2/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get('https://api.douban.com/v2/user/~me', [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '.$token->getToken(),
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'nickname' => $this->arrayItem($user, 'name'),
|
||||
'name' => $this->arrayItem($user, 'name'),
|
||||
'avatar' => $this->arrayItem($user, 'large_avatar'),
|
||||
'email' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'form_params' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody()->getContents());
|
||||
}
|
||||
}
|
||||
168
vendor/overtrue/socialite/src/Providers/FacebookProvider.php
vendored
Executable file
168
vendor/overtrue/socialite/src/Providers/FacebookProvider.php
vendored
Executable file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class FacebookProvider.
|
||||
*
|
||||
* @see https://developers.facebook.com/docs/graph-api [Facebook - Graph API]
|
||||
*/
|
||||
class FacebookProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base Facebook Graph URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $graphUrl = 'https://graph.facebook.com';
|
||||
|
||||
/**
|
||||
* The Graph API version for the request.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version = 'v3.3';
|
||||
|
||||
/**
|
||||
* The user fields being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fields = ['first_name', 'last_name', 'email', 'gender', 'verified'];
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['email'];
|
||||
|
||||
/**
|
||||
* Display the dialog in a popup view.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $popup = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://www.facebook.com/'.$this->version.'/dialog/oauth', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->graphUrl.'/oauth/access_token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->getTokenUrl(), [
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$appSecretProof = hash_hmac('sha256', $token->getToken(), $this->getConfig()->get('client_secret'));
|
||||
|
||||
$response = $this->getHttpClient()->get($this->graphUrl.'/'.$this->version.'/me?access_token='.$token.'&appsecret_proof='.$appSecretProof.'&fields='.implode(',', $this->fields), [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
$userId = $this->arrayItem($user, 'id');
|
||||
$avatarUrl = $this->graphUrl.'/'.$this->version.'/'.$userId.'/picture';
|
||||
|
||||
$firstName = $this->arrayItem($user, 'first_name');
|
||||
$lastName = $this->arrayItem($user, 'last_name');
|
||||
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'nickname' => null,
|
||||
'name' => $firstName.' '.$lastName,
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
'avatar' => $userId ? $avatarUrl.'?type=normal' : null,
|
||||
'avatar_original' => $userId ? $avatarUrl.'?width=1920' : null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCodeFields($state = null)
|
||||
{
|
||||
$fields = parent::getCodeFields($state);
|
||||
|
||||
if ($this->popup) {
|
||||
$fields['display'] = 'popup';
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user fields to request from Facebook.
|
||||
*
|
||||
* @param array $fields
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function fields(array $fields)
|
||||
{
|
||||
$this->fields = $fields;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dialog to be displayed as a popup.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function asPopup()
|
||||
{
|
||||
$this->popup = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
192
vendor/overtrue/socialite/src/Providers/FeiShuProvider.php
vendored
Executable file
192
vendor/overtrue/socialite/src/Providers/FeiShuProvider.php
vendored
Executable file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessToken;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\AuthorizeFailedException;
|
||||
use Overtrue\Socialite\InvalidStateException;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class FeiShuProvider.
|
||||
*
|
||||
* @author qijian.song@show.world
|
||||
*
|
||||
* @see https://open.feishu.cn/
|
||||
*/
|
||||
class FeiShuProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* 飞书接口域名.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://open.feishu.cn';
|
||||
|
||||
/**
|
||||
* 应用授权作用域.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['user_info'];
|
||||
|
||||
/**
|
||||
* 获取登录页面地址.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/open-apis/authen/v1/index', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权码接口参数.
|
||||
*
|
||||
* @param string|null $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getCodeFields($state = null)
|
||||
{
|
||||
$fields = [
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'app_id' => $this->getConfig()->get('client_id'),
|
||||
];
|
||||
|
||||
if ($this->usesState()) {
|
||||
$fields['state'] = $state;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 app_access_token 地址.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/open-apis/auth/v3/app_access_token/internal';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 app_access_token.
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code = '')
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'headers' => ['Content-Type' => 'application/json'],
|
||||
'json' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 app_access_token 接口参数.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return [
|
||||
'app_id' => $this->getConfig()->get('client_id'),
|
||||
'app_secret' => $this->getConfig()->get('client_secret'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化 token.
|
||||
*
|
||||
* @param \Psr\Http\Message\StreamInterface|array $body
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessTokenInterface
|
||||
*/
|
||||
protected function parseAccessToken($body)
|
||||
{
|
||||
if (!is_array($body)) {
|
||||
$body = json_decode($body, true);
|
||||
}
|
||||
|
||||
if (empty($body['app_access_token'])) {
|
||||
throw new AuthorizeFailedException('Authorize Failed: '.json_encode($body, JSON_UNESCAPED_UNICODE), $body);
|
||||
}
|
||||
$data['access_token'] = $body['app_access_token'];
|
||||
|
||||
return new AccessToken($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息.
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function user(AccessTokenInterface $token = null)
|
||||
{
|
||||
if (is_null($token) && $this->hasInvalidState()) {
|
||||
throw new InvalidStateException();
|
||||
}
|
||||
|
||||
$token = $token ?: $this->getAccessToken();
|
||||
|
||||
$user = $this->getUserByToken($token, $this->getCode());
|
||||
$user = $this->mapUserToObject($user)->merge(['original' => $user]);
|
||||
|
||||
return $user->setToken($token)->setProviderName($this->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 token 获取用户信息.
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$userUrl = $this->baseUrl.'/open-apis/authen/v1/access_token';
|
||||
|
||||
$response = $this->getHttpClient()->post(
|
||||
$userUrl,
|
||||
[
|
||||
'json' => [
|
||||
'app_access_token' => $token->getToken(),
|
||||
'code' => $this->getCode(),
|
||||
'grant_type' => 'authorization_code',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$result = json_decode($response->getBody(), true);
|
||||
|
||||
return $result['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化用户信息.
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'open_id'),
|
||||
'username' => $this->arrayItem($user, 'name'),
|
||||
'nickname' => $this->arrayItem($user, 'name'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar_url'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
126
vendor/overtrue/socialite/src/Providers/GitHubProvider.php
vendored
Executable file
126
vendor/overtrue/socialite/src/Providers/GitHubProvider.php
vendored
Executable file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Exception;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class GitHubProvider.
|
||||
*/
|
||||
class GitHubProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['user:email'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://github.com/login/oauth/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'https://github.com/login/oauth/access_token';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$userUrl = 'https://api.github.com/user';
|
||||
|
||||
$response = $this->getHttpClient()->get(
|
||||
$userUrl,
|
||||
$this->createAuthorizationHeaders($token)
|
||||
);
|
||||
|
||||
$user = json_decode($response->getBody(), true);
|
||||
|
||||
if (in_array('user:email', $this->scopes)) {
|
||||
$user['email'] = $this->getEmailByToken($token);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the email for the given access token.
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getEmailByToken($token)
|
||||
{
|
||||
$emailsUrl = 'https://api.github.com/user/emails';
|
||||
|
||||
try {
|
||||
$response = $this->getHttpClient()->get(
|
||||
$emailsUrl,
|
||||
$this->createAuthorizationHeaders($token)
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (json_decode($response->getBody(), true) as $email) {
|
||||
if ($email['primary'] && $email['verified']) {
|
||||
return $email['email'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'username' => $this->arrayItem($user, 'login'),
|
||||
'nickname' => $this->arrayItem($user, 'login'),
|
||||
'name' => $this->arrayItem($user, 'name'),
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar_url'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default options for an HTTP request.
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function createAuthorizationHeaders(string $token)
|
||||
{
|
||||
return [
|
||||
'headers' => [
|
||||
'Accept' => 'application/vnd.github.v3+json',
|
||||
'Authorization' => sprintf('token %s', $token),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
119
vendor/overtrue/socialite/src/Providers/GoogleProvider.php
vendored
Executable file
119
vendor/overtrue/socialite/src/Providers/GoogleProvider.php
vendored
Executable file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class GoogleProvider.
|
||||
*
|
||||
* @see https://developers.google.com/identity/protocols/OpenIDConnect [OpenID Connect]
|
||||
*/
|
||||
class GoogleProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The separating character for the requested scopes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $scopeSeparator = ' ';
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://accounts.google.com/o/oauth2/v2/auth', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'https://www.googleapis.com/oauth2/v4/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$guzzleVersion = \defined(ClientInterface::class.'::VERSION') ? \constant(ClientInterface::class.'::VERSION') : 7;
|
||||
$postKey = (1 === version_compare($guzzleVersion, '6')) ? 'form_params' : 'body';
|
||||
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
$postKey => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the POST fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get('https://www.googleapis.com/userinfo/v2/me', [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$token->getToken(),
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'username' => $this->arrayItem($user, 'email'),
|
||||
'nickname' => $this->arrayItem($user, 'name'),
|
||||
'name' => $this->arrayItem($user, 'name'),
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
'avatar' => $this->arrayItem($user, 'picture'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
181
vendor/overtrue/socialite/src/Providers/LinkedinProvider.php
vendored
Executable file
181
vendor/overtrue/socialite/src/Providers/LinkedinProvider.php
vendored
Executable file
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class LinkedinProvider.
|
||||
*
|
||||
* @see https://developer.linkedin.com/docs/oauth2 [Authenticating with OAuth 2.0]
|
||||
*/
|
||||
class LinkedinProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['r_liteprofile', 'r_emailaddress'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://www.linkedin.com/oauth/v2/authorization', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()
|
||||
->post($this->getTokenUrl(), ['form_params' => $this->getTokenFields($code)]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'https://www.linkedin.com/oauth/v2/accessToken';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the POST fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$basicProfile = $this->getBasicProfile($token);
|
||||
$emailAddress = $this->getEmailAddress($token);
|
||||
|
||||
return array_merge($basicProfile, $emailAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the basic profile fields for the user.
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getBasicProfile($token)
|
||||
{
|
||||
$url = 'https://api.linkedin.com/v2/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))';
|
||||
|
||||
$response = $this->getHttpClient()->get($url, [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
'X-RestLi-Protocol-Version' => '2.0.0',
|
||||
],
|
||||
]);
|
||||
|
||||
return (array) json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the email address for the user.
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getEmailAddress($token)
|
||||
{
|
||||
$url = 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))';
|
||||
|
||||
$response = $this->getHttpClient()->get($url, [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
'X-RestLi-Protocol-Version' => '2.0.0',
|
||||
],
|
||||
]);
|
||||
|
||||
return (array) $this->arrayItem(json_decode($response->getBody(), true), 'elements.0.handle~');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
$preferredLocale = $this->arrayItem($user, 'firstName.preferredLocale.language').'_'.$this->arrayItem($user, 'firstName.preferredLocale.country');
|
||||
$firstName = $this->arrayItem($user, 'firstName.localized.'.$preferredLocale);
|
||||
$lastName = $this->arrayItem($user, 'lastName.localized.'.$preferredLocale);
|
||||
$name = $firstName.' '.$lastName;
|
||||
|
||||
$images = (array) $this->arrayItem($user, 'profilePicture.displayImage~.elements', []);
|
||||
$avatars = array_filter($images, function ($image) {
|
||||
return $image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] === 100;
|
||||
});
|
||||
$avatar = array_shift($avatars);
|
||||
$originalAvatars = array_filter($images, function ($image) {
|
||||
return $image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] === 800;
|
||||
});
|
||||
$originalAvatar = array_shift($originalAvatars);
|
||||
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'nickname' => $name,
|
||||
'name' => $name,
|
||||
'email' => $this->arrayItem($user, 'emailAddress'),
|
||||
'avatar' => $avatar ? $this->arrayItem($avatar, 'identifiers.0.identifier') : null,
|
||||
'avatar_original' => $originalAvatar ? $this->arrayItem($originalAvatar, 'identifiers.0.identifier') : null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user fields to request from LinkedIn.
|
||||
*
|
||||
* @param array $fields
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function fields(array $fields)
|
||||
{
|
||||
$this->fields = $fields;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the provider is operating as stateless.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isStateless()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
89
vendor/overtrue/socialite/src/Providers/OutlookProvider.php
vendored
Executable file
89
vendor/overtrue/socialite/src/Providers/OutlookProvider.php
vendored
Executable file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class OutlookProvider.
|
||||
*/
|
||||
class OutlookProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scopes = ['User.Read'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scopeSeparator = ' ';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://login.microsoftonline.com/common/oauth2/v2.0/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get(
|
||||
'https://graph.microsoft.com/v1.0/me',
|
||||
['headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$token->getToken(),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'nickname' => null,
|
||||
'name' => $this->arrayItem($user, 'displayName'),
|
||||
'email' => $this->arrayItem($user, 'userPrincipalName'),
|
||||
'avatar' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return array_merge(parent::getTokenFields($code), [
|
||||
'grant_type' => 'authorization_code',
|
||||
]);
|
||||
}
|
||||
}
|
||||
206
vendor/overtrue/socialite/src/Providers/QQProvider.php
vendored
Executable file
206
vendor/overtrue/socialite/src/Providers/QQProvider.php
vendored
Executable file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class QQProvider.
|
||||
*
|
||||
* @see http://wiki.connect.qq.com/oauth2-0%E7%AE%80%E4%BB%8B [QQ - OAuth 2.0 登录QQ]
|
||||
*/
|
||||
class QQProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base url of QQ API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://graph.qq.com';
|
||||
|
||||
/**
|
||||
* User openid.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $openId;
|
||||
|
||||
/**
|
||||
* get token(openid) with unionid.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $withUnionId = false;
|
||||
|
||||
/**
|
||||
* User unionid.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $unionId;
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['get_user_info'];
|
||||
|
||||
/**
|
||||
* The uid of user authorized.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $uid;
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth2.0/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token URL for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/oauth2.0/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Post fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->getTokenUrl(), [
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token from the token response body.
|
||||
*
|
||||
* @param string $body
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function parseAccessToken($body)
|
||||
{
|
||||
parse_str($body, $token);
|
||||
|
||||
return parent::parseAccessToken($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public function withUnionId()
|
||||
{
|
||||
$this->withUnionId = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw user for the given access token.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$url = $this->baseUrl.'/oauth2.0/me?access_token='.$token->getToken();
|
||||
$this->withUnionId && $url .= '&unionid=1';
|
||||
|
||||
$response = $this->getHttpClient()->get($url);
|
||||
|
||||
$me = json_decode($this->removeCallback($response->getBody()->getContents()), true);
|
||||
$this->openId = $me['openid'];
|
||||
$this->unionId = isset($me['unionid']) ? $me['unionid'] : '';
|
||||
|
||||
$queries = [
|
||||
'access_token' => $token->getToken(),
|
||||
'openid' => $this->openId,
|
||||
'oauth_consumer_key' => $this->getConfig()->get('client_id'),
|
||||
];
|
||||
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/user/get_user_info?'.http_build_query($queries));
|
||||
|
||||
return json_decode($this->removeCallback($response->getBody()->getContents()), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the raw user array to a Socialite User instance.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->openId,
|
||||
'unionid' => $this->unionId,
|
||||
'nickname' => $this->arrayItem($user, 'nickname'),
|
||||
'name' => $this->arrayItem($user, 'nickname'),
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
'avatar' => $this->arrayItem($user, 'figureurl_qq_2'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the fucking callback parentheses.
|
||||
*
|
||||
* @param string $response
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function removeCallback($response)
|
||||
{
|
||||
if (false !== strpos($response, 'callback')) {
|
||||
$lpos = strpos($response, '(');
|
||||
$rpos = strrpos($response, ')');
|
||||
$response = substr($response, $lpos + 1, $rpos - $lpos - 1);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
242
vendor/overtrue/socialite/src/Providers/TaobaoProvider.php
vendored
Executable file
242
vendor/overtrue/socialite/src/Providers/TaobaoProvider.php
vendored
Executable file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class TaobaoProvider.
|
||||
*
|
||||
* @author mechono <haodouliu@gmail.com>
|
||||
*
|
||||
* @see https://open.taobao.com/doc.htm?docId=102635&docType=1&source=search [Taobao - OAuth 2.0 授权登录]
|
||||
*/
|
||||
class TaobaoProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base url of Taobao API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://oauth.taobao.com';
|
||||
|
||||
/**
|
||||
* Taobao API service URL address.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $gatewayUrl = 'https://eco.taobao.com/router/rest';
|
||||
|
||||
/**
|
||||
* The API version for the request.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version = '2.0';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $format = 'json';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signMethod = 'md5';
|
||||
|
||||
/**
|
||||
* Web 对应 PC 端(淘宝 logo )浏览器页面样式;Tmall 对应天猫的浏览器页面样式;Wap 对应无线端的浏览器页面样式。
|
||||
*/
|
||||
protected $view = 'web';
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['user_info'];
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权码接口参数.
|
||||
*
|
||||
* @param string|null $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCodeFields($state = null)
|
||||
{
|
||||
$fields = [
|
||||
'client_id' => $this->getConfig()->get('client_id'),
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'view' => $this->view,
|
||||
'response_type' => 'code',
|
||||
];
|
||||
|
||||
if ($this->usesState()) {
|
||||
$fields['state'] = $state;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token URL for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Post fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code', 'view' => $this->view];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token from the token response body.
|
||||
*
|
||||
* @param string $body
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function parseAccessToken($body)
|
||||
{
|
||||
return parent::parseAccessToken($body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw user for the given access token.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getUserInfoUrl($this->gatewayUrl, $token));
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the raw user array to a Socialite User instance.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'open_id'),
|
||||
'nickname' => $this->arrayItem($user, 'nick'),
|
||||
'name' => $this->arrayItem($user, 'nick'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $params
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateSign($params)
|
||||
{
|
||||
ksort($params);
|
||||
|
||||
$stringToBeSigned = $this->getConfig()->get('client_secret');
|
||||
|
||||
foreach ($params as $k => $v) {
|
||||
if (!is_array($v) && '@' != substr($v, 0, 1)) {
|
||||
$stringToBeSigned .= "$k$v";
|
||||
}
|
||||
}
|
||||
|
||||
$stringToBeSigned .= $this->getConfig()->get('client_secret');
|
||||
|
||||
return strtoupper(md5($stringToBeSigned));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
* @param array $apiFields
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getPublicFields(AccessTokenInterface $token, array $apiFields = [])
|
||||
{
|
||||
$fields = [
|
||||
'app_key' => $this->getConfig()->get('client_id'),
|
||||
'sign_method' => $this->signMethod,
|
||||
'session' => $token->getToken(),
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'v' => $this->version,
|
||||
'format' => $this->format,
|
||||
];
|
||||
|
||||
$fields = array_merge($apiFields, $fields);
|
||||
$fields['sign'] = $this->generateSign($fields);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getUserInfoUrl($url, AccessTokenInterface $token)
|
||||
{
|
||||
$apiFields = ['method' => 'taobao.miniapp.userInfo.get'];
|
||||
|
||||
$query = http_build_query($this->getPublicFields($token, $apiFields), '', '&', $this->encodingType);
|
||||
|
||||
return $url.'?'.$query;
|
||||
}
|
||||
}
|
||||
234
vendor/overtrue/socialite/src/Providers/WeChatProvider.php
vendored
Executable file
234
vendor/overtrue/socialite/src/Providers/WeChatProvider.php
vendored
Executable file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\InvalidArgumentException;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
use Overtrue\Socialite\WeChatComponentInterface;
|
||||
|
||||
/**
|
||||
* Class WeChatProvider.
|
||||
*
|
||||
* @see http://mp.weixin.qq.com/wiki/9/01f711493b5a02f24b04365ac5d8fd95.html [WeChat - 公众平台OAuth文档]
|
||||
* @see https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN [网站应用微信登录开发指南]
|
||||
*/
|
||||
class WeChatProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base url of WeChat API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://api.weixin.qq.com/sns';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected $openId;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected $scopes = ['snsapi_login'];
|
||||
|
||||
/**
|
||||
* Indicates if the session state should be utilized.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $stateless = true;
|
||||
|
||||
/**
|
||||
* Return country code instead of country name.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $withCountryCode = false;
|
||||
|
||||
/**
|
||||
* @var WeChatComponentInterface
|
||||
*/
|
||||
protected $component;
|
||||
|
||||
/**
|
||||
* Return country code instead of country name.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function withCountryCode()
|
||||
{
|
||||
$this->withCountryCode = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* WeChat OpenPlatform 3rd component.
|
||||
*
|
||||
* @param WeChatComponentInterface $component
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function component(WeChatComponentInterface $component)
|
||||
{
|
||||
$this->scopes = ['snsapi_base'];
|
||||
|
||||
$this->component = $component;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->getTokenUrl(), [
|
||||
'headers' => ['Accept' => 'application/json'],
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
$path = 'oauth2/authorize';
|
||||
|
||||
if (in_array('snsapi_login', $this->scopes)) {
|
||||
$path = 'qrconnect';
|
||||
}
|
||||
|
||||
return $this->buildAuthUrlFromBase("https://open.weixin.qq.com/connect/{$path}", $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function buildAuthUrlFromBase($url, $state)
|
||||
{
|
||||
$query = http_build_query($this->getCodeFields($state), '', '&', $this->encodingType);
|
||||
|
||||
return $url.'?'.$query.'#wechat_redirect';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getCodeFields($state = null)
|
||||
{
|
||||
if ($this->component) {
|
||||
$this->with(array_merge($this->parameters, ['component_appid' => $this->component->getAppId()]));
|
||||
}
|
||||
|
||||
return array_merge([
|
||||
'appid' => $this->getConfig()->get('client_id'),
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'response_type' => 'code',
|
||||
'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
'state' => $state ?: md5(time()),
|
||||
'connect_redirect' => 1,
|
||||
], $this->parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
if ($this->component) {
|
||||
return $this->baseUrl.'/oauth2/component/access_token';
|
||||
}
|
||||
|
||||
return $this->baseUrl.'/oauth2/access_token';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$scopes = explode(',', $token->getAttribute('scope', ''));
|
||||
|
||||
if (in_array('snsapi_base', $scopes)) {
|
||||
return $token->toArray();
|
||||
}
|
||||
|
||||
if (empty($token['openid'])) {
|
||||
throw new InvalidArgumentException('openid of AccessToken is required.');
|
||||
}
|
||||
|
||||
$language = $this->withCountryCode ? null : (isset($this->parameters['lang']) ? $this->parameters['lang'] : 'zh_CN');
|
||||
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/userinfo', [
|
||||
'query' => array_filter([
|
||||
'access_token' => $token->getToken(),
|
||||
'openid' => $token['openid'],
|
||||
'lang' => $language,
|
||||
]),
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'openid'),
|
||||
'name' => $this->arrayItem($user, 'nickname'),
|
||||
'nickname' => $this->arrayItem($user, 'nickname'),
|
||||
'avatar' => $this->arrayItem($user, 'headimgurl'),
|
||||
'email' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return array_filter([
|
||||
'appid' => $this->getConfig()->get('client_id'),
|
||||
'secret' => $this->getConfig()->get('client_secret'),
|
||||
'component_appid' => $this->component ? $this->component->getAppId() : null,
|
||||
'component_access_token' => $this->component ? $this->component->getToken() : null,
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the fucking callback parentheses.
|
||||
*
|
||||
* @param mixed $response
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function removeCallback($response)
|
||||
{
|
||||
if (false !== strpos($response, 'callback')) {
|
||||
$lpos = strpos($response, '(');
|
||||
$rpos = strrpos($response, ')');
|
||||
$response = substr($response, $lpos + 1, $rpos - $lpos - 1);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
215
vendor/overtrue/socialite/src/Providers/WeWorkProvider.php
vendored
Executable file
215
vendor/overtrue/socialite/src/Providers/WeWorkProvider.php
vendored
Executable file
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class WeWorkProvider.
|
||||
*
|
||||
* @author mingyoung <mingyoungcheung@gmail.com>
|
||||
*/
|
||||
class WeWorkProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $agentId;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $detailed = false;
|
||||
|
||||
/**
|
||||
* Set agent id.
|
||||
*
|
||||
* @param string $agentId
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAgentId($agentId)
|
||||
{
|
||||
$this->agentId = $agentId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $agentId
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function agent($agentId)
|
||||
{
|
||||
return $this->setAgentId($agentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return user details.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function detailed()
|
||||
{
|
||||
$this->detailed = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
// 网页授权登录
|
||||
if (!empty($this->scopes)) {
|
||||
return $this->getOAuthUrl($state);
|
||||
}
|
||||
|
||||
// 第三方网页应用登录(扫码登录)
|
||||
return $this->getQrConnectUrl($state);
|
||||
}
|
||||
|
||||
/**
|
||||
* OAuth url.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getOAuthUrl($state)
|
||||
{
|
||||
$queries = [
|
||||
'appid' => $this->getConfig()->get('client_id'),
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'response_type' => 'code',
|
||||
'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
'agentid' => $this->agentId,
|
||||
'state' => $state,
|
||||
];
|
||||
|
||||
return sprintf('https://open.weixin.qq.com/connect/oauth2/authorize?%s#wechat_redirect', http_build_query($queries));
|
||||
}
|
||||
|
||||
/**
|
||||
* Qr connect url.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getQrConnectUrl($state)
|
||||
{
|
||||
$queries = [
|
||||
'appid' => $this->getConfig()->get('client_id'),
|
||||
'agentid' => $this->agentId,
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'state' => $state,
|
||||
];
|
||||
|
||||
return 'https://open.work.weixin.qq.com/wwopen/sso/qrConnect?'.http_build_query($queries);
|
||||
}
|
||||
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$userInfo = $this->getUserInfo($token);
|
||||
|
||||
if ($this->detailed && isset($userInfo['user_ticket'])) {
|
||||
return $this->getUserDetail($token, $userInfo['user_ticket']);
|
||||
}
|
||||
|
||||
$this->detailed = false;
|
||||
|
||||
return $userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user base info.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getUserInfo(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get('https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo', [
|
||||
'query' => array_filter([
|
||||
'access_token' => $token->getToken(),
|
||||
'code' => $this->getCode(),
|
||||
'debug' => 1
|
||||
]),
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user detail info.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
* @param $ticket
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getUserDetail(AccessTokenInterface $token, $ticket)
|
||||
{
|
||||
$response = $this->getHttpClient()->post('https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail', [
|
||||
'query' => [
|
||||
'access_token' => $token->getToken(),
|
||||
],
|
||||
'json' => [
|
||||
'user_ticket' => $ticket,
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
if ($this->detailed) {
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'userid'),
|
||||
'name' => $this->arrayItem($user, 'name'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar'),
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
]);
|
||||
}
|
||||
|
||||
return new User(array_filter([
|
||||
'id' => $this->arrayItem($user, 'UserId') ?: $this->arrayItem($user, 'OpenId'),
|
||||
'userId' => $this->arrayItem($user, 'UserId'),
|
||||
'openid' => $this->arrayItem($user, 'OpenId'),
|
||||
'deviceId' => $this->arrayItem($user, 'DeviceId'),
|
||||
]));
|
||||
}
|
||||
}
|
||||
126
vendor/overtrue/socialite/src/Providers/WeiboProvider.php
vendored
Executable file
126
vendor/overtrue/socialite/src/Providers/WeiboProvider.php
vendored
Executable file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class WeiboProvider.
|
||||
*
|
||||
* @see http://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E [OAuth 2.0 授权机制说明]
|
||||
*/
|
||||
class WeiboProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base url of Weibo API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://api.weibo.com';
|
||||
|
||||
/**
|
||||
* The API version for the request.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version = '2';
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['email'];
|
||||
|
||||
/**
|
||||
* The uid of user authorized.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $uid;
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth2/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token URL for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/'.$this->version.'/oauth2/access_token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Post fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw user for the given access token.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/'.$this->version.'/users/show.json', [
|
||||
'query' => [
|
||||
'uid' => $token['uid'],
|
||||
'access_token' => $token->getToken(),
|
||||
],
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the raw user array to a Socialite User instance.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'nickname' => $this->arrayItem($user, 'screen_name'),
|
||||
'name' => $this->arrayItem($user, 'name'),
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar_large'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
251
vendor/overtrue/socialite/src/SocialiteManager.php
vendored
Executable file
251
vendor/overtrue/socialite/src/SocialiteManager.php
vendored
Executable file
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
use Closure;
|
||||
use InvalidArgumentException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
|
||||
/**
|
||||
* Class SocialiteManager.
|
||||
*/
|
||||
class SocialiteManager implements FactoryInterface
|
||||
{
|
||||
/**
|
||||
* The configuration.
|
||||
*
|
||||
* @var \Overtrue\Socialite\Config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The request instance.
|
||||
*
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* The registered custom driver creators.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $customCreators = [];
|
||||
|
||||
/**
|
||||
* The initial drivers.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $initialDrivers = [
|
||||
'facebook' => 'Facebook',
|
||||
'github' => 'GitHub',
|
||||
'google' => 'Google',
|
||||
'linkedin' => 'Linkedin',
|
||||
'weibo' => 'Weibo',
|
||||
'qq' => 'QQ',
|
||||
'wechat' => 'WeChat',
|
||||
'douban' => 'Douban',
|
||||
'wework' => 'WeWork',
|
||||
'outlook' => 'Outlook',
|
||||
'douyin' => 'DouYin',
|
||||
'taobao' => 'Taobao',
|
||||
'feishu' => 'FeiShu',
|
||||
];
|
||||
|
||||
/**
|
||||
* The array of created "drivers".
|
||||
*
|
||||
* @var ProviderInterface[]
|
||||
*/
|
||||
protected $drivers = [];
|
||||
|
||||
/**
|
||||
* SocialiteManager constructor.
|
||||
*
|
||||
* @param array $config
|
||||
* @param Request|null $request
|
||||
*/
|
||||
public function __construct(array $config, Request $request = null)
|
||||
{
|
||||
$this->config = new Config($config);
|
||||
|
||||
if ($this->config->has('guzzle')) {
|
||||
Providers\AbstractProvider::setGuzzleOptions($this->config->get('guzzle'));
|
||||
}
|
||||
|
||||
if ($request) {
|
||||
$this->setRequest($request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set config instance.
|
||||
*
|
||||
* @param \Overtrue\Socialite\Config $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function config(Config $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a driver instance.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
public function driver($driver)
|
||||
{
|
||||
$driver = strtolower($driver);
|
||||
|
||||
if (!isset($this->drivers[$driver])) {
|
||||
$this->drivers[$driver] = $this->createDriver($driver);
|
||||
}
|
||||
|
||||
return $this->drivers[$driver];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequest(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request ?: $this->createDefaultRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new driver instance.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
protected function createDriver($driver)
|
||||
{
|
||||
if (isset($this->customCreators[$driver])) {
|
||||
return $this->callCustomCreator($driver);
|
||||
}
|
||||
|
||||
if (isset($this->initialDrivers[$driver])) {
|
||||
$provider = $this->initialDrivers[$driver];
|
||||
$provider = __NAMESPACE__.'\\Providers\\'.$provider.'Provider';
|
||||
|
||||
return $this->buildProvider($provider, $this->formatConfig($this->config->get($driver)));
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("Driver [$driver] not supported.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a custom driver creator.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
protected function callCustomCreator($driver)
|
||||
{
|
||||
return $this->customCreators[$driver]($this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create default request instance.
|
||||
*
|
||||
* @return Request
|
||||
*/
|
||||
protected function createDefaultRequest()
|
||||
{
|
||||
$request = Request::createFromGlobals();
|
||||
$session = new Session();
|
||||
|
||||
$request->setSession($session);
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom driver creator Closure.
|
||||
*
|
||||
* @param string $driver
|
||||
* @param \Closure $callback
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function extend($driver, Closure $callback)
|
||||
{
|
||||
$driver = strtolower($driver);
|
||||
|
||||
$this->customCreators[$driver] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the created "drivers".
|
||||
*
|
||||
* @return ProviderInterface[]
|
||||
*/
|
||||
public function getDrivers()
|
||||
{
|
||||
return $this->drivers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an OAuth 2 provider instance.
|
||||
*
|
||||
* @param string $provider
|
||||
* @param array $config
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
public function buildProvider($provider, $config)
|
||||
{
|
||||
return new $provider($this->getRequest(), $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the server configuration.
|
||||
*
|
||||
* @param array $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function formatConfig(array $config)
|
||||
{
|
||||
return array_merge([
|
||||
'identifier' => $config['client_id'],
|
||||
'secret' => $config['client_secret'],
|
||||
'callback_uri' => $config['redirect'],
|
||||
], $config);
|
||||
}
|
||||
}
|
||||
204
vendor/overtrue/socialite/src/User.php
vendored
Executable file
204
vendor/overtrue/socialite/src/User.php
vendored
Executable file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
use ArrayAccess;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* Class User.
|
||||
*/
|
||||
class User implements ArrayAccess, UserInterface, JsonSerializable, \Serializable
|
||||
{
|
||||
use HasAttributes;
|
||||
|
||||
/**
|
||||
* User constructor.
|
||||
*
|
||||
* @param array $attributes
|
||||
*/
|
||||
public function __construct(array $attributes)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unique identifier for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->getAttribute('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the username for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->getAttribute('username', $this->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the nickname / username for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNickname()
|
||||
{
|
||||
return $this->getAttribute('nickname');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full name of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->getAttribute('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the e-mail address of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmail()
|
||||
{
|
||||
return $this->getAttribute('email');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the avatar / image URL for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAvatar()
|
||||
{
|
||||
return $this->getAttribute('avatar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the token on the user.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setToken(AccessTokenInterface $token)
|
||||
{
|
||||
$this->setAttribute('token', $token->getToken());
|
||||
$this->setAttribute('access_token', $token->getToken());
|
||||
|
||||
if (\is_callable([$token, 'getRefreshToken'])) {
|
||||
$this->setAttribute('refresh_token', $token->getRefreshToken());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $provider
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProviderName($provider)
|
||||
{
|
||||
$this->setAttribute('provider', $provider);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getProviderName()
|
||||
{
|
||||
return $this->getAttribute('provider');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authorized token.
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return new AccessToken([
|
||||
'access_token' => $this->getAccessToken(),
|
||||
'refresh_token' => $this->getAttribute('refresh_token')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user access token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
return $this->getAttribute('token') ?: $this->getAttribute('access_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user refresh token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRefreshToken()
|
||||
{
|
||||
return $this->getAttribute('refresh_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original attributes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOriginal()
|
||||
{
|
||||
return $this->getAttribute('original');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
return serialize($this->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the object.
|
||||
*
|
||||
* @see https://php.net/manual/en/serializable.unserialize.php
|
||||
*
|
||||
* @param string $serialized <p>
|
||||
* The string representation of the object.
|
||||
* </p>
|
||||
*
|
||||
* @since 5.1.0
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
$this->attributes = unserialize($serialized) ?: [];
|
||||
}
|
||||
}
|
||||
53
vendor/overtrue/socialite/src/UserInterface.php
vendored
Executable file
53
vendor/overtrue/socialite/src/UserInterface.php
vendored
Executable file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
/**
|
||||
* Interface UserInterface.
|
||||
*/
|
||||
interface UserInterface
|
||||
{
|
||||
/**
|
||||
* Get the unique identifier for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId();
|
||||
|
||||
/**
|
||||
* Get the nickname / username for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNickname();
|
||||
|
||||
/**
|
||||
* Get the full name of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Get the e-mail address of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmail();
|
||||
|
||||
/**
|
||||
* Get the avatar / image URL for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAvatar();
|
||||
}
|
||||
32
vendor/overtrue/socialite/src/WeChatComponentInterface.php
vendored
Executable file
32
vendor/overtrue/socialite/src/WeChatComponentInterface.php
vendored
Executable file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
/**
|
||||
* Interface WeChatComponentInterface.
|
||||
*/
|
||||
interface WeChatComponentInterface
|
||||
{
|
||||
/**
|
||||
* Return the open-platform component app id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAppId();
|
||||
|
||||
/**
|
||||
* Return the open-platform component access token string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getToken();
|
||||
}
|
||||
243
vendor/overtrue/socialite/tests/OAuthTest.php
vendored
Executable file
243
vendor/overtrue/socialite/tests/OAuthTest.php
vendored
Executable file
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
use Mockery as m;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\Providers\AbstractProvider;
|
||||
use Overtrue\Socialite\User;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class OAuthTest extends TestCase
|
||||
{
|
||||
public function tearDown()
|
||||
{
|
||||
m::close();
|
||||
}
|
||||
|
||||
public function testAbstractProviderBackwardCompatible()
|
||||
{
|
||||
$request = Request::create('foo');
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
$session->shouldReceive('put')->once();
|
||||
$provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect');
|
||||
|
||||
$this->assertSame('client_id', $provider->getConfig()['client_id']);
|
||||
$this->assertSame('client_secret', $provider->getConfig()['client_secret']);
|
||||
$this->assertSame('redirect', $provider->getConfig()['redirect']);
|
||||
|
||||
$response = $provider->redirect();
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response);
|
||||
$this->assertSame('http://auth.url', $response->getTargetUrl());
|
||||
}
|
||||
|
||||
public function testRedirectGeneratesTheProperSymfonyRedirectResponse()
|
||||
{
|
||||
$request = Request::create('foo');
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
$session->shouldReceive('put')->once();
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect',
|
||||
]
|
||||
);
|
||||
$response = $provider->redirect();
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response);
|
||||
$this->assertSame('http://auth.url', $response->getTargetUrl());
|
||||
}
|
||||
|
||||
public function testRedirectUrl()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => str_repeat('A', 40), 'code' => 'code']);
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
]
|
||||
);
|
||||
$this->assertNull($provider->getRedirectUrl());
|
||||
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect_uri',
|
||||
]
|
||||
);
|
||||
$this->assertSame('redirect_uri', $provider->getRedirectUrl());
|
||||
$provider->setRedirectUrl('overtrue.me');
|
||||
$this->assertSame('overtrue.me', $provider->getRedirectUrl());
|
||||
|
||||
$provider->withRedirectUrl('http://overtrue.me');
|
||||
$this->assertSame('http://overtrue.me', $provider->getRedirectUrl());
|
||||
}
|
||||
|
||||
public function testUserReturnsAUserInstanceForTheAuthenticatedRequest()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => str_repeat('A', 40), 'code' => 'code']);
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
|
||||
$session->shouldReceive('get')->once()->with('state')->andReturn(str_repeat('A', 40));
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect_uri',
|
||||
]
|
||||
);
|
||||
$provider->http = m::mock('StdClass');
|
||||
$provider->http->shouldReceive('post')->once()->with(
|
||||
'http://token.url',
|
||||
[
|
||||
'headers' => ['Accept' => 'application/json'],
|
||||
'form_params' => [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'code' => 'code',
|
||||
'redirect_uri' => 'redirect_uri',
|
||||
],
|
||||
]
|
||||
)->andReturn($response = m::mock('StdClass'));
|
||||
$response->shouldReceive('getBody')->once()->andReturn('{"access_token":"access_token"}');
|
||||
$user = $provider->user();
|
||||
|
||||
$this->assertInstanceOf('Overtrue\Socialite\User', $user);
|
||||
$this->assertSame('foo', $user->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Overtrue\Socialite\InvalidStateException
|
||||
*/
|
||||
public function testExceptionIsThrownIfStateIsInvalid()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => str_repeat('B', 40), 'code' => 'code']);
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
$session->shouldReceive('get')->once()->with('state')->andReturn(str_repeat('A', 40));
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect',
|
||||
]
|
||||
);
|
||||
$user = $provider->user();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Overtrue\Socialite\AuthorizeFailedException
|
||||
* @expectedExceptionMessage Authorize Failed: {"error":"scope is invalid"}
|
||||
*/
|
||||
public function testExceptionisThrownIfAuthorizeFailed()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => str_repeat('A', 40), 'code' => 'code']);
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
$session->shouldReceive('get')->once()->with('state')->andReturn(str_repeat('A', 40));
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect_uri',
|
||||
]
|
||||
);
|
||||
$provider->http = m::mock('StdClass');
|
||||
$provider->http->shouldReceive('post')->once()->with(
|
||||
'http://token.url',
|
||||
[
|
||||
'headers' => ['Accept' => 'application/json'],
|
||||
'form_params' => [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'code' => 'code',
|
||||
'redirect_uri' => 'redirect_uri',
|
||||
],
|
||||
]
|
||||
)->andReturn($response = m::mock('StdClass'));
|
||||
$response->shouldReceive('getBody')->once()->andReturn('{"error":"scope is invalid"}');
|
||||
$user = $provider->user();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Overtrue\Socialite\InvalidStateException
|
||||
*/
|
||||
public function testExceptionIsThrownIfStateIsNotSet()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => 'state', 'code' => 'code']);
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
$session->shouldReceive('get')->once()->with('state');
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect',
|
||||
]
|
||||
);
|
||||
$user = $provider->user();
|
||||
}
|
||||
|
||||
public function testDriverName()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => 'state', 'code' => 'code']);
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect',
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertSame('OAuthTwoTest', $provider->getName());
|
||||
}
|
||||
}
|
||||
|
||||
class OAuthTwoTestProviderStub extends AbstractProvider
|
||||
{
|
||||
public $http;
|
||||
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return 'http://auth.url';
|
||||
}
|
||||
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'http://token.url';
|
||||
}
|
||||
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
return ['id' => 'foo'];
|
||||
}
|
||||
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User(['id' => $user['id']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a fresh instance of the Guzzle HTTP client.
|
||||
*
|
||||
* @return \GuzzleHttp\Client
|
||||
*/
|
||||
protected function getHttpClient()
|
||||
{
|
||||
if ($this->http) {
|
||||
return $this->http;
|
||||
}
|
||||
|
||||
return $this->http = m::mock('StdClass');
|
||||
}
|
||||
}
|
||||
60
vendor/overtrue/socialite/tests/Providers/WeWorkProviderTest.php
vendored
Executable file
60
vendor/overtrue/socialite/tests/Providers/WeWorkProviderTest.php
vendored
Executable file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
use Overtrue\Socialite\Providers\WeWorkProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class WeWorkProviderTest extends TestCase
|
||||
{
|
||||
public function testQrConnect()
|
||||
{
|
||||
$response = (new WeWorkProvider(Request::create('foo'), [
|
||||
'client_id' => 'ww100000a5f2191',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'http://www.oa.com',
|
||||
]))
|
||||
->setAgentId('1000000')
|
||||
->stateless()
|
||||
->redirect();
|
||||
|
||||
$this->assertSame('https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=ww100000a5f2191&agentid=1000000&redirect_uri=http%3A%2F%2Fwww.oa.com', $response->getTargetUrl());
|
||||
}
|
||||
|
||||
public function testOAuthWithAgentId()
|
||||
{
|
||||
$response = (new WeWorkProvider(Request::create('foo'), [
|
||||
'client_id' => 'CORPID',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'REDIRECT_URI',
|
||||
]))
|
||||
->scopes(['snsapi_base'])
|
||||
->setAgentId('1000000')
|
||||
->stateless()
|
||||
->redirect();
|
||||
|
||||
$this->assertSame('https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&agentid=1000000#wechat_redirect', $response->getTargetUrl());
|
||||
}
|
||||
|
||||
public function testOAuthWithoutAgentId()
|
||||
{
|
||||
$response = (new WeWorkProvider(Request::create('foo'), [
|
||||
'client_id' => 'CORPID',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'REDIRECT_URI',
|
||||
]))
|
||||
->scopes(['snsapi_base'])
|
||||
->stateless()
|
||||
->redirect();
|
||||
|
||||
$this->assertSame('https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base#wechat_redirect', $response->getTargetUrl());
|
||||
}
|
||||
}
|
||||
45
vendor/overtrue/socialite/tests/UserTest.php
vendored
Executable file
45
vendor/overtrue/socialite/tests/UserTest.php
vendored
Executable file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
use Overtrue\Socialite\AccessToken;
|
||||
use Overtrue\Socialite\User;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class UserTest extends TestCase
|
||||
{
|
||||
public function testJsonserialize()
|
||||
{
|
||||
$this->assertSame('[]', json_encode(new User([])));
|
||||
|
||||
$this->assertSame('{"token":"mock-token"}', json_encode(new User(['token' => new AccessToken(['access_token' => 'mock-token'])])));
|
||||
}
|
||||
|
||||
public function test_it_can_get_refresh_token()
|
||||
{
|
||||
$user = new User([
|
||||
'access_token' => 'mock-token',
|
||||
'refresh_token' => 'fake_refresh',
|
||||
]);
|
||||
|
||||
// 能通过用 User 对象获取 refresh token
|
||||
$this->assertSame('fake_refresh', $user->getRefreshToken());
|
||||
// json 序列化只有 token 字段
|
||||
$this->assertSame('{"access_token":"mock-token","refresh_token":"fake_refresh"}', json_encode($user));
|
||||
|
||||
$user = new User([]);
|
||||
$user->setToken(new AccessToken([
|
||||
'access_token' => 'mock-token',
|
||||
'refresh_token' => 'fake_refresh',
|
||||
]));
|
||||
$this->assertSame('fake_refresh', $user->getRefreshToken());
|
||||
$this->assertSame('{"token":"mock-token","access_token":"mock-token","refresh_token":"fake_refresh"}', json_encode($user));
|
||||
}
|
||||
}
|
||||
137
vendor/overtrue/socialite/tests/WechatProviderTest.php
vendored
Executable file
137
vendor/overtrue/socialite/tests/WechatProviderTest.php
vendored
Executable file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
use Overtrue\Socialite\Providers\WeChatProvider as RealWeChatProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class WechatProviderTest extends TestCase
|
||||
{
|
||||
public function testWeChatProviderHasCorrectlyRedirectResponse()
|
||||
{
|
||||
$response = (new WeChatProvider(Request::create('foo'), [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'http://localhost/socialite/callback.php',
|
||||
]))->redirect();
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response);
|
||||
$this->assertStringStartsWith('https://open.weixin.qq.com/connect/qrconnect', $response->getTargetUrl());
|
||||
$this->assertRegExp('/redirect_uri=http%3A%2F%2Flocalhost%2Fsocialite%2Fcallback.php/', $response->getTargetUrl());
|
||||
}
|
||||
|
||||
public function testWeChatProviderTokenUrlAndRequestFields()
|
||||
{
|
||||
$provider = new WeChatProvider(Request::create('foo'), [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'http://localhost/socialite/callback.php',
|
||||
]);
|
||||
|
||||
$this->assertSame('https://api.weixin.qq.com/sns/oauth2/access_token', $provider->tokenUrl());
|
||||
$this->assertSame([
|
||||
'appid' => 'client_id',
|
||||
'secret' => 'client_secret',
|
||||
'code' => 'iloveyou',
|
||||
'grant_type' => 'authorization_code',
|
||||
], $provider->tokenFields('iloveyou'));
|
||||
|
||||
$this->assertSame([
|
||||
'appid' => 'client_id',
|
||||
'redirect_uri' => 'http://localhost/socialite/callback.php',
|
||||
'response_type' => 'code',
|
||||
'scope' => 'snsapi_login',
|
||||
'state' => 'wechat-state',
|
||||
'connect_redirect' => 1,
|
||||
], $provider->codeFields('wechat-state'));
|
||||
}
|
||||
|
||||
public function testOpenPlatformComponent()
|
||||
{
|
||||
$provider = new WeChatProvider(Request::create('foo'), [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => null,
|
||||
'redirect' => 'redirect-url',
|
||||
]);
|
||||
$provider->component(new WeChatComponent());
|
||||
$this->assertSame([
|
||||
'appid' => 'client_id',
|
||||
'redirect_uri' => 'redirect-url',
|
||||
'response_type' => 'code',
|
||||
'scope' => 'snsapi_base',
|
||||
'state' => 'state',
|
||||
'connect_redirect' => 1,
|
||||
'component_appid' => 'component-app-id',
|
||||
], $provider->codeFields('state'));
|
||||
|
||||
$this->assertSame([
|
||||
'appid' => 'client_id',
|
||||
'component_appid' => 'component-app-id',
|
||||
'component_access_token' => 'token',
|
||||
'code' => 'simcode',
|
||||
'grant_type' => 'authorization_code',
|
||||
], $provider->tokenFields('simcode'));
|
||||
|
||||
$this->assertSame('https://api.weixin.qq.com/sns/oauth2/component/access_token', $provider->tokenUrl());
|
||||
}
|
||||
|
||||
public function testOpenPlatformComponentWithCustomParameters()
|
||||
{
|
||||
$provider = new WeChatProvider(Request::create('foo'), [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => null,
|
||||
'redirect' => 'redirect-url',
|
||||
]);
|
||||
$provider->component(new WeChatComponent());
|
||||
$provider->with(['foo' => 'bar']);
|
||||
|
||||
$fields = $provider->codeFields('wechat-state');
|
||||
|
||||
$this->assertArrayHasKey('foo', $fields);
|
||||
$this->assertSame('bar', $fields['foo']);
|
||||
}
|
||||
}
|
||||
|
||||
trait ProviderTrait
|
||||
{
|
||||
public function tokenUrl()
|
||||
{
|
||||
return $this->getTokenUrl();
|
||||
}
|
||||
|
||||
public function tokenFields($code)
|
||||
{
|
||||
return $this->getTokenFields($code);
|
||||
}
|
||||
|
||||
public function codeFields($state = null)
|
||||
{
|
||||
return $this->getCodeFields($state);
|
||||
}
|
||||
}
|
||||
|
||||
class WeChatProvider extends RealWeChatProvider
|
||||
{
|
||||
use ProviderTrait;
|
||||
}
|
||||
|
||||
class WeChatComponent implements \Overtrue\Socialite\WeChatComponentInterface
|
||||
{
|
||||
public function getAppId()
|
||||
{
|
||||
return 'component-app-id';
|
||||
}
|
||||
|
||||
public function getToken()
|
||||
{
|
||||
return 'token';
|
||||
}
|
||||
}
|
||||
1401
vendor/overtrue/wechat/CHANGELOG.md
vendored
Executable file
1401
vendor/overtrue/wechat/CHANGELOG.md
vendored
Executable file
File diff suppressed because it is too large
Load Diff
67
vendor/overtrue/wechat/CONTRIBUTING.md
vendored
Executable file
67
vendor/overtrue/wechat/CONTRIBUTING.md
vendored
Executable file
@@ -0,0 +1,67 @@
|
||||
# Contribute
|
||||
|
||||
## Introduction
|
||||
|
||||
First, thank you for considering contributing to wechat! It's people like you that make the open source community such a great community! 😊
|
||||
|
||||
We welcome any type of contribution, not only code. You can help with
|
||||
- **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
|
||||
- **Marketing**: writing blog posts, howto's, printing stickers, ...
|
||||
- **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
|
||||
- **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
|
||||
- **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/wechat).
|
||||
|
||||
## Your First Contribution
|
||||
|
||||
Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
|
||||
|
||||
## Submitting code
|
||||
|
||||
Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests.
|
||||
|
||||
## Code review process
|
||||
|
||||
The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge.
|
||||
It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you?
|
||||
|
||||
## Financial contributions
|
||||
|
||||
We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/wechat).
|
||||
Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.
|
||||
|
||||
## Questions
|
||||
|
||||
If you have any questions, create an [issue](issue) (protip: do a quick search first to see if someone else didn't ask the same question before!).
|
||||
You can also reach us at hello@wechat.opencollective.com.
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
|
||||
Thank you to all the people who have already contributed to wechat!
|
||||
<a href="graphs/contributors"><img src="https://opencollective.com/wechat/contributors.svg?width=890" /></a>
|
||||
|
||||
|
||||
### Backers
|
||||
|
||||
Thank you to all our backers! [[Become a backer](https://opencollective.com/wechat#backer)]
|
||||
|
||||
<a href="https://opencollective.com/wechat#backers" target="_blank"><img src="https://opencollective.com/wechat/backers.svg?width=890"></a>
|
||||
|
||||
|
||||
### Sponsors
|
||||
|
||||
Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/wechat#sponsor))
|
||||
|
||||
<a href="https://opencollective.com/wechat/sponsor/0/website" target="_blank"><img src="https://opencollective.com/wechat/sponsor/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/wechat/sponsor/1/website" target="_blank"><img src="https://opencollective.com/wechat/sponsor/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/wechat/sponsor/2/website" target="_blank"><img src="https://opencollective.com/wechat/sponsor/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/wechat/sponsor/3/website" target="_blank"><img src="https://opencollective.com/wechat/sponsor/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/wechat/sponsor/4/website" target="_blank"><img src="https://opencollective.com/wechat/sponsor/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/wechat/sponsor/5/website" target="_blank"><img src="https://opencollective.com/wechat/sponsor/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/wechat/sponsor/6/website" target="_blank"><img src="https://opencollective.com/wechat/sponsor/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/wechat/sponsor/7/website" target="_blank"><img src="https://opencollective.com/wechat/sponsor/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/wechat/sponsor/8/website" target="_blank"><img src="https://opencollective.com/wechat/sponsor/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/wechat/sponsor/9/website" target="_blank"><img src="https://opencollective.com/wechat/sponsor/9/avatar.svg"></a>
|
||||
|
||||
<!-- This `CONTRIBUTING.md` is based on @nayafia's template https://github.com/nayafia/contributing-template -->
|
||||
22
vendor/overtrue/wechat/LICENSE
vendored
Executable file
22
vendor/overtrue/wechat/LICENSE
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) overtrue <i@overtrue.me>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
92
vendor/overtrue/wechat/README.md
vendored
Executable file
92
vendor/overtrue/wechat/README.md
vendored
Executable file
@@ -0,0 +1,92 @@
|
||||
<img align="right" width="100" src="https://user-images.githubusercontent.com/1472352/49656357-1e874080-fa78-11e8-80ea-69e2103345cf.png" alt="EasyWeChat Logo"/>
|
||||
|
||||
<h1 align="left"><a href="https://www.easywechat.com">EasyWeChat</a></h1>
|
||||
|
||||
📦 It is probably the best SDK in the world for developing Wechat App.
|
||||
|
||||
[](https://github.com/overtrue/wechat/actions)
|
||||
[](https://github.com/overtrue/wechat/actions)
|
||||
[](https://packagist.org/packages/overtrue/wechat)
|
||||
[](https://packagist.org/packages/overtrue/wechat)
|
||||
[](https://scrutinizer-ci.com/g/overtrue/wechat/?branch=master)
|
||||
[](https://scrutinizer-ci.com/g/overtrue/wechat/?branch=master)
|
||||
[](https://packagist.org/packages/overtrue/wechat)
|
||||
[](https://packagist.org/packages/overtrue/wechat)
|
||||
|
||||
|
||||
## Requirement
|
||||
|
||||
1. PHP >= 7.2
|
||||
2. **[Composer](https://getcomposer.org/)**
|
||||
3. openssl 拓展
|
||||
4. fileinfo 拓展(素材管理模块需要用到)
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
$ composer require "overtrue/wechat:^4.2" -vvv
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
基本使用(以服务端为例):
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use EasyWeChat\Factory;
|
||||
|
||||
$options = [
|
||||
'app_id' => 'wx3cf0f39249eb0exxx',
|
||||
'secret' => 'f1c242f4f28f735d4687abb469072xxx',
|
||||
'token' => 'easywechat',
|
||||
'log' => [
|
||||
'level' => 'debug',
|
||||
'file' => '/tmp/easywechat.log',
|
||||
],
|
||||
// ...
|
||||
];
|
||||
|
||||
$app = Factory::officialAccount($options);
|
||||
|
||||
$server = $app->server;
|
||||
$user = $app->user;
|
||||
|
||||
$server->push(function($message) use ($user) {
|
||||
$fromUser = $user->get($message['FromUserName']);
|
||||
|
||||
return "{$fromUser->nickname} 您好!欢迎关注 overtrue!";
|
||||
});
|
||||
|
||||
$server->serve()->send();
|
||||
```
|
||||
|
||||
更多请参考 [https://www.easywechat.com/](https://www.easywechat.com/)。
|
||||
|
||||
## Documentation
|
||||
|
||||
[官网](https://www.easywechat.com) · [教程](https://www.easywechat.com/tutorials) · [讨论](https://yike.io/) · [微信公众平台](https://mp.weixin.qq.com/wiki) · [WeChat Official](http://admin.wechat.com/wiki)
|
||||
|
||||
## Integration
|
||||
|
||||
[Laravel 5 拓展包: overtrue/laravel-wechat](https://github.com/overtrue/laravel-wechat)
|
||||
|
||||
## Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||
<a href="https://github.com/overtrue/wechat/graphs/contributors"><img src="https://opencollective.com/wechat/contributors.svg?width=890" /></a>
|
||||
|
||||
|
||||
## PHP 扩展包开发
|
||||
|
||||
> 想知道如何从零开始构建 PHP 扩展包?
|
||||
>
|
||||
> 请关注我的实战课程,我会在此课程中分享一些扩展开发经验 —— [《PHP 扩展包实战教程 - 从入门到发布》](https://learnku.com/courses/creating-package)
|
||||
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fovertrue%2Fwechat?ref=badge_large)
|
||||
60
vendor/overtrue/wechat/composer.json
vendored
Executable file
60
vendor/overtrue/wechat/composer.json
vendored
Executable file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "overtrue/wechat",
|
||||
"description": "微信SDK",
|
||||
"keywords": [
|
||||
"easywechat",
|
||||
"wechat",
|
||||
"weixin",
|
||||
"weixin-sdk",
|
||||
"sdk"
|
||||
],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "overtrue",
|
||||
"email": "anzhengchao@gmail.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"ext-fileinfo": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-simplexml": "*",
|
||||
"easywechat-composer/easywechat-composer": "^1.1",
|
||||
"guzzlehttp/guzzle": "^6.2",
|
||||
"monolog/monolog": "^1.22 || ^2.0",
|
||||
"overtrue/socialite": "~2.0",
|
||||
"pimple/pimple": "^3.0",
|
||||
"psr/simple-cache": "^1.0",
|
||||
"symfony/cache": "^3.3 || ^4.3 || ^5.0",
|
||||
"symfony/event-dispatcher": "^4.3 || ^5.0",
|
||||
"symfony/http-foundation": "^2.7 || ^3.0 || ^4.0 || ^5.0",
|
||||
"symfony/psr-http-message-bridge": "^0.3 || ^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^2.15",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"mockery/mockery": "^1.2.3",
|
||||
"phpstan/phpstan": "^0.12.0",
|
||||
"phpunit/phpunit": "^7.5"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"EasyWeChat\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/Kernel/Support/Helpers.php",
|
||||
"src/Kernel/Helpers.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"EasyWeChat\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"phpcs": "vendor/bin/php-cs-fixer fix",
|
||||
"phpstan": "vendor/bin/phpstan analyse",
|
||||
"test": "vendor/bin/phpunit"
|
||||
}
|
||||
}
|
||||
39
vendor/overtrue/wechat/src/BasicService/Application.php
vendored
Executable file
39
vendor/overtrue/wechat/src/BasicService/Application.php
vendored
Executable file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace EasyWeChat\BasicService;
|
||||
|
||||
use EasyWeChat\Kernel\ServiceContainer;
|
||||
|
||||
/**
|
||||
* Class Application.
|
||||
*
|
||||
* @author overtrue <i@overtrue.me>
|
||||
*
|
||||
* @property \EasyWeChat\BasicService\Jssdk\Client $jssdk
|
||||
* @property \EasyWeChat\BasicService\Media\Client $media
|
||||
* @property \EasyWeChat\BasicService\QrCode\Client $qrcode
|
||||
* @property \EasyWeChat\BasicService\Url\Client $url
|
||||
* @property \EasyWeChat\BasicService\ContentSecurity\Client $content_security
|
||||
*/
|
||||
class Application extends ServiceContainer
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $providers = [
|
||||
Jssdk\ServiceProvider::class,
|
||||
QrCode\ServiceProvider::class,
|
||||
Media\ServiceProvider::class,
|
||||
Url\ServiceProvider::class,
|
||||
ContentSecurity\ServiceProvider::class,
|
||||
];
|
||||
}
|
||||
123
vendor/overtrue/wechat/src/BasicService/ContentSecurity/Client.php
vendored
Executable file
123
vendor/overtrue/wechat/src/BasicService/ContentSecurity/Client.php
vendored
Executable file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace EasyWeChat\BasicService\ContentSecurity;
|
||||
|
||||
use EasyWeChat\Kernel\BaseClient;
|
||||
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Class Client.
|
||||
*
|
||||
* @author tianyong90 <412039588@qq.com>
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUri = 'https://api.weixin.qq.com/wxa/';
|
||||
|
||||
/**
|
||||
* Text content security check.
|
||||
*
|
||||
* @param string $text
|
||||
*
|
||||
* @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
|
||||
*
|
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
*/
|
||||
public function checkText(string $text)
|
||||
{
|
||||
$params = [
|
||||
'content' => $text,
|
||||
];
|
||||
|
||||
return $this->httpPostJson('msg_sec_check', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Image security check.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
|
||||
*
|
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
*/
|
||||
public function checkImage(string $path)
|
||||
{
|
||||
return $this->httpUpload('img_sec_check', ['media' => $path]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Media security check.
|
||||
*
|
||||
* @param string $mediaUrl
|
||||
* @param int $mediaType
|
||||
*
|
||||
* @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
|
||||
*
|
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
|
||||
*/
|
||||
public function checkMediaAsync(string $mediaUrl, int $mediaType)
|
||||
{
|
||||
/*
|
||||
* 1:音频;2:图片
|
||||
*/
|
||||
$mediaTypes = [1, 2];
|
||||
|
||||
if (!in_array($mediaType, $mediaTypes, true)) {
|
||||
throw new InvalidArgumentException('media type must be 1 or 2');
|
||||
}
|
||||
|
||||
$params = [
|
||||
'media_url' => $mediaUrl,
|
||||
'media_type' => $mediaType,
|
||||
];
|
||||
|
||||
return $this->httpPostJson('media_check_async', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Image security check async.
|
||||
*
|
||||
* @param string $mediaUrl
|
||||
*
|
||||
* @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
|
||||
*
|
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
*/
|
||||
public function checkImageAsync(string $mediaUrl)
|
||||
{
|
||||
return $this->checkMediaAsync($mediaUrl, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio security check async.
|
||||
*
|
||||
* @param string $mediaUrl
|
||||
*
|
||||
* @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
|
||||
*
|
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
*/
|
||||
public function checkAudioAsync(string $mediaUrl)
|
||||
{
|
||||
return $this->checkMediaAsync($mediaUrl, 1);
|
||||
}
|
||||
}
|
||||
31
vendor/overtrue/wechat/src/BasicService/ContentSecurity/ServiceProvider.php
vendored
Executable file
31
vendor/overtrue/wechat/src/BasicService/ContentSecurity/ServiceProvider.php
vendored
Executable file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace EasyWeChat\BasicService\ContentSecurity;
|
||||
|
||||
use Pimple\Container;
|
||||
use Pimple\ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* Class ServiceProvider.
|
||||
*/
|
||||
class ServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function register(Container $app)
|
||||
{
|
||||
$app['content_security'] = function ($app) {
|
||||
return new Client($app);
|
||||
};
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user