本文目录导读:

我将为您详细介绍如何在Symfony项目中集成Twilio实现短信发送功能。
安装依赖
composer require twilio/sdk
配置Twilio参数
在 .env 文件中添加配置:
TWILIO_ACCOUNT_SID=your_account_sid TWILIO_AUTH_TOKEN=your_auth_token TWILIO_FROM_NUMBER=+1234567890
创建Twilio配置服务
// config/services.yaml
services:
App\Service\TwilioService:
arguments:
$accountSid: '%env(TWILIO_ACCOUNT_SID)%'
$authToken: '%env(TWILIO_AUTH_TOKEN)%'
$fromNumber: '%env(TWILIO_FROM_NUMBER)%'
创建SMS服务类
// src/Service/TwilioService.php
namespace App\Service;
use Twilio\Rest\Client;
use Psr\Log\LoggerInterface;
class TwilioService
{
private Client $client;
private string $fromNumber;
private LoggerInterface $logger;
public function __construct(
string $accountSid,
string $authToken,
string $fromNumber,
LoggerInterface $logger
) {
$this->client = new Client($accountSid, $authToken);
$this->fromNumber = $fromNumber;
$this->logger = $logger;
}
/**
* 发送短信
*/
public function sendSms(string $to, string $message, array $options = []): array
{
try {
$sms = $this->client->messages->create(
$to,
array_merge([
'from' => $this->fromNumber,
'body' => $message,
], $options)
);
$this->logger->info('SMS sent successfully', [
'to' => $to,
'sid' => $sms->sid,
'status' => $sms->status
]);
return [
'success' => true,
'sid' => $sms->sid,
'status' => $sms->status,
'message' => 'SMS sent successfully'
];
} catch (\Exception $e) {
$this->logger->error('Failed to send SMS', [
'to' => $to,
'error' => $e->getMessage()
]);
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* 发送验证码
*/
public function sendVerificationCode(string $to, string $code): array
{
$message = sprintf(
'您的验证码是: %s,有效期为5分钟。',
$code
);
return $this->sendSms($to, $message);
}
/**
* 批量发送短信
*/
public function sendBulkSms(array $recipients, string $message): array
{
$results = [];
foreach ($recipients as $recipient) {
$results[] = $this->sendSms($recipient, $message);
}
return $results;
}
/**
* 获取短信状态
*/
public function getMessageStatus(string $sid): ?string
{
try {
$message = $this->client->messages($sid)->fetch();
return $message->status;
} catch (\Exception $e) {
$this->logger->error('Failed to get message status', [
'sid' => $sid,
'error' => $e->getMessage()
]);
return null;
}
}
}
创建Form类型
// src/Form/SmsType.php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TelType;
use Symfony\Component\Validator\Constraints as Assert;
class SmsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('phoneNumber', TelType::class, [
'label' => '手机号码',
'constraints' => [
new Assert\NotBlank(['message' => '请填写手机号码']),
new Assert\Regex([
'pattern' => '/^\+?[1-9]\d{1,14}$/',
'message' => '请输入有效的手机号码(包含国家代码)'
])
]
])
->add('message', TextareaType::class, [
'label' => '短信内容',
'constraints' => [
new Assert\NotBlank(['message' => '请填写短信内容']),
new Assert\Length([
'max' => 160,
'maxMessage' => '短信内容不能超过{{ limit }}个字符'
])
]
])
->add('verificationCode', TextType::class, [
'label' => '验证码(可选)',
'required' => false,
'constraints' => [
new Assert\Length([
'min' => 6,
'max' => 6,
'exactMessage' => '验证码必须为6位数字'
])
]
]);
}
}
创建Controller
// src/Controller/SmsController.php
namespace App\Controller;
use App\Service\TwilioService;
use App\Form\SmsType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route('/sms')]
#[IsGranted('ROLE_USER')]
class SmsController extends AbstractController
{
public function __construct(
private TwilioService $twilioService
) {}
#[Route('/send', name: 'sms_send')]
public function send(Request $request): Response
{
$result = null;
$form = $this->createForm(SmsType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
if ($data['verificationCode']) {
$result = $this->twilioService->sendVerificationCode(
$data['phoneNumber'],
$data['verificationCode']
);
} else {
$result = $this->twilioService->sendSms(
$data['phoneNumber'],
$data['message']
);
}
if ($result['success']) {
$this->addFlash('success', '短信发送成功!SID: ' . $result['sid']);
} else {
$this->addFlash('error', '短信发送失败:' . $result['error']);
}
return $this->redirectToRoute('sms_send');
}
return $this->render('sms/send.html.twig', [
'form' => $form->createView(),
'result' => $result
]);
}
#[Route('/status/{sid}', name: 'sms_status')]
public function status(string $sid): Response
{
$status = $this->twilioService->getMessageStatus($sid);
return $this->json([
'sid' => $sid,
'status' => $status
]);
}
#[Route('/send-bulk', name: 'sms_send_bulk')]
public function sendBulk(Request $request): Response
{
if ($request->isMethod('POST')) {
$recipients = $request->request->all('recipients');
$message = $request->request->get('message');
$results = $this->twilioService->sendBulkSms($recipients, $message);
$successCount = count(array_filter($results, fn($r) => $r['success']));
$this->addFlash('success', "成功发送 {$successCount}/" . count($results) . " 条短信");
return $this->redirectToRoute('sms_send_bulk');
}
return $this->render('sms/send_bulk.html.twig');
}
}
创建模板
{# templates/sms/send.html.twig #}
{% extends 'base.html.twig' %}
{% block title %}发送短信{% endblock %}
{% block body %}
<div class="container mt-4">
<h1>发送短信</h1>
{% for message in app.flashes('success') %}
<div class="alert alert-success">{{ message }}</div>
{% endfor %}
{% for message in app.flashes('error') %}
<div class="alert alert-danger">{{ message }}</div>
{% endfor %}
{{ form_start(form, {'attr': {'class': 'needs-validation'}}) }}
<div class="mb-3">
{{ form_label(form.phoneNumber, null, {'label_attr': {'class': 'form-label'}}) }}
{{ form_widget(form.phoneNumber, {'attr': {'class': 'form-control'}}) }}
{{ form_errors(form.phoneNumber) }}
</div>
<div class="mb-3">
{{ form_label(form.message, null, {'label_attr': {'class': 'form-label'}}) }}
{{ form_widget(form.message, {'attr': {'class': 'form-control', 'rows': 3}}) }}
{{ form_errors(form.message) }}
</div>
<div class="mb-3">
{{ form_label(form.verificationCode, null, {'label_attr': {'class': 'form-label'}}) }}
{{ form_widget(form.verificationCode, {'attr': {'class': 'form-control'}}) }}
<small class="form-text text-muted">如果需要发送验证码,请填写6位数字</small>
{{ form_errors(form.verificationCode) }}
</div>
<button type="submit" class="btn btn-primary">发送短信</button>
{{ form_end(form) }}
</div>
{% endblock %}
创建验证码生成器
// src/Service/VerificationCodeGenerator.php
namespace App\Service;
class VerificationCodeGenerator
{
public function generate(int $length = 6): string
{
$code = '';
for ($i = 0; $i < $length; $i++) {
$code .= random_int(0, 9);
}
return $code;
}
public function store(string $phoneNumber, string $code): void
{
// 存储验证码到缓存或数据库
// 例如使用Redis或Symfony Cache组件
// 示例:使用文件缓存(生产环境应使用Redis等)
$cacheFile = sprintf('/tmp/sms_verification_%s.json', md5($phoneNumber));
file_put_contents($cacheFile, json_encode([
'code' => $code,
'expires_at' => time() + 300 // 5分钟有效期
]));
}
public function verify(string $phoneNumber, string $code): bool
{
$cacheFile = sprintf('/tmp/sms_verification_%s.json', md5($phoneNumber));
if (!file_exists($cacheFile)) {
return false;
}
$data = json_decode(file_get_contents($cacheFile), true);
if ($data['expires_at'] < time()) {
unlink($cacheFile);
return false;
}
return $data['code'] === $code;
}
}
创建异步发送(可选)
// src/Message/SmsNotification.php
namespace App\Message;
class SmsNotification
{
public function __construct(
private string $phoneNumber,
private string $message
) {}
public function getPhoneNumber(): string
{
return $this->phoneNumber;
}
public function getMessage(): string
{
return $this->message;
}
}
// src/MessageHandler/SmsNotificationHandler.php
namespace App\MessageHandler;
use App\Message\SmsNotification;
use App\Service\TwilioService;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]
class SmsNotificationHandler
{
public function __construct(
private TwilioService $twilioService
) {}
public function __invoke(SmsNotification $message): void
{
$this->twilioService->sendSms(
$message->getPhoneNumber(),
$message->getMessage()
);
}
}
使用示例
// 在Controller中使用
class SomeController extends AbstractController
{
public function __construct(
private TwilioService $twilioService,
private VerificationCodeGenerator $codeGenerator
) {}
public function sendVerification(Request $request): Response
{
$phoneNumber = $request->get('phone');
$code = $this->codeGenerator->generate();
// 存储验证码
$this->codeGenerator->store($phoneNumber, $code);
// 发送短信
$result = $this->twilioService->sendVerificationCode($phoneNumber, $code);
if ($result['success']) {
return $this->json(['message' => '验证码已发送']);
}
return $this->json(['error' => '发送失败'], 500);
}
}
注意事项
- 安全: 妥善保管Twilio凭证,不要提交到版本控制
- 验证: 始终验证电话号码格式
- 限制: 设置发送频率限制,防止滥用
- 日志: 记录所有短信发送操作
- 错误处理: 妥善处理所有异常情况
- 测试: 在开发环境使用Twilio测试凭证
这样就完成了Symfony项目中的Twilio SMS集成,记得根据实际需求调整配置和功能。