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

求助:Firebase FCM从Legacy API迁移至HTTP v1 API的PHP脚本实现

适配FCM HTTP v1 API的纯PHP实现(无第三方依赖)

核心差异说明

FCM HTTP v1 API和旧版Legacy API的核心区别在于两点:

  • 身份验证从固定服务器密钥改为OAuth 2.0访问令牌
  • 请求体格式更严格,需嵌套在message字段下,API端点包含项目ID

完整实现代码

1. 获取OAuth 2.0访问令牌

从Firebase控制台下载服务账号JSON密钥,提取client_email和private_key字段,用以下函数生成有效期1小时的访问令牌:

function getFcmAccessToken($clientEmail, $privateKey) {
    $tokenUrl = "https://oauth2.googleapis.com/token";
    
    // 构造JWT Header
    $header = json_encode(["alg" => "RS256", "typ" => "JWT"]);
    // 构造JWT Payload
    $now = time();
    $payload = json_encode([
        "iss" => $clientEmail,
        "scope" => "https://www.googleapis.com/auth/firebase.messaging",
        "aud" => $tokenUrl,
        "exp" => $now + 3600,
        "iat" => $now
    ]);
    
    // Base64URL编码Header和Payload
    $base64Header = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
    $base64Payload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
    
    // 生成签名
    $signatureInput = $base64Header . "." . $base64Payload;
    openssl_sign($signatureInput, $signature, $privateKey, "SHA256");
    $base64Signature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
    
    $jwt = $base64Header . "." . $base64Payload . "." . $base64Signature;
    
    // 请求获取访问令牌
    $curl = curl_init($tokenUrl);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query([
        "grant_type" => "urn:ietf:params:oauth:grant-type:jwt-bearer",
        "assertion" => $jwt
    ]));
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, ["Content-Type: application/x-www-form-urlencoded"]);
    
    $response = curl_exec($curl);
    curl_close($curl);
    
    $responseData = json_decode($response, true);
    return $responseData["access_token"] ?? null;
}

2. 发送FCM通知

使用获取到的访问令牌,构造符合v1 API格式的请求:

function sendFcmNotification($accessToken, $projectId, $deviceToken, $title, $body) {
    $apiUrl = "https://fcm.googleapis.com/v1/projects/{$projectId}/messages:send";
    
    $requestBody = json_encode([
        "message" => [
            "token" => $deviceToken,
            "notification" => [
                "title" => $title,
                "body" => $body
            ],
            // 可选:添加自定义数据负载
            "data" => [
                "order_id" => "12345",
                "status" => "shipped"
            ]
        ]
    ]);
    
    $curl = curl_init($apiUrl);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $requestBody);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, [
        "Authorization: Bearer {$accessToken}",
        "Content-Type: application/json"
    ]);
    // 建议开启SSL验证,避免安全风险
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
    
    $response = curl_exec($curl);
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    curl_close($curl);
    
    return [
        "http_code" => $httpCode,
        "response" => json_decode($response, true)
    ];
}

3. 调用示例

// 替换为你的实际信息
$clientEmail = "your-service-account@your-project.iam.gserviceaccount.com";
$privateKey = "-----BEGIN PRIVATE KEY-----\nYOUR_PRIVATE_KEY_CONTENTS\n-----END PRIVATE KEY-----";
$projectId = "your-firebase-project-id";
$deviceToken = "target-user-fcm-token";

// 获取访问令牌
$accessToken = getFcmAccessToken($clientEmail, $privateKey);
if (!$accessToken) {
    die("获取访问令牌失败");
}

// 发送通知
$result = sendFcmNotification($accessToken, $projectId, $deviceToken, "新订单提醒", "您的订单已发货");
print_r($result);

重要注意事项

  • 私钥格式:确保私钥包含完整的首尾标记,换行符保留正确格式
  • 令牌缓存:访问令牌有效期1小时,建议缓存令牌减少重复请求
  • SSL验证:不要随意关闭CURLOPT_SSL_VERIFYPEER,若托管环境有证书问题,联系服务商解决
  • 错误排查:若请求失败,检查HTTP状态码,常见问题包括令牌过期、设备令牌无效、项目ID错误

内容的提问来源于stack exchange,提问作者FreddyBoy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 00:05:15