我来为您设计一个PHP统一通知接口,这是一个常见的需求,用于接收来自不同渠道(短信、邮件、App推送等)的通知。

统一通知接口设计方案
数据表结构
-- 通知数据表
CREATE TABLE `notifications` (
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`notification_id` VARCHAR(64) NOT NULL COMMENT '业务通知ID',
`channel` VARCHAR(20) NOT NULL COMMENT '渠道: sms,email,push',
`type` VARCHAR(50) NOT NULL COMMENT '通知类型', VARCHAR(200) DEFAULT NULL COMMENT '标题',
`content` TEXT NOT NULL COMMENT '内容',
`receiver` JSON NOT NULL COMMENT '接收者信息',
`data` JSON DEFAULT NULL COMMENT '扩展数据',
`status` TINYINT DEFAULT 0 COMMENT '状态: 0待发送,1已发送,2失败,3已读',
`send_result` JSON DEFAULT NULL COMMENT '发送结果',
`sent_at` DATETIME DEFAULT NULL COMMENT '发送时间',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX `idx_notification_id` (`notification_id`),
INDEX `idx_channel_status` (`channel`, `status`),
INDEX `idx_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
统一通知接口
<?php
/**
* 统一通知接口
*
* @author Your Name
* @date 2024-01-01
*/
require_once 'database.php'; // 数据库连接
class UnifiedNotification {
private $db;
private $channels = [
'sms' => 'SmsChannel',
'email' => 'EmailChannel',
'push' => 'PushChannel',
'wechat' => 'WechatChannel'
];
public function __construct($db) {
$this->db = $db;
}
/**
* 统一发送通知接口
*
* @param array $params 通知参数
* @return array 发送结果
*/
public function send($params) {
try {
// 参数验证
$this->validateParams($params);
// 构建通知数据
$notification = [
'notification_id' => $this->generateNotificationId(),
'channel' => $params['channel'],
'type' => $params['type'],
'title' => $params['title'] ?? '',
'content' => $params['content'],
'receiver' => json_encode($params['receiver']),
'data' => json_encode($params['data'] ?? []),
'status' => 0
];
// 保存到数据库
$notificationId = $this->saveNotification($notification);
// 发送通知
$result = $this->dispatch($notification);
// 更新发送状态
$this->updateNotificationStatus($notificationId, $result);
return [
'code' => 200,
'message' => '通知发送成功',
'data' => [
'notification_id' => $notification['notification_id'],
'channel' => $params['channel'],
'status' => $result['status'],
'send_result' => $result
]
];
} catch (Exception $e) {
return [
'code' => 400,
'message' => $e->getMessage(),
'data' => null
];
}
}
/**
* 批量发送通知
*/
public function sendBatch($params) {
$results = [];
foreach ($params['notifications'] as $notification) {
$results[] = $this->send($notification);
}
return [
'code' => 200,
'message' => '批量发送完成',
'data' => $results
];
}
/**
* 验证参数
*/
private function validateParams($params) {
// 必填参数检查
$required = ['channel', 'type', 'content', 'receiver'];
foreach ($required as $field) {
if (empty($params[$field])) {
throw new Exception("参数 {$field} 不能为空");
}
}
// 渠道检查
if (!isset($this->channels[$params['channel']])) {
throw new Exception("不支持的渠道: {$params['channel']}");
}
// 接收者检查
if (!is_array($params['receiver']) || empty($params['receiver'])) {
throw new Exception("接收者信息不能为空");
}
}
/**
* 生成通知ID
*/
private function generateNotificationId() {
return date('YmdHis') . str_pad(mt_rand(1, 999999), 6, '0', STR_PAD_LEFT);
}
/**
* 保存通知到数据库
*/
private function saveNotification($data) {
$sql = "INSERT INTO notifications (notification_id, channel, type, title, content, receiver, data, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
$stmt = $this->db->prepare($sql);
$stmt->execute([
$data['notification_id'],
$data['channel'],
$data['type'],
$data['title'],
$data['content'],
$data['receiver'],
$data['data'],
$data['status']
]);
return $this->db->lastInsertId();
}
/**
* 分发到具体渠道
*/
private function dispatch($notification) {
$channelClass = $this->channels[$notification['channel']];
if (!class_exists($channelClass)) {
throw new Exception("渠道类不存在: {$channelClass}");
}
$channel = new $channelClass();
// 构建渠道数据
$channelData = [
'notification_id' => $notification['notification_id'],
'title' => $notification['title'],
'content' => $notification['content'],
'receiver' => json_decode($notification['receiver'], true),
'data' => json_decode($notification['data'], true)
];
return $channel->send($channelData);
}
/**
* 更新通知状态
*/
private function updateNotificationStatus($id, $result) {
$status = $result['status'] === 'success' ? 1 : 2;
$sql = "UPDATE notifications SET status = ?, send_result = ?, sent_at = NOW() WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([
$status,
json_encode($result),
$id
]);
}
/**
* 查询通知状态
*/
public function query($notificationId) {
$sql = "SELECT * FROM notifications WHERE notification_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$notificationId]);
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$data) {
return [
'code' => 404,
'message' => '通知不存在',
'data' => null
];
}
$data['receiver'] = json_decode($data['receiver'], true);
$data['data'] = json_decode($data['data'], true);
$data['send_result'] = json_decode($data['send_result'], true);
return [
'code' => 200,
'message' => '查询成功',
'data' => $data
];
}
}
渠道实现类
<?php
/**
* 短信渠道
*/
class SmsChannel {
public function send($data) {
// 实现短信发送逻辑
// 例如使用阿里云短信服务
try {
// 模拟发送
$result = [
'status' => 'success',
'message' => '短信发送成功',
'message_id' => 'MSG' . time(),
'channel' => 'sms'
];
// 实际调用短信SDK
// $smsService = new AliyunSms();
// $result = $smsService->send($data);
return $result;
} catch (Exception $e) {
return [
'status' => 'failed',
'message' => $e->getMessage(),
'channel' => 'sms'
];
}
}
}
/**
* 邮件渠道
*/
class EmailChannel {
public function send($data) {
// 实现邮件发送逻辑
try {
// 模拟发送
$result = [
'status' => 'success',
'message' => '邮件发送成功',
'message_id' => 'EMAIL' . time(),
'channel' => 'email'
];
// 实际发送邮件代码
// $mailer = new Mailer();
// $result = $mailer->send($data);
return $result;
} catch (Exception $e) {
return [
'status' => 'failed',
'message' => $e->getMessage(),
'channel' => 'email'
];
}
}
}
/**
* 推送渠道
*/
class PushChannel {
public function send($data) {
// 实现推送逻辑
try {
$result = [
'status' => 'success',
'message' => '推送成功',
'message_id' => 'PUSH' . time(),
'channel' => 'push'
];
// 实际推送代码
// $pushService = new PushService();
// $result = $pushService->send($data);
return $result;
} catch (Exception $e) {
return [
'status' => 'failed',
'message' => $e->getMessage(),
'channel' => 'push'
];
}
}
}
HTTP接口调用示例
<?php
/**
* 统一通知接口入口文件
* api/notify.php
*/
// 设置响应头
header('Content-Type: application/json; charset=utf-8');
// 接收请求
$method = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// 解析路由
$path = parse_url($uri, PHP_URL_PATH);
$action = basename($path);
require_once 'UnifiedNotification.php';
require_once 'SmsChannel.php';
require_once 'EmailChannel.php';
require_once 'PushChannel.php';
$db = getDatabaseConnection();
$notificationService = new UnifiedNotification($db);
switch ($method) {
case 'POST':
// 发送通知
$params = json_decode(file_get_contents('php://input'), true);
if ($action === 'batch') {
$result = $notificationService->sendBatch($params);
} else {
$result = $notificationService->send($params);
}
break;
case 'GET':
// 查询通知
$notificationId = $_GET['id'] ?? '';
$result = $notificationService->query($notificationId);
break;
default:
$result = [
'code' => 405,
'message' => '不支持的请求方法',
'data' => null
];
}
echo json_encode($result, JSON_UNESCAPED_UNICODE);
调用示例
// 发送短信通知
$params = [
'channel' => 'sms',
'type' => 'verify_code', => '验证码',
'content' => '您的验证码是:123456,5分钟内有效。',
'receiver' => [
'mobile' => '13800138000'
],
'data' => [
'template_id' => 'SMS_001',
'code' => '123456'
]
];
// 发送邮件通知
$emailParams = [
'channel' => 'email',
'type' => 'order_confirmation', => '订单确认',
'content' => '您的订单已确认,订单号:12345',
'receiver' => [
'email' => 'user@example.com'
],
'data' => [
'order_id' => '12345'
]
];
配置文件
<?php
// config/notification.php
return [
// 渠道配置
'channels' => [
'sms' => [
'driver' => 'aliyun',
'access_key' => 'your_access_key',
'secret_key' => 'your_secret_key',
'sign_name' => '你的签名',
'endpoint' => 'https://dysmsapi.aliyuncs.com'
],
'email' => [
'host' => 'smtp.example.com',
'port' => 465,
'username' => 'user@example.com',
'password' => 'your_password'
],
'push' => [
'app_key' => 'your_app_key',
'master_secret' => 'your_master_secret'
]
],
// 重试配置
'retry' => [
'max_attempts' => 3,
'delay_seconds' => 60
],
// 日志配置
'logging' => [
'enabled' => true,
'path' => '/path/to/notification.log'
]
];
这个统一通知接口设计具有以下特点:
- 统一入口:所有通知都通过同一个接口发送
- 多渠道支持:支持短信、邮件、推送等多种渠道
- 异步处理:可以扩展为队列异步处理
- 状态追踪:记录每条通知的发送状态
- 可扩展性:方便添加新的渠道
- 错误处理:完善的异常处理机制
您可以根据实际需求调整渠道实现和配置。