Quick Links

Google's Firebase Cloud Messaging (FCM) service is a free and convenient way to distribute push notifications to mobile devices. It works with iOS, Android, and web targets, abstracting away the differences between platforms. You send your payload once to Firebase's API and get real-time delivery to all your users.

In this article, we'll show how to use Firebase to send push notifications from your server-side PHP code. We're using the third-party

        php-firebase-cloud-messaging
    

(PHP-FCM) library to further simplify the Firebase integration.

Outlining the Architecture

Successfully sending a push notification requires several components to be working together. First you need an active Firebase account with a project that's got FCM enabled. We'll set this up in the following steps. You'll be issued a server key that your PHP backend must include with its Firebase requests.

You'll also need an app that uses the Firebase SDK to produce a client registration token. This token should be sent to your PHP backend. Persist it in your database alongside information identifying the client, such as its logged-in user ID within your application.

As this article focuses on the backend integration, we'll assume you've already got a Firebase client app that subscribes to notifications and retrieves a registration token. You can follow the documentation to create a basic Android app if you need a sample project. Within your client-side code, send the Firebase token to an API endpoint you'll create in your PHP service.

Once you've got some client tokens available on your server, you can send push notifications by making HTTP requests to the FCM API. Firebase will mediate with the individual notification delivery platforms, pushing your alert to the specified devices. FCM internally maps each client token to the correct platform, such as Google Play Services for Android and Apple Push Notification Service (APNS) for iOS.

Creating Your Firebase Project

Screenshot of the Firebase console homepage

Head to the Firebase Console, login, and click "Add project" to start setting up your integration. Give your project a name and click through the initial configuration prompts. Click the settings cog in the top-left when you reach the dashboard. Choose "Project settings" from the menu that appears.

Screenshot of setting up FCM in the Firebase console

Head to the "Cloud Messaging" tab and note down your Server Key. Your PHP service will use this credential to send notifications to the Firebase API.

Screenshot of the Firebase console homepage

You need to register your mobile applications within the Firebase console. Back on the homepage, use the "Add an app" buttons to add your iOS and Android components. Follow the setup wizard to provide your app's data and download its Firebase config file. This should be referenced when you initialize Firebase in your client-side code.

Screenshot of setting up FCM in the Firebase console

If you're building an iOS app, you need to manually link your APNS key to Firebase. Click the settings cog in the top-left, choose "Project settings," and navigate back to "Cloud Messaging." An "Apple apps" section will appear when you've got an iOS component in your project. Add an APNS key or certificate from your Apple Developer Account to complete the integration. This allows FCM to send notifications to APNS on your behalf.

Preparing Your PHP Application

Begin your PHP project by adding the PHP-FCM library using Composer:

composer require sngrl/php-firebase-cloud-messaging

Within your code, create an instance of PHP-FCM's Client class:

use sngrlPhpFirebaseCloudMessagingClientClient;
    

$client = new Client();

$client -> setApiKey("FCM-SERVER-KEY");

$client -> injectGuzzleHttpClient(new GuzzleHttpClient());

Pass the setApiKey() method the Server Key you copied from your Firebase API console. In a real application, this should be stored securely and treated as a confidential secret.

PHP-FCM relies on an injected Guzzle instance to make its HTTP requests. Guzzle is automatically included as a dependency so you don't need to manually install it. We're constructing a new Guzzle client in the example above; you could reuse an existing instance if you've already got Guzzle in your application.

The FCM Client instance is now ready to send notifications to your FCM account.

Registering Client Tokens

Notifications are distributed to client tokens that represent your users' devices. As explained above, you'll need to expose an API endpoint in your application that lets your client apps send their FCM token after the user logs in.

Here's a basic example of what this could look like:

$token = $_POST["fcmToken"];
    

$userId = ((int) $_POST["userId"]);

/**

* Call a function which persists a user/token

* association to your database

*/

saveUserFcmToken($userId, $token);

To send a push notification to every registered device, select all the tokens in your data store. You can send to a specific user by retrieving the tokens associated with their ID. This would display the notification on all the devices they've logged into, which is usually the intended behavior.

Sending Notifications

PHP-FCM abstracts each notification delivery into a Message object. This wraps a Notification - containing the text that's shown to the user - and any delivery options which you supply.

Prepare your Notification first:

use sngrlPhpFirebaseCloudMessagingClientNotification;
    

$notification = new Notification(

"Notification Title",

"The longer text of the notification, displayed below the title."

);

Next create a Message to represent the notification delivery:

use sngrlPhpFirebaseCloudMessagingClientMessage;
    

$message = new Message();

$message -> setNotification($notification);

Before sending your message, add one or more recipients. The addRecipient() method takes a Device instance; this class needs one of your FCM client tokens as its constructor parameter:

use sngrlPhpFirebaseCloudMessagingClientRecipientDevice;
    

$message -> addReceipient(new Device("FCM-CLIENT-TOKEN-USER-1"));

$message -> addReceipient(new Device("FCM-CLIENT-TOKEN-USER-2"));

Now you're ready to send the message using the Client created earlier:

$client -> send($message);

The notification will be delivered to the devices you added as recipients.

