1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Toplan\PhpSms; |
4
|
|
|
|
5
|
|
|
use SuperClosure\Serializer; |
6
|
|
|
use Toplan\TaskBalance\Balancer; |
7
|
|
|
use Toplan\TaskBalance\Task; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Class Sms |
11
|
|
|
* |
12
|
|
|
* |
13
|
|
|
* @author toplan<[email protected]> |
14
|
|
|
*/ |
15
|
|
|
class Sms |
16
|
|
|
{ |
17
|
|
|
/** |
18
|
|
|
* Send task`s name. |
19
|
|
|
* |
20
|
|
|
* @var string |
21
|
|
|
*/ |
22
|
|
|
const TASK = 'PhpSms'; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* SMS agents(service providers), |
26
|
|
|
* they are instances of class [Toplan\PhpSms\Agent]. |
27
|
|
|
* |
28
|
|
|
* @var array |
29
|
|
|
*/ |
30
|
|
|
protected static $agents = []; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* The enabled agents` name. |
34
|
|
|
* |
35
|
|
|
* @var array |
36
|
|
|
*/ |
37
|
|
|
protected static $agentsName = []; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* The enabled agents` config info. |
41
|
|
|
* |
42
|
|
|
* @var array |
43
|
|
|
*/ |
44
|
|
|
protected static $agentsConfig = []; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Whether to use queue. |
48
|
|
|
* |
49
|
|
|
* @var bool |
50
|
|
|
*/ |
51
|
|
|
protected static $enableQueue = false; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* How to push to queue. |
55
|
|
|
* |
56
|
|
|
* @var \Closure |
57
|
|
|
*/ |
58
|
|
|
protected static $howToUseQueue = null; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* The enable hooks for balance task. |
62
|
|
|
* |
63
|
|
|
* @var array |
64
|
|
|
*/ |
65
|
|
|
protected static $enableHooks = [ |
66
|
|
|
'beforeRun', |
67
|
|
|
'beforeDriverRun', |
68
|
|
|
'afterDriverRun', |
69
|
|
|
'afterRun', |
70
|
|
|
]; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* An instance of class [SuperClosure\Serializer] |
74
|
|
|
* |
75
|
|
|
* @var Serializer |
76
|
|
|
*/ |
77
|
|
|
protected static $serializer = null; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* SMS(or voice verify) data container. |
81
|
|
|
* |
82
|
|
|
* @var array |
83
|
|
|
*/ |
84
|
|
|
protected $smsData = [ |
85
|
|
|
'to' => null, |
86
|
|
|
'templates' => [], |
87
|
|
|
'content' => null, |
88
|
|
|
'templateData' => [], |
89
|
|
|
'voiceCode' => null, |
90
|
|
|
]; |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* The name of first agent. |
94
|
|
|
* |
95
|
|
|
* @var string|null |
96
|
|
|
*/ |
97
|
|
|
protected $firstAgent = null; |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* Whether the current instance has already pushed to queue. |
101
|
|
|
* |
102
|
|
|
* @var bool |
103
|
|
|
*/ |
104
|
|
|
protected $pushedToQueue = false; |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Status container, |
108
|
|
|
* store config data before serialize a instance(before enqueue). |
109
|
|
|
* |
110
|
|
|
* @var array |
111
|
|
|
*/ |
112
|
|
|
protected $_status_before_enqueue_ = []; |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* Constructor |
116
|
|
|
* |
117
|
|
|
* @param bool $autoBoot |
118
|
|
|
*/ |
119
|
6 |
|
public function __construct($autoBoot = true) |
120
|
|
|
{ |
121
|
6 |
|
if ($autoBoot) { |
122
|
3 |
|
self::bootstrap(); |
123
|
3 |
|
} |
124
|
6 |
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Boot balanced send task. |
128
|
|
|
*/ |
129
|
6 |
|
public static function bootstrap() |
130
|
|
|
{ |
131
|
6 |
|
$task = self::getTask(); |
132
|
|
|
|
133
|
|
|
//注意这里判断Task实例有没有drivers,不能用empty,因为其不能检查语句, |
|
|
|
|
134
|
|
|
//而恰巧Task实例获取drivers是通过魔术方法获取的. |
135
|
6 |
|
if (!count($task->drivers)) { |
136
|
3 |
|
self::configuration(); |
137
|
3 |
|
self::createDrivers($task); |
138
|
3 |
|
} |
139
|
6 |
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* Get or generate a balanced task instance for send SMS/voice verify. |
143
|
|
|
* |
144
|
|
|
* @return Task |
145
|
|
|
*/ |
146
|
15 |
|
public static function getTask() |
147
|
|
|
{ |
148
|
15 |
|
if (!Balancer::hasTask(self::TASK)) { |
149
|
3 |
|
Balancer::task(self::TASK); |
150
|
3 |
|
} |
151
|
|
|
|
152
|
15 |
|
return Balancer::getTask(self::TASK); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Configuration. |
157
|
|
|
*/ |
158
|
6 |
|
protected static function configuration() |
159
|
|
|
{ |
160
|
6 |
|
$config = []; |
161
|
6 |
|
if (empty(self::$agentsName)) { |
162
|
3 |
|
self::initEnableAgents($config); |
163
|
3 |
|
} |
164
|
6 |
|
$diff = array_diff_key(self::$agentsName, self::$agentsConfig); |
165
|
6 |
|
self::initAgentsConfig(array_keys($diff), $config); |
166
|
6 |
|
self::validateConfig(); |
167
|
6 |
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Try to read and set enable agents` name from config file. |
171
|
|
|
* |
172
|
|
|
* @param array $config |
173
|
|
|
*/ |
174
|
3 |
|
protected static function initEnableAgents(array &$config) |
175
|
|
|
{ |
176
|
3 |
|
$config = empty($config) ? include __DIR__ . '/../config/phpsms.php' : $config; |
177
|
3 |
|
$enableAgents = isset($config['enable']) ? $config['enable'] : []; |
178
|
3 |
|
self::enable($enableAgents); |
179
|
3 |
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Try to read and set enabled agents` config from config file. |
183
|
|
|
* |
184
|
|
|
* @param array $agents |
185
|
|
|
* @param array $config |
186
|
|
|
*/ |
187
|
6 |
|
protected static function initAgentsConfig(array $agents, array &$config) |
188
|
|
|
{ |
189
|
6 |
|
if (empty($agents)) { |
190
|
3 |
|
return; |
191
|
|
|
} |
192
|
3 |
|
$config = empty($config) ? include __DIR__ . '/../config/phpsms.php' : $config; |
193
|
3 |
|
$agentsConfig = isset($config['agents']) ? $config['agents'] : []; |
194
|
3 |
|
foreach ($agents as $name) { |
195
|
3 |
|
$agentConfig = isset($agentsConfig[$name]) ? $agentsConfig[$name] : []; |
196
|
3 |
|
self::agents($name, $agentConfig); |
197
|
3 |
|
} |
198
|
3 |
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* validate configuration. |
202
|
|
|
* |
203
|
|
|
* @throws PhpSmsException |
204
|
|
|
*/ |
205
|
6 |
|
protected static function validateConfig() |
206
|
|
|
{ |
207
|
6 |
|
if (!count(self::$agentsName)) { |
208
|
|
|
throw new PhpSmsException('Please configure at least one agent'); |
209
|
|
|
} |
210
|
6 |
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* Create drivers of the balanced task. |
214
|
|
|
* |
215
|
|
|
* @param Task $task |
216
|
|
|
*/ |
217
|
18 |
|
protected static function createDrivers(Task $task) |
218
|
|
|
{ |
219
|
3 |
|
foreach (self::$agentsName as $name => $options) { |
220
|
|
|
//获取代理器配置 |
221
|
3 |
|
$configData = self::getAgentConfigData($name); |
222
|
|
|
//解析代理器数组模式的调度配置 |
223
|
3 |
|
if (is_array($options)) { |
224
|
3 |
|
$data = self::parseAgentArrayOptions($options); |
225
|
3 |
|
$configData = array_merge($configData, $data); |
226
|
3 |
|
$options = $data['driverOpts']; |
227
|
3 |
|
} |
228
|
|
|
//创建任务驱动器 |
229
|
3 |
|
$task->driver("$name $options")->data($configData) |
230
|
18 |
|
->work(function ($driver) { |
231
|
18 |
|
$configData = $driver->getDriverData(); |
232
|
18 |
|
$agent = self::getSmsAgent($driver->name, $configData); |
233
|
18 |
|
$smsData = $driver->getTaskData(); |
234
|
18 |
|
extract($smsData); |
235
|
18 |
|
if (isset($smsData['voiceCode']) && $smsData['voiceCode']) { |
236
|
|
|
$agent->voiceVerify($to, $voiceCode); |
237
|
|
|
} else { |
238
|
18 |
|
$template = isset($templates[$driver->name]) ? $templates[$driver->name] : 0; |
239
|
18 |
|
$agent->sendSms($template, $to, $templateData, $content); |
240
|
|
|
} |
241
|
18 |
|
$result = $agent->result(); |
242
|
18 |
|
if ($result['success']) { |
243
|
18 |
|
$driver->success(); |
244
|
18 |
|
} |
245
|
18 |
|
unset($result['success']); |
246
|
|
|
|
247
|
18 |
|
return $result; |
248
|
3 |
|
}); |
249
|
3 |
|
} |
250
|
3 |
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* Parse the enabled agents` scheduling config data. |
254
|
|
|
* 解析可用代理器的数组模式的调度配置 |
255
|
|
|
* |
256
|
|
|
* @param array $options |
257
|
|
|
* |
258
|
|
|
* @return array |
259
|
|
|
*/ |
260
|
3 |
|
protected static function parseAgentArrayOptions(array $options) |
261
|
|
|
{ |
262
|
3 |
|
$agentClass = self::pullAgentOptionByName($options, 'agentClass'); |
263
|
3 |
|
$sendSms = self::pullAgentOptionByName($options, 'sendSms'); |
264
|
3 |
|
$voiceVerify = self::pullAgentOptionByName($options, 'voiceVerify'); |
265
|
3 |
|
$backup = self::pullAgentOptionByName($options, 'backup') ? 'backup' : ''; |
266
|
3 |
|
$driverOpts = implode(' ', array_values($options)) . " $backup"; |
267
|
|
|
|
268
|
3 |
|
return compact('agentClass', 'sendSms', 'voiceVerify', 'driverOpts'); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Pull the character option data from the scheduling config. |
273
|
|
|
* |
274
|
|
|
* @param array $options |
275
|
|
|
* @param string $name |
276
|
|
|
* |
277
|
|
|
* @return mixed |
278
|
|
|
*/ |
279
|
3 |
|
protected static function pullAgentOptionByName(array &$options, $name) |
280
|
|
|
{ |
281
|
3 |
|
if (!isset($options[$name])) { |
282
|
3 |
|
return; |
283
|
|
|
} |
284
|
3 |
|
$value = $options[$name]; |
285
|
3 |
|
unset($options[$name]); |
286
|
|
|
|
287
|
3 |
|
return $value; |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* Get agent config data by name. |
292
|
|
|
* |
293
|
|
|
* @param string $name |
294
|
|
|
* |
295
|
|
|
* @return array |
296
|
|
|
*/ |
297
|
3 |
|
protected static function getAgentConfigData($name) |
298
|
|
|
{ |
299
|
3 |
|
return isset(self::$agentsConfig[$name]) ? self::$agentsConfig[$name] : []; |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
/** |
303
|
|
|
* Get a sms agent instance by agent name, |
304
|
|
|
* if null, will try to create a new agent instance. |
305
|
|
|
* |
306
|
|
|
* @param string $name |
307
|
|
|
* @param array $configData |
308
|
|
|
* |
309
|
|
|
* @throws PhpSmsException |
310
|
|
|
* |
311
|
|
|
* @return mixed |
312
|
|
|
*/ |
313
|
21 |
|
public static function getSmsAgent($name, array $configData) |
314
|
|
|
{ |
315
|
21 |
|
if (!isset(self::$agents[$name])) { |
316
|
6 |
|
$configData['name'] = $name; |
317
|
6 |
|
$className = isset($configData['agentClass']) ? $configData['agentClass'] : ('Toplan\\PhpSms\\' . $name . 'Agent'); |
318
|
6 |
|
if ((isset($configData['sendSms']) && is_callable($configData['sendSms'])) || |
319
|
6 |
|
(isset($configData['voiceVerify']) && is_callable($configData['voiceVerify']))) { |
320
|
|
|
//创建寄生代理器 |
321
|
3 |
|
$configData['agentClass'] = ''; |
322
|
3 |
|
self::$agents[$name] = new ParasiticAgent($configData); |
323
|
6 |
|
} elseif (class_exists($className)) { |
324
|
|
|
//创建新代理器 |
325
|
3 |
|
self::$agents[$name] = new $className($configData); |
326
|
3 |
|
} else { |
327
|
|
|
//无代理器可用 |
328
|
|
|
throw new PhpSmsException("Do not support [$name] agent."); |
329
|
|
|
} |
330
|
6 |
|
} |
331
|
|
|
|
332
|
21 |
|
return self::$agents[$name]; |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
/** |
336
|
|
|
* Set enable agents. |
337
|
|
|
* |
338
|
|
|
* @param mixed $agentName |
339
|
|
|
* @param mixed $options |
340
|
|
|
*/ |
341
|
6 |
|
public static function enable($agentName, $options = null) |
342
|
|
|
{ |
343
|
6 |
|
if (is_array($agentName)) { |
344
|
6 |
|
foreach ($agentName as $name => $opt) { |
345
|
6 |
|
self::enable($name, $opt); |
346
|
6 |
|
} |
347
|
6 |
|
} elseif ($agentName && is_string($agentName) && $options !== null) { |
348
|
3 |
|
self::$agentsName["$agentName"] = is_array($options) ? $options : "$options"; |
349
|
6 |
|
} elseif (is_int($agentName) && !is_array($options) && "$options") { |
350
|
3 |
|
self::$agentsName["$options"] = '1'; |
351
|
6 |
|
} elseif ($agentName && $options === null) { |
352
|
3 |
|
self::$agentsName["$agentName"] = '1'; |
353
|
3 |
|
} |
354
|
6 |
|
} |
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* Set config info by agent name. |
358
|
|
|
* |
359
|
|
|
* @param array|string $agentName |
360
|
|
|
* @param array $config |
361
|
|
|
* |
362
|
|
|
* @throws PhpSmsException |
363
|
|
|
*/ |
364
|
6 |
|
public static function agents($agentName, array $config = []) |
365
|
|
|
{ |
366
|
6 |
|
if (is_array($agentName)) { |
367
|
3 |
|
foreach ($agentName as $name => $conf) { |
368
|
3 |
|
self::agents($name, $conf); |
369
|
3 |
|
} |
370
|
6 |
|
} elseif ($agentName && is_array($config)) { |
371
|
6 |
|
if (preg_match('/^[0-9]+$/', $agentName)) { |
372
|
|
|
throw new PhpSmsException("Agent name [$agentName] must be string, could not be a pure digital"); |
373
|
|
|
} |
374
|
6 |
|
self::$agentsConfig["$agentName"] = $config; |
375
|
6 |
|
} |
376
|
6 |
|
} |
377
|
|
|
|
378
|
|
|
/** |
379
|
|
|
* Get the enabled agents` name. |
380
|
|
|
* |
381
|
|
|
* @return array |
382
|
|
|
*/ |
383
|
12 |
|
public static function getEnableAgents() |
384
|
|
|
{ |
385
|
12 |
|
return self::$agentsName; |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
/** |
389
|
|
|
* Get the enabled agents` config info. |
390
|
|
|
* |
391
|
|
|
* @return array |
392
|
|
|
*/ |
393
|
12 |
|
public static function getAgentsConfig() |
394
|
|
|
{ |
395
|
12 |
|
return self::$agentsConfig; |
396
|
|
|
} |
397
|
|
|
|
398
|
|
|
/** |
399
|
|
|
* Tear down enable agents and prepare to create and start a new balance task, |
400
|
|
|
* so before do it must destroy old task instance. |
401
|
|
|
*/ |
402
|
6 |
|
public static function cleanEnableAgents() |
403
|
|
|
{ |
404
|
6 |
|
Balancer::destroy(self::TASK); |
405
|
6 |
|
self::$agentsName = []; |
406
|
6 |
|
} |
407
|
|
|
|
408
|
|
|
/** |
409
|
|
|
* Tear down agents config and prepare to create and start a new balance task, |
410
|
|
|
* so before do it must destroy old task instance. |
411
|
|
|
*/ |
412
|
3 |
|
public static function cleanAgentsConfig() |
413
|
|
|
{ |
414
|
3 |
|
Balancer::destroy(self::TASK); |
415
|
3 |
|
self::$agentsConfig = []; |
416
|
3 |
|
} |
417
|
|
|
|
418
|
|
|
/** |
419
|
|
|
* Create a sms instance which send SMS, |
420
|
|
|
* and set SMS templates or content. |
421
|
|
|
* |
422
|
|
|
* @param mixed $agentName |
423
|
|
|
* @param mixed $tempId |
424
|
|
|
* |
425
|
|
|
* @return Sms |
426
|
|
|
*/ |
427
|
|
|
public static function make($agentName = null, $tempId = null) |
428
|
|
|
{ |
429
|
|
|
$sms = new self(); |
430
|
|
|
if (is_array($agentName)) { |
431
|
|
|
$sms->template($agentName); |
432
|
|
|
} elseif ($agentName && is_string($agentName)) { |
433
|
|
|
if ($tempId === null) { |
434
|
|
|
$sms->content($agentName); |
435
|
|
|
} elseif (is_string("$tempId")) { |
436
|
|
|
$sms->template($agentName, $tempId); |
437
|
|
|
} |
438
|
|
|
} |
439
|
|
|
|
440
|
|
|
return $sms; |
441
|
|
|
} |
442
|
|
|
|
443
|
|
|
/** |
444
|
|
|
* Create a sms instance which send voice verify, |
445
|
|
|
* and set verify code. |
446
|
|
|
* |
447
|
|
|
* @param string|int $code |
448
|
|
|
* |
449
|
|
|
* @return Sms |
450
|
|
|
*/ |
451
|
3 |
|
public static function voice($code) |
452
|
|
|
{ |
453
|
3 |
|
$sms = new self(); |
454
|
3 |
|
$sms->smsData['voiceCode'] = $code; |
455
|
|
|
|
456
|
3 |
|
return $sms; |
457
|
|
|
} |
458
|
|
|
|
459
|
|
|
/** |
460
|
|
|
* Set whether to use queue, and define how to use queue. |
461
|
|
|
* |
462
|
|
|
* @param mixed $enable |
463
|
|
|
* @param mixed $handler |
464
|
|
|
* |
465
|
|
|
* @return bool |
466
|
|
|
*/ |
467
|
3 |
|
public static function queue($enable = null, $handler = null) |
468
|
|
|
{ |
469
|
3 |
|
if ($enable === null && $handler === null) { |
470
|
3 |
|
return self::$enableQueue; |
471
|
|
|
} |
472
|
3 |
|
if (is_callable($enable)) { |
473
|
3 |
|
$handler = $enable; |
474
|
3 |
|
$enable = true; |
475
|
3 |
|
} |
476
|
3 |
|
self::$enableQueue = (bool) $enable; |
477
|
3 |
|
if (is_callable($handler)) { |
478
|
3 |
|
self::$howToUseQueue = $handler; |
|
|
|
|
479
|
3 |
|
} |
480
|
|
|
|
481
|
3 |
|
return self::$enableQueue; |
482
|
|
|
} |
483
|
|
|
|
484
|
|
|
/** |
485
|
|
|
* Set the receiver`s mobile number. |
486
|
|
|
* |
487
|
|
|
* @param string $mobile |
488
|
|
|
* |
489
|
|
|
* @return $this |
490
|
|
|
*/ |
491
|
6 |
|
public function to($mobile) |
492
|
|
|
{ |
493
|
6 |
|
$this->smsData['to'] = $mobile; |
494
|
|
|
|
495
|
6 |
|
return $this; |
496
|
|
|
} |
497
|
|
|
|
498
|
|
|
/** |
499
|
|
|
* Set content for content SMS. |
500
|
|
|
* |
501
|
|
|
* @param string $content |
502
|
|
|
* |
503
|
|
|
* @return $this |
504
|
|
|
*/ |
505
|
3 |
|
public function content($content) |
506
|
|
|
{ |
507
|
3 |
|
$this->smsData['content'] = trim((string) $content); |
508
|
|
|
|
509
|
3 |
|
return $this; |
510
|
|
|
} |
511
|
|
|
|
512
|
|
|
/** |
513
|
|
|
* Set template id for template SMS. |
514
|
|
|
* |
515
|
|
|
* @param mixed $agentName |
516
|
|
|
* @param mixed $tempId |
517
|
|
|
* |
518
|
|
|
* @return $this |
519
|
|
|
*/ |
520
|
3 |
|
public function template($agentName, $tempId = null) |
521
|
|
|
{ |
522
|
3 |
|
if (is_array($agentName)) { |
523
|
3 |
|
foreach ($agentName as $k => $v) { |
524
|
3 |
|
$this->template($k, $v); |
525
|
3 |
|
} |
526
|
3 |
|
} elseif ($agentName && $tempId) { |
527
|
3 |
|
if (!isset($this->smsData['templates']) || !is_array($this->smsData['templates'])) { |
528
|
|
|
$this->smsData['templates'] = []; |
529
|
|
|
} |
530
|
3 |
|
$this->smsData['templates']["$agentName"] = $tempId; |
531
|
3 |
|
} |
532
|
|
|
|
533
|
3 |
|
return $this; |
534
|
|
|
} |
535
|
|
|
|
536
|
|
|
/** |
537
|
|
|
* Set template data for template SMS. |
538
|
|
|
* |
539
|
|
|
* @param array $data |
540
|
|
|
* |
541
|
|
|
* @return $this |
542
|
|
|
*/ |
543
|
3 |
|
public function data(array $data) |
544
|
|
|
{ |
545
|
3 |
|
$this->smsData['templateData'] = $data; |
546
|
|
|
|
547
|
3 |
|
return $this; |
548
|
|
|
} |
549
|
|
|
|
550
|
|
|
/** |
551
|
|
|
* Set the first agent by agent`s name. |
552
|
|
|
* |
553
|
|
|
* @param string $name |
554
|
|
|
* |
555
|
|
|
* @return $this |
556
|
|
|
*/ |
557
|
3 |
|
public function agent($name) |
558
|
|
|
{ |
559
|
3 |
|
$this->firstAgent = (string) $name; |
560
|
|
|
|
561
|
3 |
|
return $this; |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
/** |
565
|
|
|
* Start send SMS/voice verify. |
566
|
|
|
* |
567
|
|
|
* If give a true parameter, will immediately start whatever whether to use queue. |
568
|
|
|
* if you are already pushed sms instance to queue, you can recall the method `send()` in queue job without `true` parameter, |
569
|
|
|
* so this mechanism in order to make you convenient use the method `send()` in queue system. |
570
|
|
|
* |
571
|
|
|
* @param bool $immediately |
572
|
|
|
* |
573
|
|
|
* @return mixed |
574
|
|
|
*/ |
575
|
18 |
|
public function send($immediately = false) |
576
|
|
|
{ |
577
|
18 |
|
if (!self::$enableQueue || $this->pushedToQueue) { |
578
|
18 |
|
$immediately = true; |
579
|
18 |
|
} |
580
|
18 |
|
if ($immediately) { |
581
|
18 |
|
$result = Balancer::run(self::TASK, [ |
582
|
18 |
|
'data' => $this->getData(), |
583
|
18 |
|
'driver' => $this->firstAgent, |
584
|
18 |
|
]); |
585
|
18 |
|
} else { |
586
|
3 |
|
$result = $this->push(); |
587
|
|
|
} |
588
|
|
|
|
589
|
18 |
|
return $result; |
590
|
|
|
} |
591
|
|
|
|
592
|
|
|
/** |
593
|
|
|
* Push to queue by custom method. |
594
|
|
|
* |
595
|
|
|
* @throws \Exception | PhpSmsException |
596
|
|
|
* |
597
|
|
|
* @return mixed |
598
|
|
|
*/ |
599
|
3 |
|
public function push() |
600
|
|
|
{ |
601
|
3 |
|
if (is_callable(self::$howToUseQueue)) { |
602
|
|
|
try { |
603
|
3 |
|
$this->pushedToQueue = true; |
604
|
|
|
|
605
|
3 |
|
return call_user_func_array(self::$howToUseQueue, [$this, $this->smsData]); |
606
|
|
|
} catch (\Exception $e) { |
607
|
|
|
$this->pushedToQueue = false; |
608
|
|
|
throw $e; |
609
|
|
|
} |
610
|
|
|
} else { |
611
|
|
|
throw new PhpSmsException('Please define how to use queue by method `queue($enable, $handler)`'); |
612
|
|
|
} |
613
|
|
|
} |
614
|
|
|
|
615
|
|
|
/** |
616
|
|
|
* Get all the data of SMS/voice verify. |
617
|
|
|
* |
618
|
|
|
* @param null|string $name |
619
|
|
|
* |
620
|
|
|
* @return mixed |
621
|
|
|
*/ |
622
|
36 |
|
public function getData($name = null) |
623
|
|
|
{ |
624
|
36 |
|
if (is_string($name) && isset($this->smsData["$name"])) { |
625
|
3 |
|
return $this->smsData[$name]; |
626
|
|
|
} |
627
|
|
|
|
628
|
36 |
|
return $this->smsData; |
629
|
|
|
} |
630
|
|
|
|
631
|
|
|
/** |
632
|
|
|
* Overload static method. |
633
|
|
|
* |
634
|
|
|
* @param string $name |
635
|
|
|
* @param array $args |
636
|
|
|
* |
637
|
|
|
* @throws PhpSmsException |
638
|
|
|
*/ |
639
|
9 |
|
public static function __callStatic($name, $args) |
640
|
|
|
{ |
641
|
9 |
|
$name = $name === 'beforeSend' ? 'beforeRun' : $name; |
642
|
9 |
|
$name = $name === 'afterSend' ? 'afterRun' : $name; |
643
|
9 |
|
$name = $name === 'beforeAgentSend' ? 'beforeDriverRun' : $name; |
644
|
9 |
|
$name = $name === 'afterAgentSend' ? 'afterDriverRun' : $name; |
645
|
9 |
|
if (in_array($name, self::$enableHooks)) { |
646
|
9 |
|
$handler = $args[0]; |
647
|
9 |
|
$override = isset($args[1]) ? (bool) $args[1] : false; |
648
|
9 |
|
if (is_callable($handler)) { |
649
|
9 |
|
$task = self::getTask(); |
650
|
9 |
|
$task->hook($name, $handler, $override); |
651
|
9 |
|
} else { |
652
|
|
|
throw new PhpSmsException("Please give method static $name() a callable parameter"); |
653
|
|
|
} |
654
|
9 |
|
} else { |
655
|
|
|
throw new PhpSmsException("Do not find static method $name()"); |
656
|
|
|
} |
657
|
9 |
|
} |
658
|
|
|
|
659
|
|
|
/** |
660
|
|
|
* Overload method. |
661
|
|
|
* |
662
|
|
|
* @param string $name |
663
|
|
|
* @param array $args |
664
|
|
|
* |
665
|
|
|
* @throws PhpSmsException |
666
|
|
|
* @throws \Exception |
667
|
|
|
*/ |
668
|
3 |
|
public function __call($name, $args) |
669
|
|
|
{ |
670
|
|
|
try { |
671
|
3 |
|
$this->__callStatic($name, $args); |
672
|
3 |
|
} catch (\Exception $e) { |
673
|
|
|
throw $e; |
674
|
|
|
} |
675
|
3 |
|
} |
676
|
|
|
|
677
|
|
|
/** |
678
|
|
|
* Serialize magic method, |
679
|
|
|
* store current sms instance status. |
680
|
|
|
* |
681
|
|
|
* @return array |
682
|
|
|
*/ |
683
|
3 |
|
public function __sleep() |
684
|
|
|
{ |
685
|
|
|
try { |
686
|
3 |
|
$this->_status_before_enqueue_['enableAgents'] = self::serializeEnableAgents(); |
687
|
3 |
|
$this->_status_before_enqueue_['agentsConfig'] = self::getAgentsConfig(); |
688
|
3 |
|
$this->_status_before_enqueue_['handlers'] = self::serializeHandlers(); |
689
|
3 |
|
} catch (\Exception $e) { |
690
|
|
|
//swallow exception |
691
|
|
|
} |
692
|
|
|
|
693
|
3 |
|
return ['pushedToQueue', 'smsData', 'firstAgent', '_status_before_enqueue_']; |
694
|
|
|
} |
695
|
|
|
|
696
|
|
|
/** |
697
|
|
|
* Unserialize magic method, |
698
|
|
|
* note: the force bootstrap must before reinstall handlers! |
699
|
|
|
*/ |
700
|
3 |
|
public function __wakeup() |
701
|
|
|
{ |
702
|
3 |
|
if (empty($this->_status_before_enqueue_)) { |
703
|
|
|
return; |
704
|
|
|
} |
705
|
3 |
|
$status = $this->_status_before_enqueue_; |
706
|
3 |
|
self::$agentsName = self::unserializeEnableAgents($status['enableAgents']); |
707
|
3 |
|
self::$agentsConfig = $status['agentsConfig']; |
708
|
3 |
|
Balancer::destroy(self::TASK); |
709
|
3 |
|
self::bootstrap(); |
710
|
3 |
|
self::reinstallHandlers($status['handlers']); |
711
|
3 |
|
} |
712
|
|
|
|
713
|
|
|
/** |
714
|
|
|
* Get a closure serializer. |
715
|
|
|
* |
716
|
|
|
* @return Serializer |
717
|
|
|
*/ |
718
|
3 |
|
public static function getSerializer() |
719
|
|
|
{ |
720
|
3 |
|
if (!self::$serializer) { |
721
|
3 |
|
self::$serializer = new Serializer(); |
722
|
3 |
|
} |
723
|
|
|
|
724
|
3 |
|
return self::$serializer; |
725
|
|
|
} |
726
|
|
|
|
727
|
|
|
/** |
728
|
|
|
* Serialize enabled agents. |
729
|
|
|
* |
730
|
|
|
* @return array |
731
|
|
|
*/ |
732
|
3 |
|
protected static function serializeEnableAgents() |
733
|
|
|
{ |
734
|
3 |
|
$enableAgents = self::getEnableAgents(); |
735
|
3 |
|
foreach ($enableAgents as $name => &$options) { |
736
|
3 |
|
if (is_array($options)) { |
737
|
3 |
|
self::serializeClosureAndReplace($options, 'sendSms'); |
738
|
3 |
|
self::serializeClosureAndReplace($options, 'voiceVerify'); |
739
|
3 |
|
} |
740
|
3 |
|
} |
741
|
|
|
|
742
|
3 |
|
return $enableAgents; |
743
|
|
|
} |
744
|
|
|
|
745
|
|
|
/** |
746
|
|
|
* Unserialize enabled agents. |
747
|
|
|
* |
748
|
|
|
* @param array $serialized |
749
|
|
|
* |
750
|
|
|
* @return mixed |
751
|
|
|
*/ |
752
|
3 |
|
protected static function unserializeEnableAgents(array $serialized) |
753
|
|
|
{ |
754
|
3 |
|
foreach ($serialized as $name => &$options) { |
755
|
3 |
|
if (is_array($options)) { |
756
|
3 |
|
self::unserializeToClosureAndReplace($options, 'sendSms'); |
757
|
3 |
|
self::unserializeToClosureAndReplace($options, 'voiceVerify'); |
758
|
3 |
|
} |
759
|
3 |
|
} |
760
|
|
|
|
761
|
3 |
|
return $serialized; |
762
|
|
|
} |
763
|
|
|
|
764
|
|
|
/** |
765
|
|
|
* Serialize character closure value of a array and replace origin value. |
766
|
|
|
* |
767
|
|
|
* @param array $options |
768
|
|
|
* @param string $key |
769
|
|
|
*/ |
770
|
3 |
|
protected static function serializeClosureAndReplace(array &$options, $key) |
771
|
|
|
{ |
772
|
3 |
|
if (isset($options["$key"]) && is_callable($options["$key"])) { |
773
|
3 |
|
$serializer = self::getSerializer(); |
774
|
3 |
|
$options["$key"] = (string) $serializer->serialize($options["$key"]); |
775
|
3 |
|
} |
776
|
3 |
|
} |
777
|
|
|
|
778
|
|
|
/** |
779
|
|
|
* Unserialize character string of a array to closure and replace origin value. |
780
|
|
|
* |
781
|
|
|
* @param array $options |
782
|
|
|
* @param string $key |
783
|
|
|
*/ |
784
|
3 |
|
protected static function unserializeToClosureAndReplace(array &$options, $key) |
785
|
|
|
{ |
786
|
3 |
|
if (isset($options["$key"])) { |
787
|
3 |
|
$serializer = self::getSerializer(); |
788
|
3 |
|
$options["$key"] = $serializer->unserialize($options["$key"]); |
789
|
3 |
|
} |
790
|
3 |
|
} |
791
|
|
|
|
792
|
|
|
/** |
793
|
|
|
* Serialize these hooks` handlers: |
794
|
|
|
* 'beforeRun','beforeDriverRun','afterDriverRun','afterRun'. |
795
|
|
|
* |
796
|
|
|
* @return array |
797
|
|
|
*/ |
798
|
3 |
|
protected static function serializeHandlers() |
799
|
|
|
{ |
800
|
3 |
|
$hooks = []; |
801
|
3 |
|
$serializer = self::getSerializer(); |
802
|
3 |
|
$task = self::getTask(); |
803
|
3 |
|
foreach ($task->handlers as $hookName => $handlers) { |
804
|
3 |
|
foreach ($handlers as $handler) { |
805
|
3 |
|
$serialized = $serializer->serialize($handler); |
806
|
3 |
|
if (!isset($hooks[$hookName])) { |
807
|
3 |
|
$hooks[$hookName] = []; |
808
|
3 |
|
} |
809
|
3 |
|
array_push($hooks[$hookName], $serialized); |
810
|
3 |
|
} |
811
|
3 |
|
} |
812
|
|
|
|
813
|
3 |
|
return $hooks; |
814
|
|
|
} |
815
|
|
|
|
816
|
|
|
/** |
817
|
|
|
* Reinstall balance task hooks` handlers by serialized handlers. |
818
|
|
|
* |
819
|
|
|
* @param array $handlers |
820
|
|
|
*/ |
821
|
3 |
|
protected static function reinstallHandlers(array $handlers) |
822
|
|
|
{ |
823
|
3 |
|
$serializer = self::getSerializer(); |
824
|
3 |
|
foreach ($handlers as $hookName => $serializedHandlers) { |
825
|
3 |
|
foreach ($serializedHandlers as $index => $handler) { |
826
|
3 |
|
if (is_string($handler)) { |
827
|
3 |
|
$handler = $serializer->unserialize($handler); |
828
|
3 |
|
} |
829
|
3 |
|
self::$hookName($handler, $index === 0); |
830
|
3 |
|
} |
831
|
3 |
|
} |
832
|
3 |
|
} |
833
|
|
|
} |
834
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.