| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- <?php
- namespace App\Jobs;
- use Illuminate\Bus\Queueable;
- use Illuminate\Contracts\Queue\ShouldQueue;
- use Illuminate\Foundation\Bus\Dispatchable;
- use Illuminate\Queue\InteractsWithQueue;
- use Illuminate\Queue\SerializesModels;
- use RuntimeException;
- class SendSmsMessage implements ShouldQueue
- {
- use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
- public function __construct(public int $messageId) {}
- public function handle()
- {
- $msg = \App\Models\SmsMessage::with(['recipients'])->findOrFail($this->messageId);
- $msg->update(['status' => 'processing']);
- foreach ($msg->recipients as $r) {
- if (in_array($r->status, ['sent', 'failed'])) continue;
- try {
- $phone = $r->phone;
- $message = $msg->content;
- $params = array(
- 'to' => '+39' . $phone,
- 'from' => env('SMS_FROM', 'Leezard'),
- 'message' => $message,
- 'format' => 'json',
- );
- $this->sms_send($params);
- $r->update(['status' => 'sent', 'sent_at' => now(), 'error_message' => null]);
- } catch (\Throwable $e) {
- $r->update(['status' => 'failed', 'error_message' => $e->getMessage()]);
- }
- }
- $total = $msg->recipients()->count();
- $sent = $msg->recipients()->where('status', 'sent')->count();
- $failed = $msg->recipients()->where('status', 'failed')->count();
- $newStatus = 'draft';
- if ($total === 0) {
- $newStatus = 'draft';
- } elseif ($sent === $total) {
- $newStatus = 'sent';
- } elseif ($sent > 0 && $failed > 0) {
- $newStatus = 'partial';
- } else {
- $newStatus = 'failed';
- }
- $msg->update([
- 'status' => $newStatus,
- 'sent_at' => $sent > 0 ? now() : $msg->sent_at,
- ]);
- }
- public function sms_send(array $params, bool $backup = false)
- {
- if (!isset($params['format'])) {
- $params['format'] = 'json';
- }
- $url = $backup
- ? 'https://api2.smsapi.com/sms.do'
- : 'https://api.smsapi.com/sms.do';
- $ch = curl_init($url);
- curl_setopt_array($ch, [
- CURLOPT_POST => true,
- CURLOPT_POSTFIELDS => $params,
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_HTTPHEADER => [
- 'Authorization: Bearer ' . env('SMS_TOKEN'),
- ],
- CURLOPT_TIMEOUT => 15,
- CURLOPT_CONNECTTIMEOUT => 5,
- ]);
- $content = curl_exec($ch);
- $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- $curlError = curl_error($ch);
- curl_close($ch);
- if ($content === false) {
- if (!$backup) {
- return $this->sms_send($params, true);
- }
- throw new RuntimeException('SMS API cURL error: ' . $curlError);
- }
- if ($httpStatus !== 200) {
- if (!$backup && $httpStatus >= 500 && $httpStatus < 600) {
- return $this->sms_send($params, true);
- }
- throw new RuntimeException("SMS API HTTP {$httpStatus}: {$content}");
- }
- $data = json_decode($content, true);
- if (json_last_error() !== JSON_ERROR_NONE) {
- throw new RuntimeException('SMS API invalid JSON response: ' . $content);
- }
- if (isset($data['error'])) {
- $msg = is_array($data['error'])
- ? ($data['error']['message'] ?? json_encode($data['error']))
- : $data['error'];
- throw new RuntimeException('SMS API error: ' . $msg);
- }
- if (isset($data['list'][0]['status'])) {
- $status = strtoupper($data['list'][0]['status']);
- if (in_array($status, ['ERROR', 'FAILED', 'REJECTED'], true)) {
- $errMsg = $data['list'][0]['error_message'] ?? 'Unknown SMS API error';
- throw new RuntimeException("SMS API message error ({$status}): {$errMsg}");
- }
- }
- return $data;
- }
- }
|