14

I have used FCM with the legacy protocol but cannot find any concrete documentation to use the new FCM HTTP v1 API with php.

I have managed to import the Google API Client Library into my project but cannot find any documentation or tutorials on how to obtain the access token for the required scopes for fcm messages.

AL.
  • 36,815
  • 10
  • 142
  • 281
Jude Fernandes
  • 7,437
  • 11
  • 53
  • 90
  • Well I do not know how you are doing since you did not code, what is that to send messages through FCM you have the api key in the configuration of your project in the same console of firebase, on the other hand, I leave unh repo in which I have a form to send notifications with firebase, look it up and see if it helps. [REPOSITORY](https://gitlab.com/xfxstudios/firebase_form) – Carlos Quintero Apr 12 '18 at 03:21
  • 2
    @CarlosQuintero I looked at your code and you are using the older legacy way of sending fcm requests which I have already got, I wanted to know how to code for the new way using the HTTP v1 API with php – Jude Fernandes Apr 12 '18 at 05:05
  • see this [REPO](https://gist.github.com/brianjcollins/eb12662799ecb09beeeffa70a663765d) – Carlos Quintero Apr 12 '18 at 05:23
  • @CarlosQuintero Thanks that seem like it should help , will try it out and mark yours as the correct answer once done. – Jude Fernandes Apr 12 '18 at 06:16

4 Answers4

13

Maybe a bit late, but this is how to retrieve an oath token to be used with the FCM HTTP v1 API.

  • Download this Google library to use it in your php code.
  • Generate and download a new private key from the Firebase console
  • Store this key in json format in a secure place on your server.

How to configure the Google Client with your private key

public function configureClient()
{
    $client = new Google_Client();
    try {
        $client->setAuthConfig("include_your_private_json_key_path_here");
        $client->addScope(Google_Service_FirebaseCloudMessaging::CLOUD_PLATFORM);

        // retrieve the saved oauth token if it exists, you can save it on your database or in a secure place on your server
        $savedTokenJson = $this->readFile();

        if ($savedTokenJson != null) {
            // the token exists, set it to the client and check if it's still valid
            $client->setAccessToken($savedTokenJson);
            if ($client->isAccessTokenExpired()) {
                // the token is expired, generate a new token and set it to the client
                $accessToken = $this->generateToken($client);
                $client->setAccessToken($accessToken);
            }
        } else {
            // the token doesn't exist, generate a new token and set it to the client
            $accessToken = $this->generateToken($client);
            $client->setAccessToken($accessToken);
        }

        $oauthToken = $accessToken["access_token"];

        // the client is configured, now you can send the push notification using the $oauthToken.

    } catch (Google_Exception $e) {
        // handle exception
    }
}

How to request a new oauth token

private function generateToken($client)
{
    $client->fetchAccessTokenWithAssertion();
    $accessToken = $client->getAccessToken();

    // save the oauth token json on your database or in a secure place on your server
    $tokenJson = json_encode($accessToken);
    $this->saveFile($tokenJson);

    return $accessToken;
}

Please note that saveFile() and readFile() methods should be implemented as you prefer to store and retrieve the oath token json. Follow the migration guide for the payload structure.

lubilis
  • 3,942
  • 4
  • 31
  • 54
  • 3
    if you just want to send notifications to apps use this, using a laravel library will just be an over kill for this task and this approach is far more easier to use. – magicianiam Aug 08 '20 at 15:29
  • Hi, can you explain what is Google_Service_FirebaseCloudMessaging::CLOUD_PLATFORM for ? – Rifki Maulana Oct 20 '22 at 06:20
  • @RifkiMaulana this defines the scope for the Google Client. To send push notifications this scope would be enough: Google_Service_FirebaseCloudMessaging::FIREBASE_MESSAGING – lubilis Oct 24 '22 at 10:05
5

If you are willing to use an existing library instead of implementing it yourself, you might consider having a look at https://github.com/kreait/firebase-php/ which has received support for FCM just today.

https://firebase-php.readthedocs.io/en/latest/cloud-messaging.html

If it isn't for you, you will at least be able to extract the connections to the FCM REST API with PHP from the source code. In short, it's the implementation of https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages .

jeromegamez
  • 3,348
  • 1
  • 23
  • 36
  • Thanks for the reference but taking a look at the documentation I found a note that says `The Cloud Messaging API currently does not support sending messages tailored to different target platforms (Android, iOS and Web).` which is only possible in the HTTPv1 FCM calls so it looks like it still supports only the legacy protocol – Jude Fernandes Apr 17 '18 at 08:10
  • 1
    It doesn’t support it *yet*, the platform configs are coming in a future release - I should have made this clearer :) – jeromegamez Apr 17 '18 at 08:17
  • Looking forward to it, are you the author of the library? – Jude Fernandes Apr 17 '18 at 08:26
  • 1
    Yes :). I usually write this when I reference it, just another thing I forgot – jeromegamez Apr 17 '18 at 08:27
  • Cool, any kind of eta on those new features? – Jude Fernandes Apr 17 '18 at 11:30
  • No ETAs (it‘s a project I do in my spare time), but this or next month seems realistic. – jeromegamez Apr 17 '18 at 16:21
  • 1
    I just stumbled over this while searching for something else and wanted to let you know that FCM is now fully implemented in the PHP SDK \o/ – jeromegamez Aug 10 '19 at 07:06