Here's a complete example that wraps the notification handling code into a convenient function:

use sngrlPhpFirebaseCloudMessagingClientClient;
    

use sngrlPhpFirebaseCloudMessagingClientMessage;

use sngrlPhpFirebaseCloudMessagingClientNotification;

use sngrlPhpFirebaseCloudMessagingClientRecipientDevice;

$client = new Client();

$client -> setApiKey("FCM-SERVER-KEY");

$client -> injectGuzzleHttpClient(new GuzzleHttpClient());

function sendNotification(

Client $client,

string $title,

string $body,

string ...$clientTokens) : void {

$message = new Message();

$message -> setNotification(

new Notification(

$title,

$body

)

);

foreach ($clientTokens as $clientToken) {

$message -> addRecipient(new Device($clientToken));

}

$client -> send($message);

}

sendNotification($client, "Hello World", "Test Notification", "FCM-CLIENT-TOKEN-1");

Handling FCM Response Data

The Client::send() method returns the HTTP response object for the notification request. You can inspect the JSON-encoded response data to determine whether your notifications were delivered successfully.

$message = new Message();
    

$message -> setNotification(new Notification("Test", "Test"));

$message -> addReceipient(new Device("FCM-CLIENT-TOKEN-USER-1"));

$message -> addReceipient(new Device("FCM-CLIENT-TOKEN-USER-2"));

$response = $client -> send($message);

$responseData = $response -> json();

The response data array has a structure similar to the following:

{
    

"success": 1,

"failure": 1,

"results": [

{

"message_id": 100

},

{

"error": "InvalidRegistration"

}

]

}

The results array contains an object representing the delivery status of each of the devices you tried to send to. This will match the order of recipients added to the Message via the addRecipient() method. The sample JSON above indicates that only the first device received the notification. The second delivery failed so you should remove the device token from your database.

$recipients = [
    

"FCM-CLIENT-TOKEN-USER-1",

"FCM-CLIENT-TOKEN-USER-2"

];

$message = new Message();

$message -> setNotification(new Notification("Test", "Test"));

foreach ($recipients as $recipient) {

$message -> addReceipient(new Device($recipient));

}

$response = $client -> send($message);

$responseData = $response -> json();

foreach ($responseData["results"] as $i => $result) {

if (isset($result["error"])) {

deleteUserFcmToken($recipients[$i]);

}

}

Adding Arbitrary Data to Notifications

Messages can include arbitrary data which needs to be communicated to the client application:

$message = new Message();
    

$message -> setNotification(

new Notification(

"Breaking News!",

"A breaking news story is available."

)

);

$message -> setData([

"uri" => "/news/latest-stories"

]);

Client-side code can access this data to take different actions when a notification is received.

Setting Message Priorities

FCM supports a message priority system that lets you request an immediate delivery to the target device. When high priority mode is used, FCM attempts to wake-up sleeping Android devices to handle the notification, even if background activity is being suppressed.

// Indicate a high-priority message
    

$message -> setPriority("high");

This attribute must be used carefully. Sending too many priority messages that don't result in user interactions will cause your deliveries to be deprioritized instead. The mechanism is intended for genuinely important payloads that need to break through a device's battery saving, network throttling, and background activity restrictions.

iOS handles priorities differently. You'll get an error if you try to send a high priority message to an iOS device. You can use the values normal or 5, the latter indicating a high priority delivery is preferred.

Time to Live

A Message instance's Time to Live (TTL) determines how long it remains relevant for. FCM won't always be able to deliver notifications in a timely manner. The target device could be offline or in a battery saving state. FCM will keep trying to deliver the notification but this isn't always desirable behavior. Some notifications such as expiration reminders might be irrelevant to the user by the time they receive them.

Use the setTimeToLive() method to define the lifespan of your messages. FCM will stop trying to deliver them after the TTL has expired.

$message = new Message();
    

$message -> setNotification(

new Notification(

"Server rotation scheduled for 12pm",

"Cancel within the next 10 minutes."

)

);

$message -> setTimeToLive(600);

Badges on iOS

iOS uses red badges on home screen icons to indicate the number of unread notifications available within the app. You can change your app's numeric badge with the setBadge() method on a Notification object:

$message = new Message();
    

$notification = new Notification(

"Server rotation scheduled for 12pm",

"Cancel within the next 10 minutes."

);

$notification -> setBadge(1);

$message -> setNotification($notification);

$message -> setTimeToLive(600);

The Notification class has methods for other platform-specific behaviors too. You can change the notification's icon on Android devices (setIcon()), assign a sound to play (setSound()), and use tags (setTag()) to control whether previous notifications are replaced by the new delivery. These properties and the quirks of their platform implementations are described in the FCM API documentation.

Conclusion

FCM is an ideal way to start sending push notifications to mobile devices from a PHP backend. It handles interactions with platform-specific push implementations such as APNS and Google Play Services, reducing the amount of code you need to write.

The PHP Firebase Cloud Messaging library wraps the FCM API in convenient PHP classes and methods. For more advanced control, you can call the FCM API directly via a PHP HTTP library such as Guzzle. You might have to take this approach if you need to use notification options that aren't exposed by PHP-FCM.