php实现签到功能实现
数据库设计
创建签到记录表,包含用户ID、签到日期、连续签到天数等字段。表结构示例:
CREATE TABLE `sign_in_records` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`sign_date` date NOT NULL,
`continuous_days` int(11) DEFAULT 1,
PRIMARY KEY (`id`),
UNIQUE KEY `user_date` (`user_id`,`sign_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
签到逻辑实现
检查用户今日是否已签到,未签到则插入记录并更新连续签到天数:
function signIn($userId) {
$today = date('Y-m-d');
$pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
// 检查今日是否已签到
$stmt = $pdo->prepare("SELECT * FROM sign_in_records WHERE user_id = ? AND sign_date = ?");
$stmt->execute([$userId, $today]);
if ($stmt->fetch()) {
return ['status' => 0, 'message' => '今日已签到'];
}
// 获取昨日签到记录
$yesterday = date('Y-m-d', strtotime('-1 day'));
$stmt = $pdo->prepare("SELECT continuous_days FROM sign_in_records WHERE user_id = ? AND sign_date = ?");
$stmt->execute([$userId, $yesterday]);
$lastRecord = $stmt->fetch();
// 计算连续签到天数
$continuousDays = $lastRecord ? $lastRecord['continuous_days'] + 1 : 1;
// 插入签到记录
$stmt = $pdo->prepare("INSERT INTO sign_in_records (user_id, sign_date, continuous_days) VALUES (?, ?, ?)");
$stmt->execute([$userId, $today, $continuousDays]);
return ['status' => 1, 'continuous_days' => $continuousDays];
}
奖励机制
根据连续签到天数发放不同奖励,可在签到成功后调用:
function giveReward($userId, $continuousDays) {
$rewards = [
3 => ['points' => 10],
7 => ['points' => 30, 'vip_days' => 1],
30 => ['points' => 100, 'vip_days' => 7]
];
if (isset($rewards[$continuousDays])) {
// 发放对应奖励
$reward = $rewards[$continuousDays];
// 更新用户积分、VIP天数等
// ...
return $reward;
}
return null;
}
签到统计
获取用户签到历史记录和统计信息:
function getSignStats($userId) {
$pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
// 当月签到记录
$stmt = $pdo->prepare("SELECT sign_date FROM sign_in_records
WHERE user_id = ? AND sign_date >= ?");
$firstDay = date('Y-m-01');
$stmt->execute([$userId, $firstDay]);
$records = $stmt->fetchAll(PDO::FETCH_COLUMN);
// 连续签到天数
$stmt = $pdo->prepare("SELECT continuous_days FROM sign_in_records
WHERE user_id = ? ORDER BY sign_date DESC LIMIT 1");
$stmt->execute([$userId]);
$currentContinuous = $stmt->fetchColumn();
return [
'month_records' => $records,
'continuous_days' => $currentContinuous ?: 0
];
}
前端展示
创建日历形式展示签到状态,标记已签到日期:

<div class="calendar">
<?php
$stats = getSignStats($userId);
$currentMonth = date('m');
$daysInMonth = cal_days_in_month(CAL_GREGORIAN, $currentMonth, date('Y'));
for ($day = 1; $day <= $daysInMonth; $day++) {
$date = date('Y-m-') . str_pad($day, 2, '0', STR_PAD_LEFT);
$signed = in_array($date, $stats['month_records']) ? 'signed' : '';
echo "<div class='day {$signed}'>$day</div>";
}
?>
</div>
安全考虑
- 对用户输入进行验证和过滤
- 使用预处理语句防止SQL注入
- 重要操作记录日志
- 接口添加频率限制防止刷签到
性能优化
- 为常用查询字段添加索引
- 对活跃用户签到数据缓存
- 批量处理奖励发放
- 考虑使用Redis记录临时签到状态