5

Update July 2023

The batch messaging endpoint has been deprecated and will be removed in July 2024. The recommendation is to iterate through the tokens use the standard v1 api send method: https://firebase.google.com/docs/cloud-messaging/send-message#send-a-batch-of-messages

Here is example on how to send a notification to a single device:

<?php


require_once '<Path_to_google-api-php-client>/vendor/autoload.php'; 


function getOATHToken()
{
    $client = new Google_Client();
    try {
        $client->setAuthConfig("<path_to_your_private_json_key.json>");
        $client->addScope(Google_Service_FirebaseCloudMessaging::CLOUD_PLATFORM);

        $savedTokenJson = readSavedToken();

        if ($savedTokenJson) {
            // the token exists, set it to the client and check if it's still valid
            $client->setAccessToken($savedTokenJson);
            $accessToken = $savedTokenJson;
            if ($client->isAccessTokenExpired()) {
                // the token is expired, generate a new token and set it to the client
                $accessToken = generateToken($client);
                $client->setAccessToken($accessToken);
            }
        } else {
            // the token doesn't exist, generate a new token and set it to the client
            $accessToken = generateToken($client);
            $client->setAccessToken($accessToken);
        }
        

        $oauthToken = $accessToken["access_token"];

        return $oauthToken;

        
    } catch (Google_Exception $e) {}
   return false;
}

//Using a simple file to cache and read the toke, can store it in a databse also
function readSavedToken() {
  $tk = @file_get_contents('token.cache');
  if ($tk) return json_decode($tk, true); else return false;
}
function writeToken($tk) {
 file_put_contents("token.cache",$tk);
}

function generateToken($client)
{
    $client->fetchAccessTokenWithAssertion();
    $accessToken = $client->getAccessToken();

    $tokenJson = json_encode($accessToken);
    writeToken($tokenJson);

    return $accessToken;
}


// Finally
function sendNotification($token, $title, $body, $accessToken) {

    $payload = ["message" => ["token" => $token, "notification"=>["title" => $title, "body"=> $body]]];

    $postdata = json_encode($payload);
    
    $opts = array('http' =>
        array(
            'method'  => 'POST',
            'header'  => 'Content-Type: application/json' . "\r\nAuthorization: Bearer $accessToken",
            'content' => $postdata
        )
    );

    $context  = stream_context_create($opts);

    $result = file_get_contents('https://fcm.googleapis.com/v1/projects/<your_firebase_project_id>/messages:send', false, $context);

    echo "\n\n======RESPONSE======\n\n";
    echo $result;

}

$token = "token-1"; //FCM Device token

$title = "Test from PHP";
$body = "This is a test from PHP";

