基于MySQLi Multi_Query的PHP API接收JSON发送FCM推送遇异常
实现PHP API向Android用户发送推送通知的完整方案
我来帮你一步步拆解需求,从接收JSON数据到最终发送FCM推送,同时避开常见的坑:
1. 接收并验证请求的JSON数据
首先得确保API能正确接收前端传来的JSON,还要验证必填字段是否存在,避免后续逻辑出错:
// 接收JSON请求体 $input = file_get_contents('php://input'); $data = json_decode($input, true); // 验证必填字段:手机号、状态、用户ID if (!isset($data['phone_number'], $data['status'], $data['user_id'])) { http_response_code(400); echo json_encode(['error' => '缺少必填参数:phone_number、status、user_id']); exit; } $phoneNumber = $data['phone_number']; $status = $data['status']; $userId = $data['user_id'];
2. 从数据库关联获取FCM令牌
接下来要通过number_list表找到对应手机号所属的用户(这里你传了user_id,也可以做双重验证),再从user表拿到有效的FCM令牌:
// 假设你用PDO连接数据库(推荐用PDO避免SQL注入) $dbHost = '你的数据库地址'; $dbName = '数据库名'; $dbUser = '用户名'; $dbPass = '密码'; try { $pdo = new PDO("mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4", $dbUser, $dbPass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 关联两张表查询,确保手机号和user_id匹配,且用户开启了FCM $stmt = $pdo->prepare(" SELECT u.fcm, u.fcm_enabled FROM number_list nl JOIN user u ON nl.user_id = u.id WHERE nl.number = :phone AND nl.user_id = :user_id "); $stmt->bindParam(':phone', $phoneNumber); $stmt->bindParam(':user_id', $userId); $stmt->execute(); $userInfo = $stmt->fetch(PDO::FETCH_ASSOC); if (!$userInfo) { http_response_code(404); echo json_encode(['error' => '未找到对应手机号的用户记录']); exit; } // 检查用户是否开启FCM推送 if (!$userInfo['fcm_enabled']) { http_response_code(403); echo json_encode(['error' => '该用户未开启推送通知']); exit; } $fcmToken = $userInfo['fcm']; if (empty($fcmToken)) { http_response_code(400); echo json_encode(['error' => '该用户的FCM令牌为空']); exit; } } catch (PDOException $e) { http_response_code(500); echo json_encode(['error' => '数据库查询失败:' . $e->getMessage()]); exit; }
3. 调用FCM API发送推送通知
现在拿到有效的FCM令牌,就可以根据status字段定制通知内容,调用FCM的HTTP API发送推送:
// FCM服务器密钥(从Firebase控制台获取) $fcmServerKey = '你的FCM服务器密钥'; // 根据状态定制通知内容 switch ($status) { case 'active': $notificationTitle = '手机号状态更新'; $notificationBody = '你的手机号已激活,可以正常使用啦!'; break; case 'inactive': $notificationTitle = '手机号状态提醒'; $notificationBody = '你的手机号已暂停使用,请及时处理'; break; // 可以添加更多状态的处理逻辑 default: $notificationTitle = '状态更新'; $notificationBody = '你的手机号状态已变更为:' . $status; break; } // 构造FCM请求体 $fcmPayload = [ 'to' => $fcmToken, 'notification' => [ 'title' => $notificationTitle, 'body' => $notificationBody, 'sound' => 'default' // 可选:播放默认通知音 ], 'data' => [ 'phone_number' => $phoneNumber, 'status' => $status, 'user_id' => $userId // 可以添加更多自定义数据,供Android客户端处理 ] ]; // 发送请求到FCM API $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: key=' . $fcmServerKey, 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fcmPayload)); $fcmResponse = curl_exec($ch); $curlError = curl_error($ch); curl_close($ch); if ($curlError) { http_response_code(500); echo json_encode(['error' => 'FCM请求失败:' . $curlError]); exit; } // 解析FCM响应,判断是否发送成功 $fcmResponseData = json_decode($fcmResponse, true); if (isset($fcmResponseData['failure']) && $fcmResponseData['failure'] > 0) { http_response_code(500); echo json_encode(['error' => '推送发送失败:' . json_encode($fcmResponseData['results'])]); } else { echo json_encode(['success' => true, 'message' => '推送通知已成功发送']); }
常见异常排查要点
- SQL注入风险:一定要用预处理语句(PDO或MySQLi的prepare),不要直接拼接SQL字符串
- FCM令牌有效性:如果FCM返回
InvalidRegistration错误,说明令牌无效,需要提醒用户重新登录获取新令牌 - 数据库关联错误:确保
number_list表的user_id和user表的id是正确关联的,避免查询不到数据 - 请求头设置:FCM API要求必须带
Authorization和Content-Type头,缺一不可
内容的提问来源于stack exchange,提问作者Khushi Patel
相关产品推荐
相关产品推荐

