如何在PHP中获取FCM推送失败Token并更新数据库状态
问题描述
使用fmcSendToServerAction函数向Firebase发送推送通知,收到FCM响应如下:
{"multicast_id":3518989135591430380,"success":1,"failure":2,"canonical_ids":0,"results":[{"error":"NotRegistered"},{"error":"NotRegistered"},{"message_id":"48ccfe8f-b449-491a-b912-fe9cc86ab98e"}]}
已将用户同意接收通知时生成的Token存储在数据库中(ID为37和38的Token推送失败),需要获取这些失败的Token并更新数据库中的激活状态。相关代码如下:
/** * * @Route("/fcm/send", name="fmc_send_to_server") * @Method("GET") * @Template(engine="php") */ public function fmcSendToServerAction(Request $request) { $em = $this->getDoctrine()->getManager(); $fcmTokens = $em->getRepository('VlanceBaseBundle:FcmToken')->findAll(); $registrationIds = array_map(function ($ft) { return $ft->getToken(); }, $fcmTokens); $fcmMessages = $em->getRepository('VlanceBaseBundle:FcmNotifyPush')->getFcmNotifyPush(); $url = "https://fcm.googleapis.com/fcm/send"; $server_key = "SERVER_MY_KEY"; if (count($fcmMessages) <= 0) { return new Response('No notifications to send to users', 200); } foreach ($fcmMessages as $message) { $messageData = [ 'data' => [ 'title' => $message->getTitle(), 'body' => $message->getDiscription(), 'click_action' => $message->getUrl() ], 'registration_ids' => $registrationIds, ]; $options = [ CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . $server_key, "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode($messageData), CURLOPT_SSL_VERIFYPEER => false, CURLOPT_RETURNTRANSFER => true, // Capture the response ]; $curl = curl_init(); curl_setopt_array($curl, $options); $response = curl_exec($curl); $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); // Get HTTP response code curl_close($curl); } return new Response('All notifications have been sent to users', 200); }
解决方案
要实现获取失败Token并更新数据库的需求,可按以下步骤修改代码:
1. 保留Token与数据库实体的关联
原代码仅提取了Token字符串,丢失了对应的FcmToken实体,无法直接关联到数据库记录。需调整逻辑,建立Token到实体的映射:
// 替换原有的$fcmTokens和$registrationIds初始化部分 $em = $this->getDoctrine()->getManager(); $fcmTokens = $em->getRepository('VlanceBaseBundle:FcmToken')->findAll(); $tokenToEntityMap = []; $registrationIds = []; foreach ($fcmTokens as $ft) { $token = $ft->getToken(); $registrationIds[] = $token; $tokenToEntityMap[$token] = $ft; }
2. 解析FCM响应并处理失败Token
在获取FCM响应后,解析结果并筛选出NotRegistered的失败项,对应到数据库实体更新状态:
// 在curl_close($curl)后添加以下代码 if ($httpCode === 200 && !empty($response)) { $fcmResponse = json_decode($response, true); if (isset($fcmResponse['results']) && is_array($fcmResponse['results'])) { foreach ($fcmResponse['results'] as $index => $result) { // 筛选出未注册的失败Token if (isset($result['error']) && $result['error'] === 'NotRegistered') { $failedToken = $registrationIds[$index]; // 通过映射找到对应的数据库实体 if (isset($tokenToEntityMap[$failedToken])) { $tokenEntity = $tokenToEntityMap[$failedToken]; // 更新激活状态(根据你的实体字段调整,这里假设字段为isActive) $tokenEntity->setIsActive(false); $em->persist($tokenEntity); } } } // 批量提交数据库更新 $em->flush(); } }
3. 额外注意事项
- 确保
FcmToken实体包含激活状态字段(如isActive),若没有需先添加字段并同步数据库表结构。 - 若同一批Token需发送多条消息,建议仅在最后一次发送完成后统一处理失败Token,避免重复更新。
- 可添加日志记录失败的Token信息,方便后续排查问题。
内容的提问来源于stack exchange,提问作者zenke
相关产品推荐
相关产品推荐