sendNotification($token, $title, $body, getOATHToken());

?>

The batch sending example (now deprecated)

Here is a complete example on how to send a push to multiple tokens using the Google API PHP Client, using the FCM HTTP v1 api, as given in the FCM docs.

(Modified from lubilis answer above)

<?php


require_once '<Path_to_google-api-php-client>/vendor/autoload.php'; 


function getOATHToken()
{
    $client = new Google_Client();
    try {
        $client->setAuthConfig("<path_to_your_private_json_key.json>");
        $client->addScope(Google_Service_FirebaseCloudMessaging::CLOUD_PLATFORM);

        $savedTokenJson = readSavedToken();

        if ($savedTokenJson) {
            // the token exists, set it to the client and check if it's still valid
            $client->setAccessToken($savedTokenJson);
            $accessToken = $savedTokenJson;
            if ($client->isAccessTokenExpired()) {
                // the token is expired, generate a new token and set it to the client
                $accessToken = generateToken($client);
                $client->setAccessToken($accessToken);
            }
        } else {
            // the token doesn't exist, generate a new token and set it to the client
            $accessToken = generateToken($client);
            $client->setAccessToken($accessToken);
        }
        

        $oauthToken = $accessToken["access_token"];

        return $oauthToken;

        
    } catch (Google_Exception $e) {}
   return false;
}

//Using a simple file to cache and read the toke, can store it in a databse also
function readSavedToken() {
  $tk = @file_get_contents('token.cache');
  if ($tk) return json_decode($tk, true); else return false;
}
function writeToken($tk) {
 file_put_contents("token.cache",$tk);
}

function generateToken($client)
{
    $client->fetchAccessTokenWithAssertion();
    $accessToken = $client->getAccessToken();

    $tokenJson = json_encode($accessToken);
    writeToken($tokenJson);

    return $accessToken;
}


// Finally
function sendNotification($tokens, $title, $body, $accessToken) {

    $boundary = "--subrequest_boundary";
    $multiPayload = $boundary;

    foreach ($tokens as $token) {
        $head = "Content-Type: application/http\r\n".
                "Content-Transfer-Encoding: binary\r\n\r\n".
                "POST /v1/projects/<your_firebase_project_name>/messages:send\r\n".
                "Content-Type: application/json\r\n".
                "accept: application/json\r\n\r\n";
        
        $payload = ["message" => ["token" => $token, "notification"=>["title" => $title, "body"=> $body]]];

        $postdata = json_encode($payload);
        $multiPayload .= "\r\n".$head.$postdata."\r\n".$boundary;
        
    }
    
    $multiPayload .= "--";
    

    //Uncomment for debugging
    //echo "\n\n==== POST DATA====\n\n";
    //echo $multiPayload;


    $opts = array('http' =>
        array(
            'method'  => 'POST',
            'header'  => 'Content-Type: multipart/mixed; boundary="subrequest_boundary"' . "\r\nAuthorization: Bearer $accessToken",
            'content' => $multiPayload
        )
    );

    //Uncomment for debugging
    //echo "\n\n==== HTTP OPTIONS====\n\n";
    //var_dump($opts);

    $context  = stream_context_create($opts);


    // This is the path for sending push multiple tokens (upto 500 as per the docs)
    $result = file_get_contents('https://fcm.googleapis.com/batch', false, $context);

    echo "\n\n======RESPONSE======\n\n";
    echo $result;

}

$tokens = ["token-1","token-2"]; //FCM Device tokens as array

$title = "Test from PHP";
$body = "This is a test from PHP";

sendNotification($tokens, $title, $body, getOATHToken());

?>
Mohan Noone
  • 561
  • 6
  • 14
2

Following the author's lead, here's an example php project that uses FCM HTTP v1 API:

repo: https://github.com/jeromegamez/firebase-php-examples
package docs: https://firebase-php.readthedocs.io/en/latest/cloud-messaging.html
package repo: https://github.com/kreait/firebase-php

Jannie Theunissen
  • 28,256
  • 21
  • 100
  • 127