基于Arduino RFID的PHP每日单次考勤实现技术问询
解决RFID每日仅记录一次考勤的问题
我来帮你搞定这个每日仅打卡一次的需求,你的现有代码确实会每次扫描就插入记录,咱们得加个前置检查,顺便还得修复个严重的安全漏洞——直接把用户输入拼进SQL里太危险了!
下面是修改后的完整代码,我会逐部分给你解释:
public function getRFIDAttendanceApi() { // 1. 先安全获取并验证RFID UID,避免空值或恶意输入 $rfid_uid = isset($_REQUEST['uid']) ? trim($_REQUEST['uid']) : ''; if (empty($rfid_uid)) { // 返回清晰的错误提示,方便Arduino端处理 echo json_encode(['status' => 'error', 'message' => '无效的RFID卡号']); return; } // 2. 验证该RFID是否属于有效用户(保留原逻辑,但改用安全的预处理语句) $checkUserSql = "SELECT COUNT(*) AS tot FROM tbl_users WHERE rfid_uid = ?"; $stmt = $this->conn->prepare($checkUserSql); $stmt->bind_param("s", $rfid_uid); $stmt->execute(); $result = $stmt->get_result(); $userData = $result->fetch_assoc(); $stmt->close(); if ($userData['tot'] <= 0) { echo json_encode(['status' => 'error', 'message' => '未找到该RFID对应的用户']); return; } // 3. 核心逻辑:检查该用户今日是否已经打过卡 // 假设你的考勤表有个记录打卡时间的字段`attendance_date`,如果字段名不同请自行替换 $checkAttendanceSql = "SELECT COUNT(*) AS today_count FROM tbl_attendance WHERE rfid_uid = ? AND DATE(attendance_date) = CURDATE()"; $stmt = $this->conn->prepare($checkAttendanceSql); $stmt->bind_param("s", $rfid_uid); $stmt->execute(); $result = $stmt->get_result(); $attendanceData = $result->fetch_assoc(); $stmt->close(); if ($attendanceData['today_count'] > 0) { // 用户今日已打卡,直接返回提示,不重复插入 echo json_encode(['status' => 'info', 'message' => '今日已完成考勤记录']); return; } // 4. 今日未打卡,执行插入操作(依旧用预处理语句保证安全) $insertSql = "INSERT INTO tbl_attendance (rfid_uid, attendance_date) VALUES (?, NOW())"; $stmt = $this->conn->prepare($insertSql); $stmt->bind_param("s", $rfid_uid); $flag = $stmt->execute(); $stmt->close(); if ($flag) { echo json_encode(['status' => 'success', 'message' => '考勤记录成功']); } else { echo json_encode(['status' => 'error', 'message' => '考勤记录失败:' . $this->conn->error]); } }
关键修改点说明:
- SQL注入防护:所有SQL操作都用了预处理语句(
prepare()+bind_param()),彻底避免了恶意输入篡改SQL的风险,这是生产环境必须做的安全措施。 - 每日打卡校验:通过
DATE(attendance_date) = CURDATE()精准筛选今日的考勤记录,确保同一用户当天只能打卡一次。如果你的考勤表还没有记录时间的字段,建议添加一个attendance_date DATETIME DEFAULT CURRENT_TIMESTAMP。 - 输入合法性检查:先判断
rfid_uid是否为空,过滤无效请求。 - 友好的反馈机制:用JSON格式返回不同状态的提示,方便Arduino端根据状态触发不同的硬件反馈(比如绿灯亮表示成功,黄灯表示已打卡,红灯表示失败)。
额外小建议:
- 可以给
tbl_attendance表的rfid_uid和attendance_date字段加个联合索引,这样每日打卡检查的查询速度会更快。
内容的提问来源于stack exchange,提问作者Salman Mahmood
相关产品推荐
相关产品推荐

