如何通过PHP检测无效GCM注册令牌并从数据库删除
检测并删除失效的GCM注册令牌
其实现在GCM已经正式迁移到FCM(Firebase Cloud Messaging)了,但两者的失效令牌检测逻辑是一致的。核心思路就是捕获GCM/FCM服务器返回的推送响应,根据特定错误码识别失效令牌,然后从数据库中移除。
下面一步步给你讲具体实现:
1. 先获取推送请求的响应
你的现有代码应该是通过curl向GCM服务器发送请求,但可能没处理返回的响应。我们需要先把响应抓下来并解析成数组,这样才能判断令牌是否有效。
修改后的推送请求代码示例:
$api_key = "你的GCM/FCM API密钥"; $reg_token = array($token); // 这里可以传多个令牌,支持批量推送 $message = array( 'title' => '你的推送标题', 'body' => '你的推送内容' ); // 构造请求参数 $fields = array( 'registration_ids' => $reg_token, 'notification' => $message ); $headers = array( 'Authorization: key=' . $api_key, 'Content-Type: application/json' ); // 初始化curl $ch = curl_init(); // 注意:GCM旧地址是https://android.googleapis.com/gcm/send,建议换成FCM的官方地址https://fcm.googleapis.com/fcm/send curl_setopt($ch, CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields)); // 执行请求并获取响应 $result = curl_exec($ch); curl_close($ch); // 把JSON响应解析成关联数组 $response = json_decode($result, true);
2. 根据响应错误码识别失效令牌
GCM/FCM会在推送失败时返回对应的错误码,其中和"令牌失效/用户卸载应用"强相关的主要有两个:
NotRegistered:设备未注册(最常见于用户卸载应用后,令牌已被FCM服务器标记为无效)InvalidRegistration:注册令牌本身无效(比如格式错误、已被手动注销)
另外像MismatchSenderId这类错误,属于发送者配置问题,不属于令牌失效,不用删除,需要排查API密钥或项目配置。
3. 删除数据库中的失效令牌
解析响应里的results数组,它的顺序和你请求时registration_ids的顺序完全对应,所以可以精准匹配到对应的令牌,然后执行删除:
if (isset($response['results'])) { foreach ($response['results'] as $index => $result_item) { // 检查当前令牌是否返回错误 if (isset($result_item['error'])) { $error_code = $result_item['error']; // 判断是否是需要删除的失效令牌 if ($error_code === 'NotRegistered' || $error_code === 'InvalidRegistration') { $invalid_token = $reg_token[$index]; // 这里替换成你的数据库删除逻辑,示例用PDO实现(mysqli逻辑类似) try { $pdo = new PDO('mysql:host=你的数据库地址;dbname=你的数据库名', '用户名', '密码'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $pdo->prepare("DELETE FROM 你的令牌表名 WHERE token = :token"); $stmt->bindParam(':token', $invalid_token); $stmt->execute(); echo "已成功删除失效令牌: {$invalid_token}"; } catch(PDOException $e) { echo "删除令牌失败: " . $e->getMessage(); } } } } }
一些额外的注意事项
- 批量推送多个令牌时,这个逻辑同样适用,因为
results数组的顺序和请求的令牌顺序严格对应。 - 遇到
Unavailable或InternalServerError这类错误,是FCM服务器暂时不可用,不要删除令牌,可以稍后重试推送。 - 建议添加日志记录,把失效令牌和删除操作记录下来,方便后续排查问题。
内容的提问来源于stack exchange,提问作者Alexandre C. do Carmo
相关产品推荐
相关产品推荐

