1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of ibrand/laravel-sms. |
5
|
|
|
* |
6
|
|
|
* (c) iBrand <https://www.ibrand.cc> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace iBrand\Sms; |
13
|
|
|
|
14
|
|
|
use Carbon\Carbon; |
15
|
|
|
use iBrand\Sms\Jobs\DbLogger; |
16
|
|
|
use iBrand\Sms\Messages\CodeMessage; |
17
|
|
|
use iBrand\Sms\Storage\CacheStorage; |
18
|
|
|
use iBrand\Sms\Storage\StorageInterface; |
19
|
|
|
use Overtrue\EasySms\Contracts\MessageInterface; |
20
|
|
|
use Overtrue\EasySms\EasySms; |
21
|
|
|
use Overtrue\EasySms\Exceptions\NoGatewayAvailableException; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Class Sms. |
25
|
|
|
*/ |
26
|
|
|
class Sms |
27
|
|
|
{ |
28
|
|
|
/** |
29
|
|
|
* @var EasySms |
30
|
|
|
*/ |
31
|
|
|
protected $easySms; |
32
|
|
|
/** |
33
|
|
|
* @var |
34
|
|
|
*/ |
35
|
|
|
protected $storage; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var |
39
|
|
|
*/ |
40
|
|
|
protected $key; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @param mixed $key |
44
|
|
|
*/ |
45
|
30 |
|
public function setKey($key) |
46
|
|
|
{ |
47
|
30 |
|
$key = 'ibrand.sms.' . $key; |
48
|
30 |
|
$this->key = md5($key); |
49
|
30 |
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @return mixed |
53
|
|
|
*/ |
54
|
4 |
|
public function getKey() |
55
|
|
|
{ |
56
|
4 |
|
return $this->key; |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Sms constructor. |
61
|
|
|
* |
62
|
|
|
* @param EasySms $easySms |
63
|
|
|
*/ |
64
|
39 |
|
public function __construct(EasySms $easySms, StorageInterface $storage) |
65
|
|
|
{ |
66
|
39 |
|
$this->easySms = $easySms; |
67
|
39 |
|
$this->storage = $storage; |
68
|
39 |
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @param StorageInterface $storage |
72
|
|
|
*/ |
73
|
4 |
|
public function setStorage(StorageInterface $storage) |
74
|
|
|
{ |
75
|
4 |
|
$this->storage = $storage; |
76
|
4 |
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @param $to |
80
|
|
|
* @param null $data |
81
|
|
|
* @param array $gateways |
82
|
|
|
* |
83
|
|
|
* @return bool |
84
|
|
|
*/ |
85
|
26 |
|
public function send($to, $data = [], array $gateways = []) |
86
|
|
|
{ |
87
|
|
|
try { |
88
|
26 |
|
$flag = false; |
89
|
|
|
|
90
|
26 |
|
$this->setKey($to); |
91
|
|
|
|
92
|
|
|
//1. get code from storage. |
93
|
26 |
|
$code = $this->getCodeFromStorage(); |
94
|
|
|
|
95
|
26 |
|
if ($this->needNewCode($code)) { |
96
|
26 |
|
$code = $this->getNewCode($to); |
97
|
|
|
} |
98
|
|
|
|
99
|
26 |
|
$validMinutes = (int) config('ibrand.sms.code.validMinutes', 5); |
100
|
|
|
|
101
|
26 |
|
if (!($data instanceof MessageInterface)) { |
102
|
26 |
|
$message = new CodeMessage($code->code, $validMinutes, $data); |
|
|
|
|
103
|
|
|
} else { |
104
|
|
|
$message = $data; |
105
|
|
|
} |
106
|
|
|
|
107
|
26 |
|
$results = $this->easySms->send($to, $message, $gateways); |
108
|
|
|
|
109
|
22 |
|
foreach ($results as $key => $value) { |
110
|
22 |
|
if ('success' == $value['status']) { |
111
|
22 |
|
$code->put('sent', true); |
112
|
22 |
|
$code->put('sentAt', Carbon::now()); |
113
|
22 |
|
$this->storage->set($this->key, $code); |
114
|
22 |
|
$flag = true; |
115
|
|
|
} |
116
|
|
|
} |
117
|
8 |
|
} catch (NoGatewayAvailableException $noGatewayAvailableException) { |
118
|
8 |
|
$results = $noGatewayAvailableException->results; |
119
|
8 |
|
$flag = false; |
120
|
|
|
} catch (\Exception $exception) { |
121
|
|
|
$results = $exception->getMessage(); |
122
|
|
|
$flag = false; |
123
|
|
|
} |
124
|
|
|
|
125
|
26 |
|
DbLogger::dispatch($code, json_encode($results), $flag); |
|
|
|
|
126
|
|
|
|
127
|
26 |
|
return $flag; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* check china mobile. |
132
|
|
|
* |
133
|
|
|
* @param $to |
134
|
|
|
* |
135
|
|
|
* @return false|int |
136
|
|
|
*/ |
137
|
2 |
|
public function verifyMobile($to) |
138
|
|
|
{ |
139
|
2 |
|
return preg_match('/^(?:\+?86)?1(?:3\d{3}|5[^4\D]\d{2}|8\d{3}|7(?:[0-35-9]\d{2}|4(?:0\d|1[0-2]|9\d))|9[0-35-9]\d{2}|6[2567]\d{2}|4(?:(?:10|4[01])\d{3}|[68]\d{4}|[579]\d{2}))\d{6}$/', $to); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* @param $to |
144
|
|
|
* |
145
|
|
|
* @return mixed |
146
|
|
|
*/ |
147
|
26 |
|
public function getCodeFromStorage() |
148
|
|
|
{ |
149
|
26 |
|
return $this->storage->get($this->key, ''); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* @param $code |
154
|
|
|
* |
155
|
|
|
* @return bool |
156
|
|
|
*/ |
157
|
26 |
|
protected function needNewCode($code) |
158
|
|
|
{ |
159
|
26 |
|
if (empty($code)) { |
160
|
26 |
|
return true; |
161
|
|
|
} |
162
|
|
|
|
163
|
8 |
|
return $this->checkAttempts($code); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Check attempt times. |
168
|
|
|
* |
169
|
|
|
* @param $code |
170
|
|
|
* |
171
|
|
|
* @return bool |
172
|
|
|
*/ |
173
|
8 |
|
private function checkAttempts($code) |
174
|
|
|
{ |
175
|
8 |
|
$maxAttempts = config('ibrand.sms.code.maxAttempts'); |
176
|
|
|
|
177
|
8 |
|
if ($code->expireAt > Carbon::now() && $code->attempts < $maxAttempts) { |
178
|
4 |
|
return false; |
179
|
|
|
} |
180
|
|
|
|
181
|
8 |
|
return true; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* @param $to |
186
|
|
|
* |
187
|
|
|
* @return Code |
188
|
|
|
*/ |
189
|
30 |
|
public function getNewCode($to) |
190
|
|
|
{ |
191
|
30 |
|
$code = $this->generateCode($to); |
192
|
|
|
|
193
|
30 |
|
$this->storage->set($this->key, $code); |
194
|
|
|
|
195
|
30 |
|
return $code; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* @param $to |
200
|
|
|
* |
201
|
|
|
* @return bool |
202
|
|
|
*/ |
203
|
6 |
|
public function canSend($to) |
204
|
|
|
{ |
205
|
6 |
|
$this->setKey($to); |
206
|
|
|
|
207
|
6 |
|
$code = $this->storage->get($this->key, ''); |
208
|
|
|
|
209
|
6 |
|
if (empty($code) || $code->sentAt < Carbon::now()->addMinutes(-1)) { |
210
|
6 |
|
return true; |
211
|
|
|
} |
212
|
|
|
|
213
|
6 |
|
return false; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* @param $to |
218
|
|
|
* |
219
|
|
|
* @return Code |
220
|
|
|
*/ |
221
|
30 |
|
public function generateCode($to) |
222
|
|
|
{ |
223
|
30 |
|
$length = (int) config('ibrand.sms.code.length', 5); |
224
|
30 |
|
$characters = '0123456789'; |
225
|
30 |
|
$charLength = strlen($characters); |
226
|
30 |
|
$randomString = ''; |
227
|
30 |
|
for ($i = 0; $i < $length; ++$i) { |
228
|
30 |
|
$randomString .= $characters[mt_rand(0, $charLength - 1)]; |
229
|
|
|
} |
230
|
|
|
|
231
|
30 |
|
$validMinutes = (int) config('ibrand.sms.code.validMinutes', 5); |
232
|
|
|
|
233
|
30 |
|
return new Code($to, $randomString, false, 0, Carbon::now()->addMinutes($validMinutes)); |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* @return CacheStorage|StorageInterface |
238
|
|
|
*/ |
239
|
5 |
|
public function getStorage() |
240
|
|
|
{ |
241
|
5 |
|
return $this->storage ? $this->storage : new CacheStorage(); |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
/** |
245
|
|
|
* @param $to |
246
|
|
|
* @param $inputCode |
247
|
|
|
* |
248
|
|
|
* @return bool |
249
|
|
|
*/ |
250
|
4 |
|
public function checkCode($to, $inputCode) |
251
|
|
|
{ |
252
|
4 |
|
if (config('app.debug')) { |
253
|
|
|
return true; |
254
|
|
|
} |
255
|
|
|
|
256
|
4 |
|
$this->setKey($to); |
257
|
|
|
|
258
|
4 |
|
$code = $this->storage->get($this->key, ''); |
259
|
|
|
|
260
|
4 |
|
if (empty($code)) { |
261
|
|
|
return false; |
262
|
|
|
} |
263
|
|
|
|
264
|
4 |
|
if ($code && $code->code == $inputCode) { |
265
|
4 |
|
$this->storage->forget($this->key); |
266
|
|
|
|
267
|
4 |
|
return true; |
268
|
|
|
} |
269
|
|
|
|
270
|
4 |
|
$code->put('attempts', $code->attempts + 1); |
271
|
|
|
|
272
|
4 |
|
$this->storage->set($this->key, $code); |
273
|
|
|
|
274
|
4 |
|
return false; |
275
|
|
|
} |
276
|
|
|
} |
277
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.