本文目录导读:

我来为你详细介绍PHP项目实现用户生日祝福的几种方案。
方案概述
生日祝福功能核心流程:检测生日 → 发送祝福 → 记录状态
基础实现方案
1 数据库设计
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
email VARCHAR(100),
birthday DATE,
last_birthday_wish DATETIME,
wish_sent_today TINYINT(1) DEFAULT 0
);
2 基础检测脚本
<?php
class BirthdayWish {
private $db;
public function __construct($db) {
$this->db = $db;
}
/**
* 检测并发送生日祝福
*/
public function checkAndSendWishes() {
$today = date('m-d');
$currentYear = date('Y');
// 查询今天生日的用户
$sql = "SELECT * FROM users
WHERE DATE_FORMAT(birthday, '%m-%d') = ?
AND (last_birthday_wish IS NULL
OR DATE(last_birthday_wish) != CURDATE())";
$stmt = $this->db->prepare($sql);
$stmt->execute([$today]);
$users = $stmt->fetchAll();
foreach ($users as $user) {
$this->sendBirthdayWish($user);
}
}
/**
* 发送祝福
*/
private function sendBirthdayWish($user) {
// 计算年龄
$age = date('Y') - date('Y', strtotime($user['birthday']));
// 准备祝福内容
$message = "亲爱的{$user['username']},祝你{$age}岁生日快乐!";
// 发送方式:邮件
$this->sendEmail($user['email'], '生日祝福', $message);
// 更新发送记录
$this->updateWishRecord($user['id']);
}
/**
* 更新祝福记录
*/
private function updateWishRecord($userId) {
$sql = "UPDATE users
SET last_birthday_wish = NOW(),
wish_sent_today = 1
WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId]);
}
}
多种发送方式
1 邮件发送
<?php
use PHPMailer\PHPMailer\PHPMailer;
class EmailSender {
public function sendBirthdayEmail($to, $name, $age) {
$mail = new PHPMailer(true);
try {
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = 'your@email.com';
$mail->Password = 'your-password';
$mail->SMTPSecure = 'tls';
$mail->Port = 587;
$mail->setFrom('noreply@yourdomain.com', '生日祝福');
$mail->addAddress($to, $name);
$mail->Subject = '🎂 生日快乐!';
// HTML模板
$mail->isHTML(true);
$mail->Body = "
<div style='max-width:600px;margin:0 auto;padding:20px;text-align:center;'>
<h1>🎉 生日快乐!</h1>
<p>亲爱的 {$name}:</p>
<p>今天是你的{$age}岁生日,</p>
<p>祝你生日快乐,万事如意!</p>
<div style='font-size:48px;'>🎂🎁🎊</div>
</div>
";
$mail->send();
return true;
} catch (Exception $e) {
error_log("邮件发送失败: " . $mail->ErrorInfo);
return false;
}
}
}
2 短信发送(使用阿里云)
<?php
use AlibabaCloud\Client\AlibabaCloud;
class SMSSender {
public function sendBirthdaySMS($phone, $name) {
AlibabaCloud::accessKeyClient('your-access-key', 'your-access-secret')
->regionId('cn-hangzhou')
->asDefaultClient();
try {
$result = AlibabaCloud::rpc()
->product('Dysmsapi')
->version('2017-05-25')
->action('SendSms')
->method('POST')
->host('dysmsapi.aliyuncs.com')
->options([
'query' => [
'PhoneNumbers' => $phone,
'SignName' => '你的签名',
'TemplateCode' => 'SMS_123456789',
'TemplateParam' => json_encode([
'name' => $name
])
]
])
->request();
return $result->toArray();
} catch (Exception $e) {
error_log("短信发送失败: " . $e->getMessage());
return false;
}
}
}
定时任务实现
1 Linux Crontab
# 每天早上8点执行 0 8 * * * /usr/bin/php /path/to/birthday_wish.php # 每小时执行一次 0 * * * * /usr/bin/php /path/to/birthday_wish.php
2 完整的定时任务脚本
#!/usr/bin/php
<?php
// birthday_wish.php - 定时任务入口
require_once 'config/database.php';
require_once 'vendor/autoload.php';
class BirthdayWishCron {
private $birthdayWish;
private $emailSender;
public function __construct() {
$db = new PDO("mysql:host=localhost;dbname=test", "root", "");
$this->birthdayWish = new BirthdayWish($db);
$this->emailSender = new EmailSender();
}
public function execute() {
echo "[" . date('Y-m-d H:i:s') . "] 开始检测生日用户...\n";
$today = date('m-d');
$db = $this->getDb();
// 查询今天生日的用户
$stmt = $db->prepare("
SELECT * FROM users
WHERE DATE_FORMAT(birthday, '%m-%d') = ?
AND (last_birthday_wish IS NULL
OR DATE(last_birthday_wish) != CURDATE())
");
$stmt->execute([$today]);
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo "发现 " . count($users) . " 位生日用户\n";
foreach ($users as $user) {
$this->processUser($user);
}
echo "[" . date('Y-m-d H:i:s') . "] 处理完成\n";
}
private function processUser($user) {
$age = date('Y') - date('Y', strtotime($user['birthday']));
echo "发送祝福给: {$user['username']} ({$age}岁)\n";
// 发送邮件
$emailResult = $this->emailSender->sendBirthdayEmail(
$user['email'],
$user['username'],
$age
);
if ($emailResult) {
echo "✓ 邮件发送成功\n";
$this->updateWishRecord($user['id']);
} else {
echo "✗ 邮件发送失败\n";
}
}
}
// 执行
$cron = new BirthdayWishCron();
$cron->execute();
高级功能实现
1 个性化祝福模板
<?php
class BirthdayTemplate {
private $templates = [
'friend' => "亲爱的{name},{age}岁生日快乐!愿你永远年轻,永远热泪盈眶!",
'colleague' => "尊敬的{name},祝您{age}岁生日快乐,工作顺利,家庭幸福!",
'vip' => "尊贵的VIP用户{name},感谢您的一路相伴,祝您{age}岁生日快乐!我们还为您准备了专属优惠券:{coupon}"
];
public function getPersonalizedWish($user) {
$template = $this->templates[$user['type']] ?? $this->templates['friend'];
$replacements = [
'{name}' => $user['username'],
'{age}' => $this->calculateAge($user['birthday']),
'{coupon}' => $this->generateCoupon($user['id'])
];
return str_replace(array_keys($replacements), $replacements, $template);
}
private function calculateAge($birthday) {
$birth = new DateTime($birthday);
$now = new DateTime();
return $birth->diff($now)->y;
}
private function generateCoupon($userId) {
return "BIRTHDAY" . date('Ymd') . $userId;
}
}
2 批量发送优化
<?php
class BatchBirthdaySender {
private $messageQueue = [];
private $maxBatchSize = 50;
public function addToQueue($user, $message) {
$this->messageQueue[] = [
'user' => $user,
'message' => $message
];
if (count($this->messageQueue) >= $this->maxBatchSize) {
$this->flushQueue();
}
}
public function flushQueue() {
if (empty($this->messageQueue)) {
return;
}
// 批量插入发送记录
$this->batchInsertRecords($this->messageQueue);
// 批量发送邮件(使用队列系统)
foreach ($this->messageQueue as $item) {
// 推送到消息队列
Queue::push('sendEmail', $item);
}
$this->messageQueue = [];
}
private function batchInsertRecords($records) {
$sql = "INSERT INTO birthday_wish_log (user_id, sent_at, status) VALUES ";
$values = [];
$params = [];
foreach ($records as $index => $record) {
$values[] = "(?, NOW(), 'pending')";
$params[] = $record['user']['id'];
}
$sql .= implode(', ', $values);
// 执行批量插入
}
}
最佳实践建议
1 时区处理
date_default_timezone_set('Asia/Shanghai');
2 防重复机制
// 使用Redis防止重复发送
$redisKey = "birthday:send:{$userId}:" . date('Ymd');
if ($redis->exists($redisKey)) {
return; // 今天已发送
}
// 发送逻辑...
$redis->setex($redisKey, 86400, 1);
3 异常处理
try {
// 发送逻辑
} catch (Exception $e) {
// 记录日志
error_log("生日祝福发送失败: " . $e->getMessage());
// 重试机制
$retryCount = 0;
while ($retryCount < 3) {
if ($this->retrySend($user)) {
break;
}
$retryCount++;
sleep(5);
}
}
部署建议
- 使用消息队列:Redis、RabbitMQ处理大量发送请求
- 日志记录:记录每次发送的状态便于排查
- 监控告警:设置发送失败告警
- 限流控制:避免短时间内大量发送被封
- 用户隐私:注意用户隐私保护,提供退订功能
这个方案可以根据项目规模灵活调整,从小型项目到大型系统都可以适用。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播