You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:43:49