本文目录导读:

实现PHP合同到期提醒,通常有两种模式:被动检查(用户访问时触发)和主动推送(服务器定时执行),以下是具体的实现方案和代码示例。
用户访问时触发提醒(被动模式)
适合后台管理系统,用户登录或刷新页面时检查合同。
数据库表设计
CREATE TABLE contracts (
id INT AUTO_INCREMENT,
contract_name VARCHAR(255),
end_date DATE,
remind_days INT DEFAULT 30, -- 提前多少天提醒
status TINYINT DEFAULT 1, -- 1:生效 0:已结束
PRIMARY KEY (id)
);
PHP 查询即将到期合同
<?php
// 连接数据库(使用PDO)
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
// 计算提醒日期范围:到 提醒天数
$today = date('Y-m-d');
$sql = "SELECT * FROM contracts
WHERE status = 1
AND end_date BETWEEN :today AND :remind_date
ORDER BY end_date ASC";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':today' => $today,
':remind_date' => date('Y-m-d', strtotime('+30 days')) // 提前30天
]);
$reminders = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 输出提醒
foreach ($reminders as $contract) {
echo "合同【{$contract['contract_name']}】将于 {$contract['end_date']} 到期!\n";
}
?>
在后台页面嵌入提醒逻辑
可以在后台框架的 BaseController 或公共模板中执行上述查询,并在页面顶部显示倒计时或弹窗。
定时任务主动推送(推荐)
适合需要邮件、短信或钉钉/企业微信通知,无需用户登录即可触发。
编写 PHP 脚本 remind.php
<?php
// 加载数据库连接和配置
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
// 获取所有即将到期(且未发送提醒)的合同
$sql = "SELECT * FROM contracts
WHERE status = 1
AND remind_sent = 0
AND end_date BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL remind_days DAY)";
$contracts = $pdo->query($sql)->fetchAll();
foreach ($contracts as $contract) {
// 1. 发送邮件(示例使用 mail(),实际建议 PHPMailer)
$subject = "合同到期提醒:{$contract['contract_name']}";
$message = "合同《{$contract['contract_name']}》将于 {$contract['end_date']} 到期,请及时处理。";
mail('admin@example.com', $subject, $message);
// 2. 发送短信/钉钉机器人(可接入第三方API)
// 例如使用发短信API:sms_send('13800138000', $message);
// 3. 标记已发送,避免重复提醒
$update = $pdo->prepare("UPDATE contracts SET remind_sent = 1 WHERE id = ?");
$update->execute([$contract['id']]);
}
设置 Linux 定时任务(Crontab)
# 每天早8点执行一次 0 8 * * * /usr/bin/php /path/to/remind.php >> /var/log/contract_remind.log 2>&1
扩展:支持多频次提醒
可以在数据库增加 remind_stages 字段(如:30天、7天、1天各提醒一次),每次执行时检查时间差。
集成到框架中的最佳实践
以 Laravel 为例(其他框架思路类似):
创建 Artisan 命令
php artisan make:command ContractReminder
实现 handle() 方法:
public function handle()
{
$contracts = Contract::where('status', 1)
->where('end_date', '<=', now()->addDays(30))
->where('end_date', '>=', now())
->get();
foreach ($contracts as $contract) {
// 发送通知(Laravel Notifications)
$contract->owner->notify(new ContractExpiring($contract));
}
}
配置任务调度
在 App\Console\Kernel.php 中添加:
protected function schedule(Schedule $schedule)
{
$schedule->command('contract:remind')->dailyAt('09:00');
}
然后执行 php artisan schedule:run 或设置服务器Crontab:
* * * * * cd /your-project && php artisan schedule:run >> /dev/null 2>&1
注意事项
| 问题 | 解决方案 |
|---|---|
| 时区不一致 | 数据库和PHP代码统一使用 Asia/Shanghai 时区 |
| 重复提醒 | 使用 remind_sent 字段或检查上次提醒时间戳 |
| 大量合同性能 | 使用索引(end_date, status),分页查询 |
| 通知失败 | 记录日志并在失败时重试(或使用消息队列) |
| 用户自定义提醒 | 在合同表增加 remind_days 字段,允许用户设置 |
- 简单管理后台:用方案一,在页面加载时查询即将到期合同并展示。
- 自动化通知:用方案二(定时脚本)或方案三(框架调度),结合邮件/短信/微信通知。
- 进阶需求:可使用 Redis 存储提醒状态,或使用消息队列(如 RabbitMQ)异步发送通知。
最终选择取决于你的项目规模、运维能力和通知渠道要求,如果是企业级应用,建议使用方案三(框架+定时任务)并增加失败重试和日志监控。